]> Pileus Git - ~andy/linux/blobdiff - tools/perf/builtin-timechart.c
perf annotate: Check availability of annotate when processing samples
[~andy/linux] / tools / perf / builtin-timechart.c
index 8ee0ff1777a8145542236d5ae6e16d4358c2801b..25526d6eae59f65a4a0405c9186d93b9cd5d3d59 100644 (file)
 
 struct per_pid;
 struct power_event;
+struct wake_event;
 
 struct timechart {
        struct perf_tool        tool;
        struct per_pid          *all_data;
        struct power_event      *power_events;
+       struct wake_event       *wake_events;
        int                     proc_num;
        unsigned int            numcpus;
        u64                     min_freq,       /* Lowest CPU frequency seen */
@@ -56,7 +58,8 @@ struct timechart {
                                first_time, last_time;
        bool                    power_only,
                                tasks_only,
-                               with_backtrace;
+                               with_backtrace,
+                               topology;
 };
 
 struct per_pidcomm;
@@ -148,8 +151,6 @@ struct wake_event {
        const char *backtrace;
 };
 
-static struct wake_event     *wake_events;
-
 struct process_filter {
        char                    *name;
        int                     pid;
@@ -383,8 +384,8 @@ static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp,
                we->waker = -1;
 
        we->wakee = wakee;
-       we->next = wake_events;
-       wake_events = we;
+       we->next = tchart->wake_events;
+       tchart->wake_events = we;
        p = find_create_pid(tchart, we->wakee);
 
        if (p && p->current && p->current->state == TYPE_NONE) {
@@ -487,8 +488,7 @@ static const char *cat_backtrace(union perf_event *event,
                                 * It seems the callchain is corrupted.
                                 * Discard all.
                                 */
-                               free(p);
-                               p = NULL;
+                               zfree(&p);
                                goto exit;
                        }
                        continue;
@@ -531,12 +531,10 @@ static int process_sample_event(struct perf_tool *tool,
                        tchart->last_time = sample->time;
        }
 
-       if (sample->cpu > tchart->numcpus)
-               tchart->numcpus = sample->cpu;
-
        if (evsel->handler != NULL) {
                tracepoint_handler f = evsel->handler;
-               return f(tchart, evsel, sample, cat_backtrace(event, sample, machine));
+               return f(tchart, evsel, sample,
+                        cat_backtrace(event, sample, machine));
        }
 
        return 0;
@@ -764,7 +762,7 @@ static void draw_wakeups(struct timechart *tchart)
        struct per_pid *p;
        struct per_pidcomm *c;
 
-       we = wake_events;
+       we = tchart->wake_events;
        while (we) {
                int from = 0, to = 0;
                char *task_from = NULL, *task_to = NULL;
@@ -837,8 +835,14 @@ static void draw_cpu_usage(struct timechart *tchart)
                while (c) {
                        sample = c->samples;
                        while (sample) {
-                               if (sample->type == TYPE_RUNNING)
-                                       svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm);
+                               if (sample->type == TYPE_RUNNING) {
+                                       svg_process(sample->cpu,
+                                                   sample->start_time,
+                                                   sample->end_time,
+                                                   p->pid,
+                                                   c->comm,
+                                                   sample->backtrace);
+                               }
 
                                sample = sample->next;
                        }
@@ -1031,8 +1035,6 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
        int count;
        int thresh = TIME_THRESH;
 
-       tchart->numcpus++;
-
        if (tchart->power_only)
                tchart->proc_num = 0;
 
@@ -1043,6 +1045,9 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
                thresh /= 10;
        } while (!process_filter && thresh && count < tchart->proc_num);
 
+       if (!tchart->proc_num)
+               count = 0;
+
        open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
 
        svg_time_grid();
@@ -1062,6 +1067,37 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
        svg_close();
 }
 
+static int process_header(struct perf_file_section *section __maybe_unused,
+                         struct perf_header *ph,
+                         int feat,
+                         int fd __maybe_unused,
+                         void *data)
+{
+       struct timechart *tchart = data;
+
+       switch (feat) {
+       case HEADER_NRCPUS:
+               tchart->numcpus = ph->env.nr_cpus_avail;
+               break;
+
+       case HEADER_CPU_TOPOLOGY:
+               if (!tchart->topology)
+                       break;
+
+               if (svg_build_topology_map(ph->env.sibling_cores,
+                                          ph->env.nr_sibling_cores,
+                                          ph->env.sibling_threads,
+                                          ph->env.nr_sibling_threads))
+                       fprintf(stderr, "problem building topology\n");
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static int __cmd_timechart(struct timechart *tchart, const char *output_name)
 {
        const struct perf_evsel_str_handler power_tracepoints[] = {
@@ -1087,6 +1123,11 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
        if (session == NULL)
                return -ENOMEM;
 
+       (void)perf_header__process_sections(&session->header,
+                                           perf_data_file__fd(session->file),
+                                           tchart,
+                                           process_header);
+
        if (!perf_session__has_traces(session, "timechart record"))
                goto out_delete;
 
@@ -1212,6 +1253,23 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
        return 0;
 }
 
+static int
+parse_highlight(const struct option *opt __maybe_unused, const char *arg,
+               int __maybe_unused unset)
+{
+       unsigned long duration = strtoul(arg, NULL, 0);
+
+       if (svg_highlight || svg_highlight_name)
+               return -1;
+
+       if (duration)
+               svg_highlight = duration;
+       else
+               svg_highlight_name = strdup(arg);
+
+       return 0;
+}
+
 int cmd_timechart(int argc, const char **argv,
                  const char *prefix __maybe_unused)
 {
@@ -1230,6 +1288,9 @@ int cmd_timechart(int argc, const char **argv,
        OPT_STRING('i', "input", &input_name, "file", "input file name"),
        OPT_STRING('o', "output", &output_name, "file", "output file name"),
        OPT_INTEGER('w', "width", &svg_page_width, "page width"),
+       OPT_CALLBACK(0, "highlight", NULL, "duration or task name",
+                     "highlight tasks. Pass duration in ns or process name.",
+                      parse_highlight),
        OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
        OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
                    "output processes data only"),
@@ -1240,6 +1301,8 @@ int cmd_timechart(int argc, const char **argv,
                    "Look for files with symbols relative to this directory"),
        OPT_INTEGER('n', "proc-num", &tchart.proc_num,
                    "min. number of tasks to print"),
+       OPT_BOOLEAN('t', "topology", &tchart.topology,
+                   "sort CPUs according to topology"),
        OPT_END()
        };
        const char * const timechart_usage[] = {