diff options
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r-- | tools/perf/builtin-timechart.c | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 0bda620a717d..20d4212fa337 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -58,7 +58,8 @@ struct timechart { | |||
58 | first_time, last_time; | 58 | first_time, last_time; |
59 | bool power_only, | 59 | bool power_only, |
60 | tasks_only, | 60 | tasks_only, |
61 | with_backtrace; | 61 | with_backtrace, |
62 | topology; | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | struct per_pidcomm; | 65 | struct per_pidcomm; |
@@ -531,12 +532,10 @@ static int process_sample_event(struct perf_tool *tool, | |||
531 | tchart->last_time = sample->time; | 532 | tchart->last_time = sample->time; |
532 | } | 533 | } |
533 | 534 | ||
534 | if (sample->cpu > tchart->numcpus) | ||
535 | tchart->numcpus = sample->cpu; | ||
536 | |||
537 | if (evsel->handler != NULL) { | 535 | if (evsel->handler != NULL) { |
538 | tracepoint_handler f = evsel->handler; | 536 | tracepoint_handler f = evsel->handler; |
539 | return f(tchart, evsel, sample, cat_backtrace(event, sample, machine)); | 537 | return f(tchart, evsel, sample, |
538 | cat_backtrace(event, sample, machine)); | ||
540 | } | 539 | } |
541 | 540 | ||
542 | return 0; | 541 | return 0; |
@@ -837,8 +836,14 @@ static void draw_cpu_usage(struct timechart *tchart) | |||
837 | while (c) { | 836 | while (c) { |
838 | sample = c->samples; | 837 | sample = c->samples; |
839 | while (sample) { | 838 | while (sample) { |
840 | if (sample->type == TYPE_RUNNING) | 839 | if (sample->type == TYPE_RUNNING) { |
841 | svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm); | 840 | svg_process(sample->cpu, |
841 | sample->start_time, | ||
842 | sample->end_time, | ||
843 | p->pid, | ||
844 | c->comm, | ||
845 | sample->backtrace); | ||
846 | } | ||
842 | 847 | ||
843 | sample = sample->next; | 848 | sample = sample->next; |
844 | } | 849 | } |
@@ -1031,8 +1036,6 @@ static void write_svg_file(struct timechart *tchart, const char *filename) | |||
1031 | int count; | 1036 | int count; |
1032 | int thresh = TIME_THRESH; | 1037 | int thresh = TIME_THRESH; |
1033 | 1038 | ||
1034 | tchart->numcpus++; | ||
1035 | |||
1036 | if (tchart->power_only) | 1039 | if (tchart->power_only) |
1037 | tchart->proc_num = 0; | 1040 | tchart->proc_num = 0; |
1038 | 1041 | ||
@@ -1062,6 +1065,37 @@ static void write_svg_file(struct timechart *tchart, const char *filename) | |||
1062 | svg_close(); | 1065 | svg_close(); |
1063 | } | 1066 | } |
1064 | 1067 | ||
1068 | static int process_header(struct perf_file_section *section __maybe_unused, | ||
1069 | struct perf_header *ph, | ||
1070 | int feat, | ||
1071 | int fd __maybe_unused, | ||
1072 | void *data) | ||
1073 | { | ||
1074 | struct timechart *tchart = data; | ||
1075 | |||
1076 | switch (feat) { | ||
1077 | case HEADER_NRCPUS: | ||
1078 | tchart->numcpus = ph->env.nr_cpus_avail; | ||
1079 | break; | ||
1080 | |||
1081 | case HEADER_CPU_TOPOLOGY: | ||
1082 | if (!tchart->topology) | ||
1083 | break; | ||
1084 | |||
1085 | if (svg_build_topology_map(ph->env.sibling_cores, | ||
1086 | ph->env.nr_sibling_cores, | ||
1087 | ph->env.sibling_threads, | ||
1088 | ph->env.nr_sibling_threads)) | ||
1089 | fprintf(stderr, "problem building topology\n"); | ||
1090 | break; | ||
1091 | |||
1092 | default: | ||
1093 | break; | ||
1094 | } | ||
1095 | |||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1065 | static int __cmd_timechart(struct timechart *tchart, const char *output_name) | 1099 | static int __cmd_timechart(struct timechart *tchart, const char *output_name) |
1066 | { | 1100 | { |
1067 | const struct perf_evsel_str_handler power_tracepoints[] = { | 1101 | const struct perf_evsel_str_handler power_tracepoints[] = { |
@@ -1087,6 +1121,11 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) | |||
1087 | if (session == NULL) | 1121 | if (session == NULL) |
1088 | return -ENOMEM; | 1122 | return -ENOMEM; |
1089 | 1123 | ||
1124 | (void)perf_header__process_sections(&session->header, | ||
1125 | perf_data_file__fd(session->file), | ||
1126 | tchart, | ||
1127 | process_header); | ||
1128 | |||
1090 | if (!perf_session__has_traces(session, "timechart record")) | 1129 | if (!perf_session__has_traces(session, "timechart record")) |
1091 | goto out_delete; | 1130 | goto out_delete; |
1092 | 1131 | ||
@@ -1212,6 +1251,23 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, | |||
1212 | return 0; | 1251 | return 0; |
1213 | } | 1252 | } |
1214 | 1253 | ||
1254 | static int | ||
1255 | parse_highlight(const struct option *opt __maybe_unused, const char *arg, | ||
1256 | int __maybe_unused unset) | ||
1257 | { | ||
1258 | unsigned long duration = strtoul(arg, NULL, 0); | ||
1259 | |||
1260 | if (svg_highlight || svg_highlight_name) | ||
1261 | return -1; | ||
1262 | |||
1263 | if (duration) | ||
1264 | svg_highlight = duration; | ||
1265 | else | ||
1266 | svg_highlight_name = strdup(arg); | ||
1267 | |||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1215 | int cmd_timechart(int argc, const char **argv, | 1271 | int cmd_timechart(int argc, const char **argv, |
1216 | const char *prefix __maybe_unused) | 1272 | const char *prefix __maybe_unused) |
1217 | { | 1273 | { |
@@ -1230,6 +1286,9 @@ int cmd_timechart(int argc, const char **argv, | |||
1230 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | 1286 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
1231 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | 1287 | OPT_STRING('o', "output", &output_name, "file", "output file name"), |
1232 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), | 1288 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), |
1289 | OPT_CALLBACK(0, "highlight", NULL, "duration or task name", | ||
1290 | "highlight tasks. Pass duration in ns or process name.", | ||
1291 | parse_highlight), | ||
1233 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), | 1292 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), |
1234 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, | 1293 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, |
1235 | "output processes data only"), | 1294 | "output processes data only"), |
@@ -1240,6 +1299,8 @@ int cmd_timechart(int argc, const char **argv, | |||
1240 | "Look for files with symbols relative to this directory"), | 1299 | "Look for files with symbols relative to this directory"), |
1241 | OPT_INTEGER('n', "proc-num", &tchart.proc_num, | 1300 | OPT_INTEGER('n', "proc-num", &tchart.proc_num, |
1242 | "min. number of tasks to print"), | 1301 | "min. number of tasks to print"), |
1302 | OPT_BOOLEAN('t', "topology", &tchart.topology, | ||
1303 | "sort CPUs according to topology"), | ||
1243 | OPT_END() | 1304 | OPT_END() |
1244 | }; | 1305 | }; |
1245 | const char * const timechart_usage[] = { | 1306 | const char * const timechart_usage[] = { |