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

Commit 20c457b8 authored by Thomas Renninger's avatar Thomas Renninger Committed by Ingo Molnar
Browse files

perf timechart: Adjust perf timechart to the new power events



builtin-timechart must only pass -e power:xy events if they are supported by
the running kernel, otherwise try to fetch the old power:power{start,end}
events.

For this I added the tiny helper function:

   int is_valid_tracepoint(const char *event_string)

to parse-events.[hc], which could be more generic as an interface and support
hardware/software/... events, not only tracepoints, but someone else could
extend that if needed...

Signed-off-by: default avatarThomas Renninger <trenn@suse.de>
Acked-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Acked-by: default avatarJean Pihet <j-pihet@ti.com>
LKML-Reference: <1294073445-14812-4-git-send-email-trenn@suse.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 25e41933
Loading
Loading
Loading
Loading
+76 −18
Original line number Original line Diff line number Diff line
@@ -32,6 +32,10 @@
#include "util/session.h"
#include "util/session.h"
#include "util/svghelper.h"
#include "util/svghelper.h"


#define SUPPORT_OLD_POWER_EVENTS 1
#define PWR_EVENT_EXIT -1


static char		const *input_name = "perf.data";
static char		const *input_name = "perf.data";
static char		const *output_name = "output.svg";
static char		const *output_name = "output.svg";


@@ -301,12 +305,21 @@ struct trace_entry {
	int			lock_depth;
	int			lock_depth;
};
};


struct power_entry {
#ifdef SUPPORT_OLD_POWER_EVENTS
static int use_old_power_events;
struct power_entry_old {
	struct trace_entry te;
	struct trace_entry te;
	u64	type;
	u64	type;
	u64	value;
	u64	value;
	u64	cpu_id;
	u64	cpu_id;
};
};
#endif

struct power_processor_entry {
	struct trace_entry te;
	u32	state;
	u32	cpu_id;
};


#define TASK_COMM_LEN 16
#define TASK_COMM_LEN 16
struct wakeup_entry {
struct wakeup_entry {
@@ -489,29 +502,49 @@ static int process_sample_event(event_t *event __used,
	te = (void *)sample->raw_data;
	te = (void *)sample->raw_data;
	if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
	if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
		char *event_str;
		char *event_str;
		struct power_entry *pe;
#ifdef SUPPORT_OLD_POWER_EVENTS

		struct power_entry_old *peo;
		pe = (void *)te;
		peo = (void *)te;

#endif
		event_str = perf_header__find_event(te->type);
		event_str = perf_header__find_event(te->type);


		if (!event_str)
		if (!event_str)
			return 0;
			return 0;


		if (strcmp(event_str, "power:power_start") == 0)
		if (strcmp(event_str, "power:cpu_idle") == 0) {
			c_state_start(pe->cpu_id, sample->time, pe->value);
			struct power_processor_entry *ppe = (void *)te;

			if (ppe->state == (u32)PWR_EVENT_EXIT)
		if (strcmp(event_str, "power:power_end") == 0)
				c_state_end(ppe->cpu_id, sample->time);
			c_state_end(pe->cpu_id, sample->time);
			else

				c_state_start(ppe->cpu_id, sample->time,
		if (strcmp(event_str, "power:power_frequency") == 0)
					      ppe->state);
			p_state_change(pe->cpu_id, sample->time, pe->value);
		}
		else if (strcmp(event_str, "power:cpu_frequency") == 0) {
			struct power_processor_entry *ppe = (void *)te;
			p_state_change(ppe->cpu_id, sample->time, ppe->state);
		}


		if (strcmp(event_str, "sched:sched_wakeup") == 0)
		else if (strcmp(event_str, "sched:sched_wakeup") == 0)
			sched_wakeup(sample->cpu, sample->time, sample->pid, te);
			sched_wakeup(sample->cpu, sample->time, sample->pid, te);


		if (strcmp(event_str, "sched:sched_switch") == 0)
		else if (strcmp(event_str, "sched:sched_switch") == 0)
			sched_switch(sample->cpu, sample->time, te);
			sched_switch(sample->cpu, sample->time, te);

#ifdef SUPPORT_OLD_POWER_EVENTS
		if (use_old_power_events) {
			if (strcmp(event_str, "power:power_start") == 0)
				c_state_start(peo->cpu_id, sample->time,
					      peo->value);

			else if (strcmp(event_str, "power:power_end") == 0)
				c_state_end(sample->cpu, sample->time);

			else if (strcmp(event_str,
					"power:power_frequency") == 0)
				p_state_change(peo->cpu_id, sample->time,
					       peo->value);
		}
#endif
	}
	}
	return 0;
	return 0;
}
}
@@ -969,7 +1002,8 @@ static const char * const timechart_usage[] = {
	NULL
	NULL
};
};


