2010-12-02 16:42:44

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 1/8] acpi: Use ACPI C-state type instead of enumeration value to export cpuidle state name

In the former /proc/acpi/processor/power/* there were Cx showing the
enumerated number/amount of C-states and type[Cy] which is
what should get shown as the cpuidle state name.

Typically on latest Nehalem and later CPUs, BIOS vendors miss
out C2 and C3 wrongly shows up as C2.

Signed-off-by: Thomas Renninger <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: [email protected]
---
drivers/acpi/processor_idle.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index dcb38f8..104ae77 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1008,7 +1008,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
#endif
cpuidle_set_statedata(state, cx);

- snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
state->exit_latency = cx->latency;
state->target_residency = cx->latency * latency_factor;
@@ -1016,6 +1015,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
state->flags |= CPUIDLE_FLAG_SHALLOW;
if (cx->entry_method == ACPI_CSTATE_FFH)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
@@ -1025,6 +1025,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
break;

case ACPI_STATE_C2:
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
state->flags |= CPUIDLE_FLAG_BALANCED;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
@@ -1032,6 +1033,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
break;

case ACPI_STATE_C3:
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
state->flags |= CPUIDLE_FLAG_DEEP;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->flags |= CPUIDLE_FLAG_CHECK_BM;
--
1.6.0.2


2010-12-02 16:42:43

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 6/8] acpi: processor->cpuidle: Only set cpuidle check_bm flag if pr->flags.bm_check is set

Signed-off-by: Thomas Renninger <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: Arjan van de Ven <[email protected]>
CC: Ingo Molnar <[email protected]>
CC: [email protected]
---
drivers/acpi/processor_idle.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e74f72c..d4d2c5d 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1046,7 +1046,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C3");
state->flags |= CPUIDLE_FLAG_DEEP;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->flags |= CPUIDLE_FLAG_CHECK_BM;
+ if (pr->flags.bm_check)
+ state->flags |= CPUIDLE_FLAG_CHECK_BM;
state->enter = pr->flags.bm_check ?
acpi_idle_enter_bm :
acpi_idle_enter_simple;
--
1.6.0.2

2010-12-02 16:42:41

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 2/8] cpuidle: Rename X86 specific idle poll state[0] from C0 to CPUIDLE

C0 means and is well know as "not idle".
All documentation out there uses this term as "running"/"not idle"
state. Also Linux userspace tools (e.g. cpufreq-aperf and turbostat)
show C0 residency which there is correct, but means something totally
else than cpuidle "POLL" state.


Signed-off-by: Thomas Renninger <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: Ingo Molnar <[email protected]>
CC: [email protected]
---
drivers/cpuidle/cpuidle.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 08d5f05..99cc8fc 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -260,7 +260,7 @@ static void poll_idle_init(struct cpuidle_device *dev)

cpuidle_set_statedata(state, NULL);

- snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
+ snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
state->exit_latency = 0;
state->target_residency = 0;
--
1.6.0.2

2010-12-02 16:43:07

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 4/8] X86: Cleanup idle= internal variables by getting rid of idle_halt idle_nomwait

Having four variables for the same thing:
idle_halt, idle_nomwait, force_mwait and boot_option_idle_overrides
is rather confusing and unnecessary complex.

if idle= boot param is passed, only set up one variable:
boot_option_idle_overrides

Introduces following functional changes/fixes:
- intel_idle driver does not register if any idle=xy
boot param is passed.

Signed-off-by: Thomas Renninger <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: Arjan van de Ven <[email protected]>
CC: Ingo Molnar <[email protected]>
CC: [email protected]
---
arch/ia64/include/asm/processor.h | 5 +++--
arch/ia64/kernel/process.c | 6 +-----
arch/x86/include/asm/processor.h | 5 +++--
arch/x86/kernel/process.c | 24 ++++++++----------------
drivers/acpi/processor_core.c | 4 ++--
drivers/acpi/processor_idle.c | 17 ++++++++++++-----
drivers/idle/intel_idle.c | 4 ++++
7 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index 348e44d..b34e5eb 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -717,8 +717,9 @@ prefetchw (const void *x)
#define spin_lock_prefetch(x) prefetchw(x)

extern unsigned long boot_option_idle_override;
-extern unsigned long idle_halt;
-extern unsigned long idle_nomwait;
+
+enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_HALT, IDLE_FORCE_MWAIT,
+ IDLE_NOMWAIT, IDLE_POLL};

#endif /* !__ASSEMBLY__ */

diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 16f1c7b..6d33c5c 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -53,12 +53,8 @@

void (*ia64_mark_idle)(int);

-unsigned long boot_option_idle_override = 0;
+unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
EXPORT_SYMBOL(boot_option_idle_override);
-unsigned long idle_halt;
-EXPORT_SYMBOL(idle_halt);
-unsigned long idle_nomwait;
-EXPORT_SYMBOL(idle_nomwait);
void (*pm_idle) (void);
EXPORT_SYMBOL(pm_idle);
void (*pm_power_off) (void);
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index cae9c3c..77d902a 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -762,10 +762,11 @@ extern void select_idle_routine(const struct cpuinfo_x86 *c);
extern void init_c1e_mask(void);

extern unsigned long boot_option_idle_override;
-extern unsigned long idle_halt;
-extern unsigned long idle_nomwait;
extern bool c1e_detected;

+enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_HALT, IDLE_NOMWAIT,
+ IDLE_POLL, IDLE_FORCE_MWAIT};
+
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);

diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index b618548..62f82de 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -22,11 +22,6 @@
#include <asm/i387.h>
#include <asm/debugreg.h>

-unsigned long idle_halt;
-EXPORT_SYMBOL(idle_halt);
-unsigned long idle_nomwait;
-EXPORT_SYMBOL(idle_nomwait);
-
struct kmem_cache *task_xstate_cachep;
EXPORT_SYMBOL_GPL(task_xstate_cachep);

