]> Git Repo - linux.git/blobdiff - tools/perf/util/svghelper.c
perf tools: Use zfree to help detect use after free bugs
[linux.git] / tools / perf / util / svghelper.c
index 8b79d3ad124629e44184b8d20474592f9346a44b..43262b83c5411894f3dff3244782b6bd8bfe580d 100644 (file)
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <linux/bitops.h>
 
+#include "perf.h"
 #include "svghelper.h"
+#include "util.h"
+#include "cpumap.h"
 
 static u64 first_time, last_time;
 static u64 turbo_frequency, max_freq;
@@ -28,6 +32,8 @@ static u64 turbo_frequency, max_freq;
 #define SLOT_HEIGHT 25.0
 
 int svg_page_width = 1000;
+u64 svg_highlight;
+const char *svg_highlight_name;
 
 #define MIN_TEXT_SIZE 0.01
 
@@ -39,9 +45,14 @@ static double cpu2slot(int cpu)
        return 2 * cpu + 1;
 }
 
+static int *topology_map;
+
 static double cpu2y(int cpu)
 {
-       return cpu2slot(cpu) * SLOT_MULT;
+       if (topology_map)
+               return cpu2slot(topology_map[cpu]) * SLOT_MULT;
+       else
+               return cpu2slot(cpu) * SLOT_MULT;
 }
 
 static double time2pixels(u64 __time)
@@ -104,6 +115,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
        fprintf(svgfile, "      rect.process  { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1;   stroke:rgb(  0,  0,  0); } \n");
        fprintf(svgfile, "      rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
        fprintf(svgfile, "      rect.sample   { fill:rgb(  0,  0,255); fill-opacity:0.8; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
+       fprintf(svgfile, "      rect.sample_hi{ fill:rgb(255,128,  0); fill-opacity:0.8; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
        fprintf(svgfile, "      rect.blocked  { fill:rgb(255,  0,  0); fill-opacity:0.5; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
        fprintf(svgfile, "      rect.waiting  { fill:rgb(224,214,  0); fill-opacity:0.8; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
        fprintf(svgfile, "      rect.WAITING  { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0;   stroke:rgb(  0,  0,  0); } \n");
@@ -147,17 +159,24 @@ void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
 void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
 {
        double text_size;
+       const char *type;
+
        if (!svgfile)
                return;
 
+       if (svg_highlight && end - start > svg_highlight)
+               type = "sample_hi";
+       else
+               type = "sample";
        fprintf(svgfile, "<g>\n");
 
        fprintf(svgfile, "<title>#%d running %s</title>\n",
                cpu, time_to_string(end - start));
        if (backtrace)
                fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
-       fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n",
-               time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT);
+       fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
+               time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
+               type);
 
        text_size = (time2pixels(end)-time2pixels(start));
        if (cpu > 9)
@@ -275,7 +294,7 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
                time2pixels(last_time)-time2pixels(first_time),
                cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
 
-       sprintf(cpu_string, "CPU %i", (int)cpu+1);
+       sprintf(cpu_string, "CPU %i", (int)cpu);
        fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
                10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
 
@@ -285,16 +304,25 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
        fprintf(svgfile, "</g>\n");
 }
 
-void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name)
+void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace)
 {
        double width;
+       const char *type;
 
        if (!svgfile)
                return;
 
+       if (svg_highlight && end - start >= svg_highlight)
+               type = "sample_hi";
+       else if (svg_highlight_name && strstr(name, svg_highlight_name))
+               type = "sample_hi";
+       else
+               type = "sample";
 
        fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
-       fprintf(svgfile, "<title>%s %s</title>\n", name, time_to_string(end - start));
+       fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
+       if (backtrace)
+               fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
        fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
                time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
        width = time2pixels(end)-time2pixels(start);
@@ -566,3 +594,123 @@ void svg_close(void)
                svgfile = NULL;
        }
 }
+
+#define cpumask_bits(maskp) ((maskp)->bits)
+typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;
+
+struct topology {
+       cpumask_t *sib_core;
+       int sib_core_nr;
+       cpumask_t *sib_thr;
+       int sib_thr_nr;
+};
+
+static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos)
+{
+       int i;
+       int thr;
+
+       for (i = 0; i < t->sib_thr_nr; i++) {
+               if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i])))
+                       continue;
+
+               for_each_set_bit(thr,
+                                cpumask_bits(&t->sib_thr[i]),
+                                MAX_NR_CPUS)
+                       if (map[thr] == -1)
+                               map[thr] = (*pos)++;
+       }
+}
+
+static void scan_core_topology(int *map, struct topology *t)
+{
+       int pos = 0;
+       int i;
+       int cpu;
+
+       for (i = 0; i < t->sib_core_nr; i++)
+               for_each_set_bit(cpu,
+                                cpumask_bits(&t->sib_core[i]),
+                                MAX_NR_CPUS)
+                       scan_thread_topology(map, t, cpu, &pos);
+}
+
+static int str_to_bitmap(char *s, cpumask_t *b)
+{
+       int i;
+       int ret = 0;
+       struct cpu_map *m;
+       int c;
+
+       m = cpu_map__new(s);
+       if (!m)
+               return -1;
+
+       for (i = 0; i < m->nr; i++) {
+               c = m->map[i];
+               if (c >= MAX_NR_CPUS) {
+                       ret = -1;
+                       break;
+               }
+
+               set_bit(c, cpumask_bits(b));
+       }
+
+       cpu_map__delete(m);
+
+       return ret;
+}
+
+int svg_build_topology_map(char *sib_core, int sib_core_nr,
+                          char *sib_thr, int sib_thr_nr)
+{
+       int i;
+       struct topology t;
+
+       t.sib_core_nr = sib_core_nr;
+       t.sib_thr_nr = sib_thr_nr;
+       t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t));
+       t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t));
+
+       if (!t.sib_core || !t.sib_thr) {
+               fprintf(stderr, "topology: no memory\n");
+               goto exit;
+       }
+
+       for (i = 0; i < sib_core_nr; i++) {
+               if (str_to_bitmap(sib_core, &t.sib_core[i])) {
+                       fprintf(stderr, "topology: can't parse siblings map\n");
+                       goto exit;
+               }
+
+               sib_core += strlen(sib_core) + 1;
+       }
+
+       for (i = 0; i < sib_thr_nr; i++) {
+               if (str_to_bitmap(sib_thr, &t.sib_thr[i])) {
+                       fprintf(stderr, "topology: can't parse siblings map\n");
+                       goto exit;
+               }
+
+               sib_thr += strlen(sib_thr) + 1;
+       }
+
+       topology_map = malloc(sizeof(int) * MAX_NR_CPUS);
+       if (!topology_map) {
+               fprintf(stderr, "topology: no memory\n");
+               goto exit;
+       }
+
+       for (i = 0; i < MAX_NR_CPUS; i++)
+               topology_map[i] = -1;
+
+       scan_core_topology(topology_map, &t);
+
+       return 0;
+
+exit:
+       zfree(&t.sib_core);
+       zfree(&t.sib_thr);
+
+       return -1;
+}
This page took 0.037664 seconds and 4 git commands to generate.