static const char *record_args[] = {
#ifdef SUPPORT_OLD_POWER_EVENTS
static const char * const record_old_args[] = {
	"record",
	"record",
	"-a",
	"-a",
	"-R",
	"-R",
@@ -981,19 +1015,43 @@ static const char *record_args[] = {
	"-e", "sched:sched_wakeup",
	"-e", "sched:sched_wakeup",
	"-e", "sched:sched_switch",
	"-e", "sched:sched_switch",
};
};
#endif

static const char * const record_new_args[] = {
	"record",
	"-a",
	"-R",
	"-f",
	"-c", "1",
	"-e", "power:cpu_frequency",
	"-e", "power:cpu_idle",
	"-e", "sched:sched_wakeup",
	"-e", "sched:sched_switch",
};


static int __cmd_record(int argc, const char **argv)
static int __cmd_record(int argc, const char **argv)
{
{
	unsigned int rec_argc, i, j;
	unsigned int rec_argc, i, j;
	const char **rec_argv;
	const char **rec_argv;
	const char * const *record_args = record_new_args;
	unsigned int record_elems = ARRAY_SIZE(record_new_args);

#ifdef SUPPORT_OLD_POWER_EVENTS
	if (!is_valid_tracepoint("power:cpu_idle") &&
	    is_valid_tracepoint("power:power_start")) {
		use_old_power_events = 1;
		record_args = record_old_args;
		record_elems = ARRAY_SIZE(record_old_args);
	}
#endif


	rec_argc = ARRAY_SIZE(record_args) + argc - 1;
	rec_argc = record_elems + argc - 1;
	rec_argv = calloc(rec_argc + 1, sizeof(char *));
	rec_argv = calloc(rec_argc + 1, sizeof(char *));


	if (rec_argv == NULL)
	if (rec_argv == NULL)
		return -ENOMEM;
		return -ENOMEM;


	for (i = 0; i < ARRAY_SIZE(record_args); i++)
	for (i = 0; i < record_elems; i++)
		rec_argv[i] = strdup(record_args[i]);
		rec_argv[i] = strdup(record_args[i]);


	for (j = 1; j < (unsigned int)argc; j++, i++)
	for (j = 1; j < (unsigned int)argc; j++, i++)
+41 −0
Original line number Original line Diff line number Diff line
@@ -912,6 +912,47 @@ static void print_tracepoint_events(void)
	closedir(sys_dir);
	closedir(sys_dir);
}
}


/*
 * Check whether event is in <debugfs_mount_point>/tracing/events
 */

int is_valid_tracepoint(const char *event_string)
{
	DIR *sys_dir, *evt_dir;
	struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
	char evt_path[MAXPATHLEN];
	char dir_path[MAXPATHLEN];

	if (debugfs_valid_mountpoint(debugfs_path))
		return 0;

	sys_dir = opendir(debugfs_path);
	if (!sys_dir)
		return 0;

	for_each_subsystem(sys_dir, sys_dirent, sys_next) {

		snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
			 sys_dirent.d_name);
		evt_dir = opendir(dir_path);
		if (!evt_dir)
			continue;

		for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
			snprintf(evt_path, MAXPATHLEN, "%s:%s",
				 sys_dirent.d_name, evt_dirent.d_name);
			if (!strcmp(evt_path, event_string)) {
				closedir(evt_dir);
				closedir(sys_dir);
				return 1;
			}
		}
		closedir(evt_dir);
	}
	closedir(sys_dir);
	return 0;
}

/*
/*
 * Print the help text for the event symbols:
 * Print the help text for the event symbols:
 */
 */
+1 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
#define EVENTS_HELP_MAX (128*1024)
#define EVENTS_HELP_MAX (128*1024)


extern void print_events(void);
extern void print_events(void);
extern int is_valid_tracepoint(const char *event_string);


extern char debugfs_path[];
extern char debugfs_path[];
extern int valid_debugfs_mount(const char *debugfs);
extern int valid_debugfs_mount(const char *debugfs);