@@ -328,7 +323,7 @@ long sys_execve(const char __user *name,
/*
* Idle related variables and functions
*/
-unsigned long boot_option_idle_override = 0;
+unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
EXPORT_SYMBOL(boot_option_idle_override);

/*
@@ -506,7 +501,6 @@ static void poll_idle(void)
*
* idle=mwait overrides this decision and forces the usage of mwait.
*/
-static int __cpuinitdata force_mwait;

#define MWAIT_INFO 0x05
#define MWAIT_ECX_EXTENDED_INFO 0x01
@@ -516,7 +510,7 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;

- if (force_mwait)
+ if (boot_option_idle_override == IDLE_FORCE_MWAIT)
return 1;

if (c->cpuid_level < MWAIT_INFO)
@@ -636,9 +630,10 @@ static int __init idle_setup(char *str)
if (!strcmp(str, "poll")) {
printk("using polling idle threads.\n");
pm_idle = poll_idle;
- } else if (!strcmp(str, "mwait"))
- force_mwait = 1;
- else if (!strcmp(str, "halt")) {
+ boot_option_idle_override = IDLE_POLL;
+ } else if (!strcmp(str, "mwait")) {
+ boot_option_idle_override = IDLE_FORCE_MWAIT;
+ } else if (!strcmp(str, "halt")) {
/*
* When the boot option of idle=halt is added, halt is
* forced to be used for CPU idle. In such case CPU C2/C3
@@ -647,8 +642,7 @@ static int __init idle_setup(char *str)
* the boot_option_idle_override.
*/
pm_idle = default_idle;
- idle_halt = 1;
- return 0;
+ boot_option_idle_override = IDLE_HALT;
} else if (!strcmp(str, "nomwait")) {
/*
* If the boot option of "idle=nomwait" is added,
@@ -656,12 +650,10 @@ static int __init idle_setup(char *str)
* states. In such case it won't touch the variable
* of boot_option_idle_override.
*/
- idle_nomwait = 1;
- return 0;
+ boot_option_idle_override = IDLE_NOMWAIT;
} else
return -1;

- boot_option_idle_override = 1;
return 0;
}
early_param("idle", idle_setup);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index bec561c..3c1a2fe 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -23,7 +23,7 @@ static int set_no_mwait(const struct dmi_system_id *id)
{
printk(KERN_NOTICE PREFIX "%s detected - "
"disabling mwait for CPU C-states\n", id->ident);
- idle_nomwait = 1;
+ boot_option_idle_override = IDLE_NOMWAIT;
return 0;
}

@@ -283,7 +283,7 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
{
acpi_status status = AE_OK;

- if (idle_nomwait) {
+ if (boot_option_idle_override == IDLE_NOMWAIT) {
/*
* If mwait is disabled for CPU C-states, the C2C3_FFH access
* mode will be disabled in the parameter of _PDC object.
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 104ae77..dda3412 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -79,6 +79,12 @@ module_param(bm_check_disable, uint, 0000);
static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644);

+static int disabled_by_idle_boot_param(void)
+{
+ return boot_option_idle_override == IDLE_POLL ||
+ boot_option_idle_override == IDLE_FORCE_MWAIT;
+}
+
/*
* IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
* For now disable this. Probably a bug somewhere else.
@@ -455,7 +461,8 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
continue;
}
if (cx.type == ACPI_STATE_C1 &&
- (idle_halt || idle_nomwait)) {
+ (boot_option_idle_override == IDLE_HALT ||
+ boot_option_idle_override == IDLE_NOMWAIT)) {
/*
* In most cases the C1 space_id obtained from
* _CST object is FIXED_HARDWARE access mode.
@@ -1060,7 +1067,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int ret = 0;

- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;

if (!pr)
@@ -1091,11 +1098,11 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
acpi_status status = 0;
static int first_run;

- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;

if (!first_run) {
- if (idle_halt) {
+ if (boot_option_idle_override == IDLE_HALT) {
/*
* When the boot option of "idle=halt" is added, halt
* is used for CPU IDLE.
@@ -1144,7 +1151,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;

cpuidle_unregister_device(&pr->power.dev);
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 60414ae..f0798ff 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -407,6 +407,10 @@ static int __init intel_idle_init(void)
{
int retval;

+ /* Do not load intel_idle at all for now if idle= is passed */
+ if (boot_option_idle_override != IDLE_NO_OVERRIDE)
+ return -ENODEV;
+
retval = intel_idle_probe();
if (retval)
return retval;
--
1.6.0.2

2010-12-02 16:43:40

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 3/8] X86/perf: fix power:cpu_idle double end events and throw cpu_idle events from the cpuidle layer

Currently intel_idle and acpi_idle driver show double cpu_idle "exit idle"
events -> this patch fixes it and makes cpu_idle events throwing less complex.

It also introduces cpu_idle events for all architectures which use
the cpuidle subsystem, namely:
- arch/arm/mach-at91/cpuidle.c
- arch/arm/mach-davinci/cpuidle.c
- arch/arm/mach-kirkwood/cpuidle.c
- arch/arm/mach-omap2/cpuidle34xx.c
- arch/drivers/acpi/processor_idle.c (for all cases, not only mwait)
- arch/x86/kernel/process.c (did throw events before, but was a mess)
- drivers/idle/intel_idle.c (did throw events before)

Convention should be:
Fire cpu_idle events inside the current pm_idle function (not somewhere
down the the callee tree) to keep things easy.

Current possible pm_idle functions in X86:
c1e_idle, poll_idle, cpuidle_idle_call, mwait_idle, default_idle
-> this is really easy is now.

This affects userspace:
The type field of the cpu_idle power event can now direclty get
mapped to:
/sys/devices/system/cpu/cpuX/cpuidle/stateX/{name,desc,usage,time,...}
instead of throwing very CPU/mwait specific values.
This change is not visible for the intel_idle driver.
For the acpi_idle driver it should only be visible if the vendor
misses out C-states in his BIOS.
Another (perf timechart) patch reads out cpuidle info of cpu_idle
events from:
/sys/.../cpuidle/stateX/*, then the cpuidle events are mapped
to the correct C-/cpuidle state again, even if e.g. vendors miss
out C-states in their BIOS and for example only export C1 and C3.
-> everything is fine.

Signed-off-by: Thomas Renninger <[email protected]>
CC: Robert Schoene <[email protected]>
CC: Jean Pihet <[email protected]>
CC: Arjan van de Ven <[email protected]>
CC: Ingo Molnar <[email protected]>
CC: Len Brown <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: [email protected]
---
arch/x86/kernel/process.c | 6 ++++--
arch/x86/kernel/process_32.c | 4 ----
arch/x86/kernel/process_64.c | 6 ------
drivers/cpuidle/cpuidle.c | 10 ++++++++--
drivers/idle/intel_idle.c | 2 --
5 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 155d975..b618548 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -387,6 +387,8 @@ void default_idle(void)
else
local_irq_enable();
current_thread_info()->status |= TS_POLLING;
+ trace_power_end(smp_processor_id());
+ trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
} else {
local_irq_enable();
/* loop is done by the caller */
@@ -444,8 +446,6 @@ 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, smp_processor_id());
- trace_cpu_idle((ax>>4)+1, smp_processor_id());
if (!need_resched()) {
if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
clflush((void *)&current_thread_info()->flags);
@@ -472,6 +472,8 @@ static void mwait_idle(void)
__sti_mwait(0, 0);
else
local_irq_enable();
+ trace_power_end(smp_processor_id());
+ trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
} else
local_irq_enable();
}
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 4b9befa..8d12878 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -57,8 +57,6 @@
#include <asm/syscalls.h>
#include <asm/debugreg.h>

-#include <trace/events/power.h>
-
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");

/*
@@ -113,8 +111,6 @@ void cpu_idle(void)
stop_critical_timings();
pm_idle();
start_critical_timings();
- trace_power_end(smp_processor_id());
- trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
}
tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 4c818a7..bd387e8 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -51,8 +51,6 @@
#include <asm/syscalls.h>
#include <asm/debugreg.h>

-#include <trace/events/power.h>
-
asmlinkage extern void ret_from_fork(void);

DEFINE_PER_CPU(unsigned long, old_rsp);
@@ -141,10 +139,6 @@ void cpu_idle(void)
pm_idle();
start_critical_timings();

- trace_power_end(smp_processor_id());
- trace_cpu_idle(PWR_EVENT_EXIT,
- smp_processor_id());
-
/* In many cases the interrupt that ended idle
has already called exit_idle. But some idle
loops can be woken up without interrupt. */
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 99cc8fc..4649495 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -96,7 +96,15 @@ static void cpuidle_idle_call(void)

