Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3f47a67 authored by Arjan van de Ven's avatar Arjan van de Ven Committed by Ingo Molnar
Browse files

tracing: add "power-tracer": C/P state tracer to help power optimization



Impact: new "power-tracer" ftrace plugin

This patch adds a C/P-state ftrace plugin that will generate
detailed statistics about the C/P-states that are being used,
so that we can look at detailed decisions that the C/P-state
code is making, rather than the too high level "average"
that we have today.

An example way of using this is:

 mount -t debugfs none /sys/kernel/debug
 echo cstate > /sys/kernel/debug/tracing/current_tracer
 echo 1 > /sys/kernel/debug/tracing/tracing_enabled
 sleep 1
 echo 0 > /sys/kernel/debug/tracing/tracing_enabled
 cat /sys/kernel/debug/tracing/trace | perl scripts/trace/cstate.pl > out.svg

Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 509dceef
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/cpufreq.h>
#include <linux/compiler.h>
#include <linux/dmi.h>
#include <linux/ftrace.h>

#include <linux/acpi.h>
#include <acpi/processor.h>
@@ -391,6 +392,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
	unsigned int next_perf_state = 0; /* Index into perf table */
	unsigned int i;
	int result = 0;
	struct power_trace it;

	dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);

@@ -427,6 +429,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
		}
	}

	trace_power_mark(&it, POWER_PSTATE, next_perf_state);

	switch (data->cpu_feature) {
	case SYSTEM_INTEL_MSR_CAPABLE:
		cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
+16 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/clockchips.h>
#include <linux/ftrace.h>
#include <asm/system.h>

unsigned long idle_halt;
@@ -100,6 +101,9 @@ static inline int hlt_use_halt(void)
void default_idle(void)
{
	if (hlt_use_halt()) {
		struct power_trace it;

		trace_power_start(&it, POWER_CSTATE, 1);
		current_thread_info()->status &= ~TS_POLLING;
		/*
		 * TS_POLLING-cleared state must be visible before we
@@ -112,6 +116,7 @@ void default_idle(void)
		else
			local_irq_enable();
		current_thread_info()->status |= TS_POLLING;
		trace_power_end(&it);
	} else {
		local_irq_enable();
		/* loop is done by the caller */
@@ -154,24 +159,31 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
 */
void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
{
	struct power_trace it;

	trace_power_start(&it, POWER_CSTATE, (ax>>4)+1);
	if (!need_resched()) {
		__monitor((void *)&current_thread_info()->flags, 0, 0);
		smp_mb();
		if (!need_resched())
			__mwait(ax, cx);
	}
	trace_power_end(&it);
}

/* Default MONITOR/MWAIT with no hints, used for default C1 state */
static void mwait_idle(void)
{
	struct power_trace it;
	if (!need_resched()) {
		trace_power_start(&it, POWER_CSTATE, 1);
		__monitor((void *)&current_thread_info()->flags, 0, 0);
		smp_mb();
		if (!need_resched())
			__sti_mwait(0, 0);
		else
			local_irq_enable();
		trace_power_end(&it);
	} else
		local_irq_enable();
}
@@ -183,9 +195,13 @@ static void mwait_idle(void)
 */
static void poll_idle(void)
{
	struct power_trace it;

	trace_power_start(&it, POWER_CSTATE, 0);
	local_irq_enable();
	while (!need_resched())
		cpu_relax();
	trace_power_end(&it);
}

/*
+29 −0
Original line number Diff line number Diff line
@@ -311,6 +311,35 @@ ftrace_init_module(struct module *mod,
		   unsigned long *start, unsigned long *end) { }
#endif

enum {
	POWER_NONE = 0,
	POWER_CSTATE = 1,
	POWER_PSTATE = 2,
};

struct power_trace {
#ifdef CONFIG_POWER_TRACER
	ktime_t			stamp;
	ktime_t			end;
	int			type;
	int			state;
#endif
};

#ifdef CONFIG_POWER_TRACER
extern void trace_power_start(struct power_trace *it, unsigned int type,
					unsigned int state);
extern void trace_power_mark(struct power_trace *it, unsigned int type,
					unsigned int state);
extern void trace_power_end(struct power_trace *it);
#else
static inline void trace_power_start(struct power_trace *it, unsigned int type,
					unsigned int state) { }
static inline void trace_power_mark(struct power_trace *it, unsigned int type,
					unsigned int state) { }
static inline void trace_power_end(struct power_trace *it) { }
#endif


/*
 * Structure that defines a return function trace.
+11 −0
Original line number Diff line number Diff line
@@ -217,6 +217,17 @@ config BRANCH_TRACER

	  Say N if unsure.

config POWER_TRACER
	bool "Trace power consumption behavior"
	depends on DEBUG_KERNEL
	depends on X86
	select TRACING
	help
	  This tracer helps developers to analyze and optimize the kernels
	  power management decisions, specifically the C-state and P-state
	  behavior.


config STACK_TRACER
	bool "Trace max stack"
	depends on HAVE_FUNCTION_TRACER
+1 −0
Original line number Diff line number Diff line
@@ -32,5 +32,6 @@ obj-$(CONFIG_BOOT_TRACER) += trace_boot.o
obj-$(CONFIG_FUNCTION_RET_TRACER) += trace_functions_return.o
obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
obj-$(CONFIG_BTS_TRACER) += trace_bts.o
obj-$(CONFIG_POWER_TRACER) += trace_power.o

libftrace-y := ftrace.o
Loading