From 6f4f2723d08534fd4e407e1ef8500b0f4d12c30c Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 20 Apr 2010 13:17:36 +0200 Subject: [PATCH] [CPUFREQ] x86 cpufreq: Make trace_power_frequency cpufreq driver independent and fix the broken case if a core's frequency depends on others. trace_power_frequency was only implemented in a rather ungeneric way in acpi-cpufreq driver's target() function only. -> Move the call to trace_power_frequency to cpufreq.c:cpufreq_notify_transition() where CPUFREQ_POSTCHANGE notifier is triggered. This will support power frequency tracing by all cpufreq drivers trace_power_frequency did not trace frequency changes correctly when the userspace governor was used or when CPU cores' frequency depend on each other. -> Moving this into the CPUFREQ_POSTCHANGE notifier and pass the cpu which gets switched automatically fixes this. Robert Schoene provided some important fixes on top of my initial quick shot version which are integrated in this patch: - Forgot some changes in power_end trace (TP_printk/variable names) - Variable dummy in power_end must now be cpu_id - Use static 64 bit variable instead of unsigned int for cpu_id Signed-off-by: Thomas Renninger CC: davej@redhat.com CC: arjan@infradead.org CC: linux-kernel@vger.kernel.org CC: robert.schoene@tu-dresden.de Tested-by: robert.schoene@tu-dresden.de Signed-off-by: Dave Jones --- arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 3 --- arch/x86/kernel/process.c | 8 +++---- drivers/cpufreq/cpufreq.c | 5 ++++ drivers/cpuidle/cpuidle.c | 2 +- include/trace/events/power.h | 27 ++++++++++++---------- tools/perf/builtin-timechart.c | 11 +++++---- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index cee7aa949c35..246cd3afbb5f 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -324,8 +323,6 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, } } - trace_power_frequency(POWER_PSTATE, data->freq_table[next_state].frequency); - switch (data->cpu_feature) { case SYSTEM_INTEL_MSR_CAPABLE: cmd.type = SYSTEM_INTEL_MSR_CAPABLE; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index e7e35219b32f..787572d43d9c 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -371,7 +371,7 @@ static inline int hlt_use_halt(void) void default_idle(void) { if (hlt_use_halt()) { - trace_power_start(POWER_CSTATE, 1); + trace_power_start(POWER_CSTATE, 1, smp_processor_id()); current_thread_info()->status &= ~TS_POLLING; /* * TS_POLLING-cleared state must be visible before we @@ -441,7 +441,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); */ void mwait_idle_with_hints(unsigned long ax, unsigned long cx) { - trace_power_start(POWER_CSTATE, (ax>>4)+1); + trace_power_start(POWER_CSTATE, (ax>>4)+1, smp_processor_id()); if (!need_resched()) { if (cpu_has(¤t_cpu_data, X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); @@ -457,7 +457,7 @@ void mwait_idle_with_hints(unsigned long ax, unsigned long cx) static void mwait_idle(void) { if (!need_resched()) { - trace_power_start(POWER_CSTATE, 1); + trace_power_start(POWER_CSTATE, 1, smp_processor_id()); if (cpu_has(¤t_cpu_data, X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); @@ -478,7 +478,7 @@ static void mwait_idle(void) */ static void poll_idle(void) { - trace_power_start(POWER_CSTATE, 0); + trace_power_start(POWER_CSTATE, 0, smp_processor_id()); local_irq_enable(); while (!need_resched()) cpu_relax(); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 40877d219081..6ce1bb735635 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -29,6 +29,8 @@ #include #include +#include + #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \ "cpufreq-core", msg) @@ -350,6 +352,9 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); + dprintk("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, + (unsigned long)freqs->cpu); + trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu); srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); if (likely(policy) && likely(policy->cpu == freqs->cpu)) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 199488576a05..dbefe15bd582 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -95,7 +95,7 @@ static void cpuidle_idle_call(void) /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) cpuidle_curr_governor->reflect(dev); - trace_power_end(0); + trace_power_end(smp_processor_id()); } /** diff --git a/include/trace/events/power.h b/include/trace/events/power.h index c4efe9b8280d..35a2a6e7bf1e 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -18,52 +18,55 @@ enum { DECLARE_EVENT_CLASS(power, - TP_PROTO(unsigned int type, unsigned int state), + TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id), - TP_ARGS(type, state), + TP_ARGS(type, state, cpu_id), TP_STRUCT__entry( __field( u64, type ) __field( u64, state ) + __field( u64, cpu_id ) ), TP_fast_assign( __entry->type = type; __entry->state = state; + __entry->cpu_id = cpu_id; ), - TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long)__entry->state) + TP_printk("type=%lu state=%lu cpu_id=%lu", (unsigned long)__entry->type, + (unsigned long)__entry->state, (unsigned long)__entry->cpu_id) ); DEFINE_EVENT(power, power_start, - TP_PROTO(unsigned int type, unsigned int state), + TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id), - TP_ARGS(type, state) + TP_ARGS(type, state, cpu_id) ); DEFINE_EVENT(power, power_frequency, - TP_PROTO(unsigned int type, unsigned int state), + TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id), - TP_ARGS(type, state) + TP_ARGS(type, state, cpu_id) ); TRACE_EVENT(power_end, - TP_PROTO(int dummy), + TP_PROTO(unsigned int cpu_id), - TP_ARGS(dummy), + TP_ARGS(cpu_id), TP_STRUCT__entry( - __field( u64, dummy ) + __field( u64, cpu_id ) ), TP_fast_assign( - __entry->dummy = 0xffff; + __entry->cpu_id = cpu_id; ), - TP_printk("dummy=%lu", (unsigned long)__entry->dummy) + TP_printk("cpu_id=%lu", (unsigned long)__entry->cpu_id) ); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 5a52ed9fc10b..5161619d4714 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -300,8 +300,9 @@ struct trace_entry { struct power_entry { struct trace_entry te; - s64 type; - s64 value; + u64 type; + u64 value; + u64 cpu_id; }; #define TASK_COMM_LEN 16 @@ -498,13 +499,13 @@ static int process_sample_event(event_t *event, struct perf_session *session) return 0; if (strcmp(event_str, "power:power_start") == 0) - c_state_start(data.cpu, data.time, pe->value); + c_state_start(pe->cpu_id, data.time, pe->value); if (strcmp(event_str, "power:power_end") == 0) - c_state_end(data.cpu, data.time); + c_state_end(pe->cpu_id, data.time); if (strcmp(event_str, "power:power_frequency") == 0) - p_state_change(data.cpu, data.time, pe->value); + p_state_change(pe->cpu_id, data.time, pe->value); if (strcmp(event_str, "sched:sched_wakeup") == 0) sched_wakeup(data.cpu, data.time, data.pid, te);