/* enter the state and update stats */
dev->last_state = target_state;
+
+ trace_power_start(POWER_CSTATE, next_state, dev->cpu);
+ trace_cpu_idle(next_state, dev->cpu);
+
dev->last_residency = target_state->enter(dev, target_state);
+
+ trace_power_end(dev->cpu);
+ trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
+
if (dev->last_state)
target_state = dev->last_state;

@@ -106,8 +114,6 @@ 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(smp_processor_id());
- trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
}

/**
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index ba5134f..60414ae 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -220,8 +220,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
kt_before = ktime_get_real();

stop_critical_timings();
- trace_power_start(POWER_CSTATE, (eax >> 4) + 1, cpu);
- trace_cpu_idle((eax >> 4) + 1, cpu);
if (!need_resched()) {

__monitor((void *)&current_thread_info()->flags, 0, 0);
--
1.6.0.2

2010-12-02 16:44:05

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 7/8] perf timechart: Map power:cpu_idle events to the corresponding cpuidle state

Before, power:cpu_idle events were very specific X86 Intel mwait events.
This got fixed with previous patches and cpu_idle events are now thrown by
all cpuidle drivers and can be mapped to the corresponding cpuidle state
in /sys.

This patch reads out the corresponding cpuidle name of a cpu_idle event
and uses it in the title line of the chart (c-states Cx in x86, omap2
- DDR self refresh states for various arm archs).

It also reads out the corresponding abbr(eviation) and uses the string
to draw the cpu idle occurences. This needs a short (3 letter) string
to keep the overview in the chart.

Signed-off-by: Thomas Renninger <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: Arjan van de Ven <[email protected]>
CC: Ingo Molnar <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
---
tools/perf/builtin-timechart.c | 26 ++++++-
tools/perf/util/svghelper.c | 156 +++++++++++++++++++++++++++++++++++-----
2 files changed, 163 insertions(+), 19 deletions(-)

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 148dc5e..391e475 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -31,6 +31,7 @@
#include "util/event.h"
#include "util/session.h"
#include "util/svghelper.h"
+#include "util/debug.h"

#define SUPPORT_OLD_POWER_EVENTS 1
#define PWR_EVENT_EXIT -1
@@ -379,6 +380,10 @@ static void c_state_end(int cpu, u64 timestamp)
pwr->next = power_events;

power_events = pwr;
+ if (verbose)
+ printf("CPU: %d - start_time: %llu - end_time: %llu\n",
+ power_events->cpu, power_events->start_time,
+ power_events->end_time);
}

static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
@@ -657,8 +662,25 @@ static void draw_c_p_states(void)
* two pass drawing so that the P state bars are on top of the C state blocks
*/
while (pwr) {
- if (pwr->type == CSTATE)
- svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
+ if (pwr->type == CSTATE) {
+ if (verbose) {
+ printf("CPU: %d, Start: %llu, End: %llu, type:"
+ " %d\n", pwr->cpu, pwr->start_time,
+ pwr->end_time, pwr->state);
+ }
+ /* trenn: Looks like there is a dummy c-state entry of
+ * type==0, start_time==0, end_time==highest_timestamp
+ * for each CPU at the end of the list, this one should
+ * better be filtered out before -> ignore it here.
+ */
+ if ((pwr->state == 0 && pwr->start_time == 0)) {
+ pwr = pwr->next;
+ continue;
+ }
+
+ svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time,
+ pwr->state);
+ }
pwr = pwr->next;
}

diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index b3637db..20c02fc 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -16,8 +16,13 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <linux/cpuidle.h>

#include "svghelper.h"
+#include "debug.h"

static u64 first_time, last_time;
static u64 turbo_frequency, max_freq;
@@ -43,11 +48,11 @@ static double cpu2y(int cpu)
return cpu2slot(cpu) * SLOT_MULT;
}

-static double time2pixels(u64 time)
+static double time2pixels(u64 __time)
{
double X;

- X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time);
+ X = 1.0 * svg_page_width * (__time - first_time) / (last_time - first_time);
return X;
}

