|
@@ -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;
|
|
|
|
-
|
|
|
|
- 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);
|
|
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)
|
|
|
|
- c_state_start(pe->cpu_id, sample->time, pe->value);
|
|
|
|
-
|
|
|
|
- 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, "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, "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++)
|