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: Thomas Renninger <trenn@suse.de>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Jean Pihet <j-pihet@ti.com>
LKML-Reference: <1294073445-14812-4-git-send-email-trenn@suse.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Thomas Renninger 2011-01-03 17:50:45 +01:00 committed by Ingo Molnar
parent 25e41933b5
commit 20c457b858
3 changed files with 118 additions and 18 deletions

View File

@ -32,6 +32,10 @@
#include "util/session.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 *output_name = "output.svg";
@ -301,12 +305,21 @@ struct trace_entry {
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;
u64 type;
u64 value;
u64 cpu_id;
};
#endif
struct power_processor_entry {
struct trace_entry te;
u32 state;
u32 cpu_id;
};
#define TASK_COMM_LEN 16
struct wakeup_entry {
@ -489,29 +502,49 @@ static int process_sample_event(event_t *event __used,
te = (void *)sample->raw_data;
if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
char *event_str;
struct power_entry *pe;
pe = (void *)te;
#ifdef SUPPORT_OLD_POWER_EVENTS
struct power_entry_old *peo;
peo = (void *)te;
#endif
event_str = perf_header__find_event(te->type);
if (!event_str)
return 0;
if (strcmp(event_str, "power:power_start") == 0)
c_state_start(pe->cpu_id, sample->time, pe->value);
if (strcmp(event_str, "power:cpu_idle") == 0) {
struct power_processor_entry *ppe = (void *)te;
if (ppe->state == (u32)PWR_EVENT_EXIT)
c_state_end(ppe->cpu_id, sample->time);
else
c_state_start(ppe->cpu_id, sample->time,
ppe->state);
}
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, "power:power_end") == 0)
c_state_end(pe->cpu_id, sample->time);
if (strcmp(event_str, "power:power_frequency") == 0)
p_state_change(pe->cpu_id, sample->time, pe->value);
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);
if (strcmp(event_str, "sched:sched_switch") == 0)
else if (strcmp(event_str, "sched:sched_switch") == 0)
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;
}
@ -969,7 +1002,8 @@ static const char * const timechart_usage[] = {
NULL
};
static const char *record_args[] = {
#ifdef SUPPORT_OLD_POWER_EVENTS
static const char * const record_old_args[] = {
"record",
"-a",
"-R",
@ -981,19 +1015,43 @@ static const char *record_args[] = {
"-e", "sched:sched_wakeup",
"-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)
{
unsigned int rec_argc, i, j;
const char **rec_argv;
const char * const *record_args = record_new_args;
unsigned int record_elems = ARRAY_SIZE(record_new_args);
rec_argc = ARRAY_SIZE(record_args) + argc - 1;
#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 = record_elems + argc - 1;
rec_argv = calloc(rec_argc + 1, sizeof(char *));
if (rec_argv == NULL)
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]);
for (j = 1; j < (unsigned int)argc; j++, i++)

View File

@ -912,6 +912,47 @@ static void print_tracepoint_events(void)
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:
*/

View File

@ -36,6 +36,7 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
#define EVENTS_HELP_MAX (128*1024)
extern void print_events(void);
extern int is_valid_tracepoint(const char *event_string);
extern char debugfs_path[];
extern int valid_debugfs_mount(const char *debugfs);