@@ -107,12 +112,14 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
- fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n");
- fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n");
- fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n");
- fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n");
- fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n");
- fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c0 { fill:rgb(102,255,102); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c1 { fill:rgb(102,255, 0); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c2 { fill:rgb( 0,255,102); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c3 { fill:rgb( 51,255, 51); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c4 { fill:rgb( 51,255, 0); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c5 { fill:rgb( 0,255, 51); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c6 { fill:rgb( 0,204, 0); fill-opacity:0.5; stroke-width:0; } \n");
+ fprintf(svgfile, " rect.c7 { fill:rgb( 0,153, 0); fill-opacity:0.5; stroke-width:0; } \n");
fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n");

fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
@@ -199,6 +206,81 @@ void svg_waiting(int Yslot, u64 start, u64 end)
fprintf(svgfile, "</g>\n");
}

+/* Cpuidle info from sysfs ***************************/
+struct cpuidle_state cpuidle_states[CPUIDLE_STATE_MAX];
+unsigned int cpuidle_info_max;
+
+static void debug_dump_cpuidle_states(void)
+{
+ unsigned int state;
+
+ if (cpuidle_info_max == 0) {
+ printf("No cpuidle info retrieved from /sys\n");
+ return;
+ }
+ printf("cpuidle_info_max: %u\n", cpuidle_info_max);
+ for (state = 0; state < cpuidle_info_max; state++) {
+ printf("CPUIDLE[%u]:\n", state);
+ printf("Name: %s\n", cpuidle_states[state].name);
+ printf("Abbr: %s\n", cpuidle_states[state].abbr);
+ }
+}
+static int get_sysfs_string(const char *path, char *string,
+ int max_string_size)
+{
+ int fd;
+ size_t numread, i;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ numread = read(fd, string, max_string_size-1);
+ if (numread < 1) {
+ close(fd);
+ return -1;
+ }
+ for (i = 0; i < numread; i++)
+ if (string[i] == '\n')
+ string[i] = '\0';
+ string[numread] = '\0';
+ close(fd);
+ return 0;
+}
+
+#define PERF_CPUIDLE_SYS_PATH "/sys/devices/system/cpu/cpu0/cpuidle/state%u/"
+#define PERF_SYSFS_PATH_MAX 255
+
+/*
+ * Fills up cpuidle_states[CPUIDLE_STATE_MAX] info from
+ * /sys/devices/system/cpu/cpu0/cpuidle/stateX/ and sets cpuidle_info_max
+ * to found states
+ */
+static int retrieve_cpuidle_info(void)
+{
+ char path[PERF_SYSFS_PATH_MAX];
+ int state, ret;
+
+ for (state = 0; state < CPUIDLE_STATE_MAX; state++) {
+ snprintf(path, sizeof(path), PERF_CPUIDLE_SYS_PATH "name",
+ state);
+ ret = get_sysfs_string(path, cpuidle_states[state].name,
+ CPUIDLE_NAME_LEN + 1);
+ if (ret)
+ break;
+
+ snprintf(path, sizeof(path), PERF_CPUIDLE_SYS_PATH "abbr",
+ state);
+ ret = get_sysfs_string(path, cpuidle_states[state].abbr,
+ CPUIDLE_ABBR_LEN + 1);
+ if (ret)
+ break;
+ }
+ cpuidle_info_max = state;
+ return state;
+}
+/* Cpuidle info from sysfs ***************************/
+
static char *cpu_model(void)
{
static char cpu_m[255];
@@ -278,17 +360,33 @@ void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name
fprintf(svgfile, "</g>\n");
}

+/*
+ * Svg util and kernel supported max cpuidle states may differ.
+ * Cmp. with tools/perf/utils/include/linux/cpuidle.h
+ * and include/linux/cpuidle.h
+ * Currently cpuidle kernel interface and this svg tool, both support 8 states
+ */
+#define PERF_SVG_CPUIDLE_STATE_MAX 8
+
void svg_cstate(int cpu, u64 start, u64 end, int type)
{
double width;
char style[128];
+ static bool max_states_exceed_msg;

if (!svgfile)
return;

+ if (type > PERF_SVG_CPUIDLE_STATE_MAX) {
+ if (verbose || max_states_exceed_msg == false) {
+ max_states_exceed_msg = true;
+ printf("cpuidle state (%d) exceeding max supported "
+ "states (%d).. ignoring\n",
+ type, PERF_SVG_CPUIDLE_STATE_MAX);
+ return;
+ }
+ }

- if (type > 6)
- type = 6;
sprintf(style, "c%i", type);

fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n",
@@ -451,16 +549,40 @@ static void svg_legenda_box(int X, const char *text, const char *style)

void svg_legenda(void)
{
+ unsigned int cstate, offset = 500;
+ char class[3];
+
+ retrieve_cpuidle_info();
+ /* perf timechart does not implement a verbose (-v) param yet
+ remove below comment if you want to be more verbose. */
+ /* verbose = 1; */
+ if (verbose)
+ debug_dump_cpuidle_states();
+
if (!svgfile)
return;

- svg_legenda_box(0, "Running", "sample");
- svg_legenda_box(100, "Idle","rect.c1");
- svg_legenda_box(200, "Deeper Idle", "rect.c3");
- svg_legenda_box(350, "Deepest Idle", "rect.c6");
- svg_legenda_box(550, "Sleeping", "process2");
- svg_legenda_box(650, "Waiting for cpu", "waiting");
- svg_legenda_box(800, "Blocked on IO", "blocked");
+ svg_legenda_box(0, "Running", "sample");
+ svg_legenda_box(100, "Sleeping", "process2");
+ svg_legenda_box(200, "Waiting for cpu", "waiting");
+ svg_legenda_box(350, "Blocked on IO", "blocked");
+ /* trenn: Arch specific events. Only C1 exists on x86 if
+ no cpuidle driver registered. Deeper and Deepest can get
+ removed. Also C1 events may only get fired through cpuidle
+ driver at some time. */
+ if (cpuidle_info_max == 0) {
+ svg_legenda_box(500, "Idle", "c1");
+ } else {
+ for (cstate = 0; cstate < cpuidle_info_max; cstate++) {
+ sprintf(class, "c%u", cstate);
+ svg_legenda_box(offset, cpuidle_states[cstate].name,
+ class);
+ /* The box */
+ offset += 20;
+ /* The text */
+ offset += (strlen(cpuidle_states[cstate].name) * 10);
+ }
+ }
}

void svg_time_grid(void)
--
1.6.0.2

2010-12-02 16:43:42

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 5/8] cpuidle: Introduce .abbr (abbrevation) for cpuidle states

and fill name, description and newly introduced abbrivation
consistenly (always use snprintf) in all cpuidle drivers.

This is mainly for perf timechart. It draws vector graphics
pictures of sleep/idle state usage catching perf cpu_idle events.
The string used for the idle state must not exceed 3 chars or
you can't see much in these pictures.
The name could get used in the title, the introduced abbrivations
inside of the picture and the text must therefore be rather short.

Signed-off-by: Thomas Renninger <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: Arjan van de Ven <[email protected]>
CC: Ingo Molnar <[email protected]>
CC: [email protected]
CC: [email protected]
---
arch/arm/mach-at91/cpuidle.c | 12 ++++++++----
arch/arm/mach-davinci/cpuidle.c | 13 +++++++++----
arch/arm/mach-kirkwood/cpuidle.c | 12 ++++++++----
arch/arm/mach-omap2/cpuidle34xx.c | 3 ++-
arch/sh/kernel/cpu/shmobile/cpuidle.c | 19 +++++++++++--------
drivers/acpi/processor_idle.c | 3 +++
drivers/cpuidle/cpuidle.c | 1 +
drivers/cpuidle/sysfs.c | 3 +++
drivers/idle/intel_idle.c | 11 +++++++++++
include/linux/cpuidle.h | 2 ++
10 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index 1cfeac1..6cdeb42 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -73,16 +73,20 @@ static int at91_init_cpuidle(void)
device->states[0].exit_latency = 1;
device->states[0].target_residency = 10000;
device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[0].name, "WFI");
- strcpy(device->states[0].desc, "Wait for interrupt");
+ snprintf(device->states[0].name, CPUIDLE_NAME_LEN, "WFI");
+ snprintf(device->states[0].desc, CPUIDLE_DESC_LEN,
+ "Wait for interrupt");
+ snprintf(device->states[0].abbr, CPUIDLE_ABBR_LEN, "W");

/* Wait for interrupt and RAM self refresh state */
device->states[1].enter = at91_enter_idle;
device->states[1].exit_latency = 10;
device->states[1].target_residency = 10000;
device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[1].name, "RAM_SR");
- strcpy(device->states[1].desc, "WFI and RAM Self Refresh");
+ snprintf(device->states[1].name, CPUIDLE_NAME_LEN, "RAM SR");
+ snprintf(device->states[1].desc, CPUIDLE_DESC_LEN,
+ "WFI and RAM Self Refresh");
+ snprintf(device->states[1].abbr, CPUIDLE_ABBR_LEN, "WSR");

if (cpuidle_register_device(device)) {
printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index bd59f31..42ad2d6 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -127,16 +127,21 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
device->states[0].exit_latency = 1;
device->states[0].target_residency = 10000;
device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[0].name, "WFI");
- strcpy(device->states[0].desc, "Wait for interrupt");
+ snprintf(device->states[0].name, CPUIDLE_NAME_LEN, "WFI");
+ snprintf(device->states[0].desc, CPUIDLE_DESC_LEN,
+ "Wait for interrupt");
+ snprintf(device->states[0].abbr, CPUIDLE_ABBR_LEN, "W");

/* Wait for interrupt and DDR self refresh state */
device->states[1].enter = davinci_enter_idle;
device->states[1].exit_latency = 10;
device->states[1].target_residency = 10000;
device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[1].name, "DDR SR");
- strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+ snprintf(device->states[1].name, CPUIDLE_NAME_LEN, "RAM SR");
+ snprintf(device->states[1].desc, CPUIDLE_DESC_LEN,
+ "WFI and RAM Self Refresh");
+ snprintf(device->states[1].abbr, CPUIDLE_ABBR_LEN, "WSR");
+
if (pdata->ddr2_pdown)
davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
cpuidle_set_statedata(&device->states[1], &davinci_states[1]);
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index f68d33f..48eaabb 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -75,16 +75,20 @@ static int kirkwood_init_cpuidle(void)
device->states[0].exit_latency = 1;
device->states[0].target_residency = 10000;
device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[0].name, "WFI");
- strcpy(device->states[0].desc, "Wait for interrupt");
+ snprintf(device->states[0].name, CPUIDLE_NAME_LEN, "WFI");
+ snprintf(device->states[0].desc, CPUIDLE_DESC_LEN,
+ "Wait for interrupt");
+ snprintf(device->states[0].abbr, CPUIDLE_ABBR_LEN, "W");

/* Wait for interrupt and DDR self refresh state */
device->states[1].enter = kirkwood_enter_idle;
device->states[1].exit_latency = 10;
device->states[1].target_residency = 10000;
device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[1].name, "DDR SR");
- strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+ snprintf(device->states[1].name, CPUIDLE_NAME_LEN, "RAM SR");
+ snprintf(device->states[1].desc, CPUIDLE_DESC_LEN,
+ "WFI and RAM Self Refresh");
+ snprintf(device->states[1].abbr, CPUIDLE_ABBR_LEN, "WSR");

if (cpuidle_register_device(device)) {
printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 0d50b45..a59ac39 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -496,7 +496,8 @@ int __init omap3_idle_init(void)
omap3_enter_idle_bm : omap3_enter_idle;
if (cx->type == OMAP3_STATE_C1)
dev->safe_state = state;
- sprintf(state->name, "C%d", count+1);
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", count+1);
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C%d", count+1);
count++;
}

diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 83972aa..9ad151d 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -75,8 +75,9 @@ void sh_mobile_setup_cpuidle(void)
i = CPUIDLE_DRIVER_STATE_START;

state = &dev->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
- strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
+ snprintf(state->name, CPUIDLE_NAME_LEN, "SuperH");
+ snprintf(state->desc, CPUIDLE_DESC_LEN, "SuperH Sleep Mode");
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "SH");
state->exit_latency = 1;
state->target_residency = 1 * 2;
state->power_usage = 3;
@@ -89,9 +90,10 @@ void sh_mobile_setup_cpuidle(void)

if (sh_mobile_sleep_supported & SUSP_SH_SF) {
state = &dev->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
- strncpy(state->desc, "SuperH Sleep Mode [SF]",
- CPUIDLE_DESC_LEN);
+ snprintf(state->name, CPUIDLE_NAME_LEN, "SuperH [SF]");
+ snprintf(state->desc, CPUIDLE_DESC_LEN,
+ "SuperH Sleep Mode [SF]");
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "SHF");
state->exit_latency = 100;
state->target_residency = 1 * 2;
state->power_usage = 1;
@@ -102,9 +104,10 @@ void sh_mobile_setup_cpuidle(void)

if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
state = &dev->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
- strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
- CPUIDLE_DESC_LEN);
+ snprintf(state->name, CPUIDLE_NAME_LEN, "SuperH Standby [SF]");
+ snprintf(state->desc, CPUIDLE_DESC_LEN,
+ "SuperH Mobile Standby Mode [SF]");
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "SHS");
state->exit_latency = 2300;
state->target_residency = 1 * 2;
state->power_usage = 1;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index dda3412..e74f72c 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1023,6 +1023,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
switch (cx->type) {
case ACPI_STATE_C1:
snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C1");
state->flags |= CPUIDLE_FLAG_SHALLOW;
if (cx->entry_method == ACPI_CSTATE_FFH)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
@@ -1033,6 +1034,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)

case ACPI_STATE_C2:
snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C2");
state->flags |= CPUIDLE_FLAG_BALANCED;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
@@ -1041,6 +1043,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)

case ACPI_STATE_C3:
snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C3");
state->flags |= CPUIDLE_FLAG_DEEP;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->flags |= CPUIDLE_FLAG_CHECK_BM;
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 4649495..b2d2b69 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -268,6 +268,7 @@ static void poll_idle_init(struct cpuidle_device *dev)

snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
+ snprintf(state->abbr, CPUIDLE_ABBR_LEN, "P");
state->exit_latency = 0;
state->target_residency = 0;
state->power_usage = -1;
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 0310ffa..ca7a62c 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -249,9 +249,11 @@ define_show_state_ull_function(usage)
define_show_state_ull_function(time)
define_show_state_str_function(name)
define_show_state_str_function(desc)
+define_show_state_str_function(abbr)

define_one_state_ro(name, show_state_name);
define_one_state_ro(desc, show_state_desc);
+define_one_state_ro(abbr, show_state_abbr);
define_one_state_ro(latency, show_state_exit_latency);
define_one_state_ro(power, show_state_power_usage);
define_one_state_ro(usage, show_state_usage);
@@ -260,6 +262,7 @@ define_one_state_ro(time, show_state_time);
static struct attribute *cpuidle_state_default_attrs[] = {
&attr_name.attr,
&attr_desc.attr,
+ &attr_abbr.attr,
&attr_latency.attr,
&attr_power.attr,
&attr_usage.attr,
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index f0798ff..b2954a0 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -91,6 +91,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C1 */
.name = "NHM-C1",
.desc = "MWAIT 0x00",
+ .abbr = "C1",
.driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 3,
@@ -99,6 +100,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C2 */
.name = "NHM-C3",
.desc = "MWAIT 0x10",
+ .abbr = "C3",
.driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 20,
@@ -107,6 +109,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C3 */
.name = "NHM-C6",
.desc = "MWAIT 0x20",
+ .abbr = "C6",
.driver_data = (void *) 0x20,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
@@ -119,6 +122,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C1 */
.name = "SNB-C1",
.desc = "MWAIT 0x00",
+ .abbr = "C1",
.driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
@@ -127,6 +131,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C2 */
.name = "SNB-C3",
.desc = "MWAIT 0x10",
+ .abbr = "C3",
.driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
@@ -135,6 +140,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C3 */
.name = "SNB-C6",
.desc = "MWAIT 0x20",
+ .abbr = "C6",
.driver_data = (void *) 0x20,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 104,
@@ -143,6 +149,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C4 */
.name = "SNB-C7",
.desc = "MWAIT 0x30",
+ .abbr = "C7",
.driver_data = (void *) 0x30,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 109,
@@ -155,6 +162,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C1 */
.name = "ATM-C1",
.desc = "MWAIT 0x00",
+ .abbr = "C1",
.driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
@@ -163,6 +171,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C2 */
.name = "ATM-C2",
.desc = "MWAIT 0x10",
+ .abbr = "C2",
.driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 20,
@@ -172,6 +181,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C4 */
.name = "ATM-C4",
.desc = "MWAIT 0x30",
+ .abbr = "C4",
.driver_data = (void *) 0x30,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
@@ -181,6 +191,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C6 */
.name = "ATM-C6",
.desc = "MWAIT 0x52",
+ .abbr = "C6",
.driver_data = (void *) 0x52,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 1be416b..4763ef3 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -20,6 +20,7 @@
#define CPUIDLE_STATE_MAX 8
#define CPUIDLE_NAME_LEN 16
#define CPUIDLE_DESC_LEN 32
+#define CPUIDLE_ABBR_LEN 3

struct cpuidle_device;

@@ -31,6 +32,7 @@ struct cpuidle_device;
struct cpuidle_state {
char name[CPUIDLE_NAME_LEN];
char desc[CPUIDLE_DESC_LEN];
+ char abbr[CPUIDLE_ABBR_LEN];
void *driver_data;

unsigned int flags;
--
1.6.0.2

2010-12-02 16:44:24

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH 8/8] perf: timechart: Fix memleak

There are others, but these are not worth it, e.g. built
up power event list which gets destroyed on program exit anyway or
some bytes when trace events get parsed.

This one showed by far the biggest memory waste, was easy to
fix and could help when parsing huge trace event records.

Signed-off-by: Thomas Renninger <[email protected]>
CC: Arjan van de Ven <[email protected]>
CC: Ingo Molnar <[email protected]>
CC: [email protected]
CC: [email protected]

Found with valgrind, fixes:
==43509== 1,402 bytes in 251 blocks are definitely lost in loss record 61 of 74
==43509== at 0x4C261D7: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==43509== by 0x61573B1: strdup (in /lib64/libc-2.11.1.so)
==43509== by 0x41DD3D: draw_wakeups (builtin-timechart.c:706)
==43509== by 0x41E7C9: write_svg_file (builtin-timechart.c:957)
==43509== by 0x41E87E: __cmd_timechart (builtin-timechart.c:989)
==43509== by 0x41EB3C: cmd_timechart (builtin-timechart.c:1097)
==43509== by 0x40D776: run_builtin (perf.c:286)
==43509== by 0x40D993: handle_internal_command (perf.c:357)
==43509== by 0x40DAD2: run_argv (perf.c:401)
==43509== by 0x40DCB3: main (perf.c:487)
==43509==
==43509== 2,826 bytes in 429 blocks are definitely lost in loss record 63 of 74
==43509== at 0x4C261D7: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==43509== by 0x61573B1: strdup (in /lib64/libc-2.11.1.so)
==43509== by 0x41DD70: draw_wakeups (builtin-timechart.c:710)
==43509== by 0x41E7C9: write_svg_file (builtin-timechart.c:957)
==43509== by 0x41E87E: __cmd_timechart (builtin-timechart.c:989)
==43509== by 0x41EB3C: cmd_timechart (builtin-timechart.c:1097)
==43509== by 0x40D776: run_builtin (perf.c:286)
==43509== by 0x40D993: handle_internal_command (perf.c:357)
==43509== by 0x40DAD2: run_argv (perf.c:401)
==43509== by 0x40DCB3: main (perf.c:487)
---
tools/perf/builtin-timechart.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 391e475..c6e0a00 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -715,10 +715,14 @@ static void draw_wakeups(void)
if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
if (p->pid == we->waker && !from) {
from = c->Y;
+ if (task_from)
+ free(task_from);
task_from = strdup(c->comm);
}
if (p->pid == we->wakee && !to) {
to = c->Y;
+ if (task_to)
+ free(task_to);
task_to = strdup(c->comm);
}
}
@@ -728,10 +732,14 @@ static void draw_wakeups(void)
while (c) {
if (p->pid == we->waker && !from) {
from = c->Y;
+ if (task_from)
+ free(task_from);
task_from = strdup(c->comm);
}
if (p->pid == we->wakee && !to) {
to = c->Y;
+ if (task_to)
+ free(task_to);
task_to = strdup(c->comm);
}
c = c->next;
--
1.6.0.2

2010-12-02 16:51:43

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH 7/8] perf timechart: Map power:cpu_idle events to the corresponding cpuidle state

On Thursday 02 December 2010 17:42:27 Thomas Renninger wrote:
> Before, power:cpu_idle events were very specific X86 Intel mwait events.
> This got fixed with previous patches and cpu_idle events are now thrown by
> all cpuidle drivers and can be mapped to the corresponding cpuidle state
> in /sys.
>
> This patch reads out the corresponding cpuidle name of a cpu_idle event
> and uses it in the title line of the chart (c-states Cx in x86, omap2
> - DDR self refresh states for various arm archs).
>
> It also reads out the corresponding abbr(eviation) and uses the string
> to draw the cpu idle occurences. This needs a short (3 letter) string
> to keep the overview in the chart.

I forgot two other changes:
- Fixes black c-state drawings in eog and firefox:
class="rect.cX" is wrong and must be class="cX"
- Use green color instead of red for idle drawings. This does not clash
with the Block IO drawings (also red) and better fits the "green IT"
background the C-states are about :) (that was not really the reason,
green was one of the last not used colors)...

Thomas

2010-12-02 17:31:26

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH 2/8] cpuidle: Rename X86 specific idle poll state[0] from C0 to CPUIDLE

On Thursday, December 02, 2010 09:42:22 am Thomas Renninger wrote:
> C0 means and is well know as "not idle".
> All documentation out there uses this term as "running"/"not idle"
> state. Also Linux userspace tools (e.g. cpufreq-aperf and turbostat)
> show C0 residency which there is correct, but means something totally
> else than cpuidle "POLL" state.
>
>
> Signed-off-by: Thomas Renninger <[email protected]>
> CC: [email protected]
> CC: [email protected]
> CC: [email protected]
> CC: Ingo Molnar <[email protected]>
> CC: [email protected]
> ---
> drivers/cpuidle/cpuidle.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
> index 08d5f05..99cc8fc 100644
> --- a/drivers/cpuidle/cpuidle.c
> +++ b/drivers/cpuidle/cpuidle.c
> @@ -260,7 +260,7 @@ static void poll_idle_init(struct cpuidle_device *dev)
>
> cpuidle_set_statedata(state, NULL);
>
> - snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
> + snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");

The description says "rename C0 to CPUIDLE", but the patch looks like
"rename C0 to POLL".

> snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
> state->exit_latency = 0;
> state->target_residency = 0;
>

2010-12-02 17:33:37

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH 5/8] cpuidle: Introduce .abbr (abbrevation) for cpuidle states

On Thursday, December 02, 2010 09:42:25 am Thomas Renninger wrote:
> and fill name, description and newly introduced abbrivation
> consistenly (always use snprintf) in all cpuidle drivers.
>
> This is mainly for perf timechart. It draws vector graphics
> pictures of sleep/idle state usage catching perf cpu_idle events.
> The string used for the idle state must not exceed 3 chars or
> you can't see much in these pictures.
> The name could get used in the title, the introduced abbrivations
> inside of the picture and the text must therefore be rather short.

s/abbrivation/abbreviation/g above.
s/consistenly/consistently/

> Signed-off-by: Thomas Renninger <[email protected]>
> CC: [email protected]
> CC: [email protected]
> CC: [email protected]
> CC: Arjan van de Ven <[email protected]>
> CC: Ingo Molnar <[email protected]>
> CC: [email protected]
> CC: [email protected]
> ---
> arch/arm/mach-at91/cpuidle.c | 12 ++++++++----
> arch/arm/mach-davinci/cpuidle.c | 13 +++++++++----
> arch/arm/mach-kirkwood/cpuidle.c | 12 ++++++++----
> arch/arm/mach-omap2/cpuidle34xx.c | 3 ++-
> arch/sh/kernel/cpu/shmobile/cpuidle.c | 19 +++++++++++--------
> drivers/acpi/processor_idle.c | 3 +++
> drivers/cpuidle/cpuidle.c | 1 +
> drivers/cpuidle/sysfs.c | 3 +++
> drivers/idle/intel_idle.c | 11 +++++++++++
> include/linux/cpuidle.h | 2 ++
> 10 files changed, 58 insertions(+), 21 deletions(-)
>
> diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
> index 1cfeac1..6cdeb42 100644
> --- a/arch/arm/mach-at91/cpuidle.c
> +++ b/arch/arm/mach-at91/cpuidle.c
> @@ -73,16 +73,20 @@ static int at91_init_cpuidle(void)
> device->states[0].exit_latency = 1;
> device->states[0].target_residency = 10000;
> device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
> - strcpy(device->states[0].name, "WFI");
> - strcpy(device->states[0].desc, "Wait for interrupt");
> + snprintf(device->states[0].name, CPUIDLE_NAME_LEN, "WFI");
> + snprintf(device->states[0].desc, CPUIDLE_DESC_LEN,
> + "Wait for interrupt");
> + snprintf(device->states[0].abbr, CPUIDLE_ABBR_LEN, "W");
>
> /* Wait for interrupt and RAM self refresh state */
> device->states[1].enter = at91_enter_idle;
> device->states[1].exit_latency = 10;
> device->states[1].target_residency = 10000;
> device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
> - strcpy(device->states[1].name, "RAM_SR");
> - strcpy(device->states[1].desc, "WFI and RAM Self Refresh");
> + snprintf(device->states[1].name, CPUIDLE_NAME_LEN, "RAM SR");
> + snprintf(device->states[1].desc, CPUIDLE_DESC_LEN,
> + "WFI and RAM Self Refresh");
> + snprintf(device->states[1].abbr, CPUIDLE_ABBR_LEN, "WSR");
>
> if (cpuidle_register_device(device)) {
> printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
> diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
> index bd59f31..42ad2d6 100644
> --- a/arch/arm/mach-davinci/cpuidle.c
> +++ b/arch/arm/mach-davinci/cpuidle.c
> @@ -127,16 +127,21 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
> device->states[0].exit_latency = 1;
> device->states[0].target_residency = 10000;
> device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
> - strcpy(device->states[0].name, "WFI");
> - strcpy(device->states[0].desc, "Wait for interrupt");
> + snprintf(device->states[0].name, CPUIDLE_NAME_LEN, "WFI");
> + snprintf(device->states[0].desc, CPUIDLE_DESC_LEN,
> + "Wait for interrupt");
> + snprintf(device->states[0].abbr, CPUIDLE_ABBR_LEN, "W");
>
> /* Wait for interrupt and DDR self refresh state */
> device->states[1].enter = davinci_enter_idle;
> device->states[1].exit_latency = 10;
> device->states[1].target_residency = 10000;
> device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
> - strcpy(device->states[1].name, "DDR SR");
> - strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
> + snprintf(device->states[1].name, CPUIDLE_NAME_LEN, "RAM SR");
> + snprintf(device->states[1].desc, CPUIDLE_DESC_LEN,
> + "WFI and RAM Self Refresh");
> + snprintf(device->states[1].abbr, CPUIDLE_ABBR_LEN, "WSR");
> +
> if (pdata->ddr2_pdown)
> davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
> cpuidle_set_statedata(&device->states[1], &davinci_states[1]);
> diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
> index f68d33f..48eaabb 100644
> --- a/arch/arm/mach-kirkwood/cpuidle.c
> +++ b/arch/arm/mach-kirkwood/cpuidle.c
> @@ -75,16 +75,20 @@ static int kirkwood_init_cpuidle(void)
> device->states[0].exit_latency = 1;
> device->states[0].target_residency = 10000;
> device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
> - strcpy(device->states[0].name, "WFI");
> - strcpy(device->states[0].desc, "Wait for interrupt");
> + snprintf(device->states[0].name, CPUIDLE_NAME_LEN, "WFI");
> + snprintf(device->states[0].desc, CPUIDLE_DESC_LEN,
> + "Wait for interrupt");
> + snprintf(device->states[0].abbr, CPUIDLE_ABBR_LEN, "W");
>
> /* Wait for interrupt and DDR self refresh state */
> device->states[1].enter = kirkwood_enter_idle;
> device->states[1].exit_latency = 10;
> device->states[1].target_residency = 10000;
> device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
> - strcpy(device->states[1].name, "DDR SR");
> - strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
> + snprintf(device->states[1].name, CPUIDLE_NAME_LEN, "RAM SR");
> + snprintf(device->states[1].desc, CPUIDLE_DESC_LEN,
> + "WFI and RAM Self Refresh");
> + snprintf(device->states[1].abbr, CPUIDLE_ABBR_LEN, "WSR");
>
> if (cpuidle_register_device(device)) {
> printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
> diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
> index 0d50b45..a59ac39 100644
> --- a/arch/arm/mach-omap2/cpuidle34xx.c
> +++ b/arch/arm/mach-omap2/cpuidle34xx.c
> @@ -496,7 +496,8 @@ int __init omap3_idle_init(void)
> omap3_enter_idle_bm : omap3_enter_idle;
> if (cx->type == OMAP3_STATE_C1)
> dev->safe_state = state;
> - sprintf(state->name, "C%d", count+1);
> + snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", count+1);
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C%d", count+1);
> count++;
> }
>
> diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
> index 83972aa..9ad151d 100644
> --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
> +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
> @@ -75,8 +75,9 @@ void sh_mobile_setup_cpuidle(void)
> i = CPUIDLE_DRIVER_STATE_START;
>
> state = &dev->states[i++];
> - snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
> - strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
> + snprintf(state->name, CPUIDLE_NAME_LEN, "SuperH");
> + snprintf(state->desc, CPUIDLE_DESC_LEN, "SuperH Sleep Mode");
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "SH");
> state->exit_latency = 1;
> state->target_residency = 1 * 2;
> state->power_usage = 3;
> @@ -89,9 +90,10 @@ void sh_mobile_setup_cpuidle(void)
>
> if (sh_mobile_sleep_supported & SUSP_SH_SF) {
> state = &dev->states[i++];
> - snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
> - strncpy(state->desc, "SuperH Sleep Mode [SF]",
> - CPUIDLE_DESC_LEN);
> + snprintf(state->name, CPUIDLE_NAME_LEN, "SuperH [SF]");
> + snprintf(state->desc, CPUIDLE_DESC_LEN,
> + "SuperH Sleep Mode [SF]");
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "SHF");
> state->exit_latency = 100;
> state->target_residency = 1 * 2;
> state->power_usage = 1;
> @@ -102,9 +104,10 @@ void sh_mobile_setup_cpuidle(void)
>
> if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
> state = &dev->states[i++];
> - snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
> - strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
> - CPUIDLE_DESC_LEN);
> + snprintf(state->name, CPUIDLE_NAME_LEN, "SuperH Standby [SF]");
> + snprintf(state->desc, CPUIDLE_DESC_LEN,
> + "SuperH Mobile Standby Mode [SF]");
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "SHS");
> state->exit_latency = 2300;
> state->target_residency = 1 * 2;
> state->power_usage = 1;
> diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
> index dda3412..e74f72c 100644
> --- a/drivers/acpi/processor_idle.c
> +++ b/drivers/acpi/processor_idle.c
> @@ -1023,6 +1023,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
> switch (cx->type) {
> case ACPI_STATE_C1:
> snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C1");
> state->flags |= CPUIDLE_FLAG_SHALLOW;
> if (cx->entry_method == ACPI_CSTATE_FFH)
> state->flags |= CPUIDLE_FLAG_TIME_VALID;
> @@ -1033,6 +1034,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
>
> case ACPI_STATE_C2:
> snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C2");
> state->flags |= CPUIDLE_FLAG_BALANCED;
> state->flags |= CPUIDLE_FLAG_TIME_VALID;
> state->enter = acpi_idle_enter_simple;
> @@ -1041,6 +1043,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
>
> case ACPI_STATE_C3:
> snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "C3");
> state->flags |= CPUIDLE_FLAG_DEEP;
> state->flags |= CPUIDLE_FLAG_TIME_VALID;
> state->flags |= CPUIDLE_FLAG_CHECK_BM;
> diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
> index 4649495..b2d2b69 100644
> --- a/drivers/cpuidle/cpuidle.c
> +++ b/drivers/cpuidle/cpuidle.c
> @@ -268,6 +268,7 @@ static void poll_idle_init(struct cpuidle_device *dev)
>
> snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
> snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
> + snprintf(state->abbr, CPUIDLE_ABBR_LEN, "P");
> state->exit_latency = 0;
> state->target_residency = 0;
> state->power_usage = -1;
> diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
> index 0310ffa..ca7a62c 100644
> --- a/drivers/cpuidle/sysfs.c
> +++ b/drivers/cpuidle/sysfs.c
> @@ -249,9 +249,11 @@ define_show_state_ull_function(usage)
> define_show_state_ull_function(time)
> define_show_state_str_function(name)
> define_show_state_str_function(desc)
> +define_show_state_str_function(abbr)
>
> define_one_state_ro(name, show_state_name);
> define_one_state_ro(desc, show_state_desc);
> +define_one_state_ro(abbr, show_state_abbr);
> define_one_state_ro(latency, show_state_exit_latency);
> define_one_state_ro(power, show_state_power_usage);
> define_one_state_ro(usage, show_state_usage);
> @@ -260,6 +262,7 @@ define_one_state_ro(time, show_state_time);
> static struct attribute *cpuidle_state_default_attrs[] = {
> &attr_name.attr,
> &attr_desc.attr,
> + &attr_abbr.attr,
> &attr_latency.attr,
> &attr_power.attr,
> &attr_usage.attr,
> diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
> index f0798ff..b2954a0 100644
> --- a/drivers/idle/intel_idle.c
> +++ b/drivers/idle/intel_idle.c
> @@ -91,6 +91,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C1 */
> .name = "NHM-C1",
> .desc = "MWAIT 0x00",
> + .abbr = "C1",
> .driver_data = (void *) 0x00,
> .flags = CPUIDLE_FLAG_TIME_VALID,
> .exit_latency = 3,
> @@ -99,6 +100,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C2 */
> .name = "NHM-C3",
> .desc = "MWAIT 0x10",
> + .abbr = "C3",
> .driver_data = (void *) 0x10,
> .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
> .exit_latency = 20,
> @@ -107,6 +109,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C3 */
> .name = "NHM-C6",
> .desc = "MWAIT 0x20",
> + .abbr = "C6",
> .driver_data = (void *) 0x20,
> .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
> .exit_latency = 200,
> @@ -119,6 +122,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C1 */
> .name = "SNB-C1",
> .desc = "MWAIT 0x00",
> + .abbr = "C1",
> .driver_data = (void *) 0x00,
> .flags = CPUIDLE_FLAG_TIME_VALID,
> .exit_latency = 1,
> @@ -127,6 +131,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C2 */
> .name = "SNB-C3",
> .desc = "MWAIT 0x10",
> + .abbr = "C3",
> .driver_data = (void *) 0x10,
> .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
> .exit_latency = 80,
> @@ -135,6 +140,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C3 */
> .name = "SNB-C6",
> .desc = "MWAIT 0x20",
> + .abbr = "C6",
> .driver_data = (void *) 0x20,
> .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
> .exit_latency = 104,
> @@ -143,6 +149,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C4 */
> .name = "SNB-C7",
> .desc = "MWAIT 0x30",
> + .abbr = "C7",
> .driver_data = (void *) 0x30,
> .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
> .exit_latency = 109,
> @@ -155,6 +162,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C1 */
> .name = "ATM-C1",
> .desc = "MWAIT 0x00",
> + .abbr = "C1",
> .driver_data = (void *) 0x00,
> .flags = CPUIDLE_FLAG_TIME_VALID,
> .exit_latency = 1,
> @@ -163,6 +171,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C2 */
> .name = "ATM-C2",
> .desc = "MWAIT 0x10",
> + .abbr = "C2",
> .driver_data = (void *) 0x10,
> .flags = CPUIDLE_FLAG_TIME_VALID,
> .exit_latency = 20,
> @@ -172,6 +181,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C4 */
> .name = "ATM-C4",
> .desc = "MWAIT 0x30",
> + .abbr = "C4",
> .driver_data = (void *) 0x30,
> .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
> .exit_latency = 100,
> @@ -181,6 +191,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
> { /* MWAIT C6 */
> .name = "ATM-C6",
> .desc = "MWAIT 0x52",
> + .abbr = "C6",
> .driver_data = (void *) 0x52,
> .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
> .exit_latency = 140,
> diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
> index 1be416b..4763ef3 100644
> --- a/include/linux/cpuidle.h
> +++ b/include/linux/cpuidle.h
> @@ -20,6 +20,7 @@
> #define CPUIDLE_STATE_MAX 8
> #define CPUIDLE_NAME_LEN 16
> #define CPUIDLE_DESC_LEN 32
> +#define CPUIDLE_ABBR_LEN 3
>
> struct cpuidle_device;
>
> @@ -31,6 +32,7 @@ struct cpuidle_device;
> struct cpuidle_state {
> char name[CPUIDLE_NAME_LEN];
> char desc[CPUIDLE_DESC_LEN];
> + char abbr[CPUIDLE_ABBR_LEN];
> void *driver_data;
>
> unsigned int flags;
>