Linux Perf
svghelper.c
Go to the documentation of this file.
1 /*
2  * svghelper.c - helper functions for outputting svg
3  *
4  * (C) Copyright 2009 Intel Corporation
5  *
6  * Authors:
7  * Arjan van de Ven <arjan@linux.intel.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; version 2
12  * of the License.
13  */
14 
15 #include <inttypes.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <linux/bitmap.h>
21 #include <linux/time64.h>
22 
23 #include "perf.h"
24 #include "svghelper.h"
25 #include "util.h"
26 #include "cpumap.h"
27 
28 static u64 first_time, last_time;
30 
31 
32 #define SLOT_MULT 30.0
33 #define SLOT_HEIGHT 25.0
34 #define SLOT_HALF (SLOT_HEIGHT / 2)
35 
36 int svg_page_width = 1000;
38 const char *svg_highlight_name;
39 
40 #define MIN_TEXT_SIZE 0.01
41 
42 static u64 total_height;
43 static FILE *svgfile;
44 
45 static double cpu2slot(int cpu)
46 {
47  return 2 * cpu + 1;
48 }
49 
50 static int *topology_map;
51 
52 static double cpu2y(int cpu)
53 {
54  if (topology_map)
55  return cpu2slot(topology_map[cpu]) * SLOT_MULT;
56  else
57  return cpu2slot(cpu) * SLOT_MULT;
58 }
59 
60 static double time2pixels(u64 __time)
61 {
62  double X;
63 
64  X = 1.0 * svg_page_width * (__time - first_time) / (last_time - first_time);
65  return X;
66 }
67 
68 /*
69  * Round text sizes so that the svg viewer only needs a discrete
70  * number of renderings of the font
71  */
72 static double round_text_size(double size)
73 {
74  int loop = 100;
75  double target = 10.0;
76 
77  if (size >= 10.0)
78  return size;
79  while (loop--) {
80  if (size >= target)
81  return target;
82  target = target / 2.0;
83  }
84  return size;
85 }
86 
87 void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
88 {
89  int new_width;
90 
91  svgfile = fopen(filename, "w");
92  if (!svgfile) {
93  fprintf(stderr, "Cannot open %s for output\n", filename);
94  return;
95  }
96  first_time = start;
97  first_time = first_time / 100000000 * 100000000;
98  last_time = end;
99 
100  /*
101  * if the recording is short, we default to a width of 1000, but
102  * for longer recordings we want at least 200 units of width per second
103  */
104  new_width = (last_time - first_time) / 5000000;
105 
106  if (new_width > svg_page_width)
107  svg_page_width = new_width;
108 
109  total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
110  fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
111  fprintf(svgfile, "<!DOCTYPE svg SYSTEM \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
112  fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
113 
114  fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
115 
116  fprintf(svgfile, " rect { stroke-width: 1; }\n");
117  fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
118  fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
119  fprintf(svgfile, " rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
120  fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121  fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
122  fprintf(svgfile, " rect.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
123  fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
124  fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
125  fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
126  fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
127  fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
128  fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
129  fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
130  fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
131  fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
132  fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n");
133  fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n");
134  fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n");
135  fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n");
136  fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n");
137  fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n");
138  fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n");
139 
140  fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
141 }
142 
143 static double normalize_height(double height)
144 {
145  if (height < 0.25)
146  return 0.25;
147  else if (height < 0.50)
148  return 0.50;
149  else if (height < 0.75)
150  return 0.75;
151  else
152  return 0.100;
153 }
154 
155 void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
156 {
157  double w = time2pixels(end) - time2pixels(start);
158  height = normalize_height(height);
159 
160  if (!svgfile)
161  return;
162 
163  fprintf(svgfile, "<g>\n");
164  fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
165  fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
166  time2pixels(start),
167  w,
168  Yslot * SLOT_MULT,
169  SLOT_HALF * height,
170  type);
171  fprintf(svgfile, "</g>\n");
172 }
173 
174 void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
175 {
176  double w = time2pixels(end) - time2pixels(start);
177  height = normalize_height(height);
178 
179  if (!svgfile)
180  return;
181 
182  fprintf(svgfile, "<g>\n");
183  fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
184  fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
185  time2pixels(start),
186  w,
187  Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height,
188  SLOT_HALF * height,
189  type);
190  fprintf(svgfile, "</g>\n");
191 }
192 
193 void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
194 {
195  double w = time2pixels(end) - time2pixels(start);
196  height = normalize_height(height);
197 
198  if (!svgfile)
199  return;
200 
201  fprintf(svgfile, "<g>\n");
202  fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
203  fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
204  time2pixels(start),
205  w,
206  Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height,
207  SLOT_HEIGHT * height,
208  type);
209  fprintf(svgfile, "</g>\n");
210 }
211 
212 void svg_box(int Yslot, u64 start, u64 end, const char *type)
213 {
214  if (!svgfile)
215  return;
216 
217  fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
218  time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
219 }
220 
221 static char *time_to_string(u64 duration);
222 void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
223 {
224  if (!svgfile)
225  return;
226 
227  fprintf(svgfile, "<g>\n");
228  fprintf(svgfile, "<title>#%d blocked %s</title>\n", cpu,
229  time_to_string(end - start));
230  if (backtrace)
231  fprintf(svgfile, "<desc>Blocked on:\n%s</desc>\n", backtrace);
232  svg_box(Yslot, start, end, "blocked");
233  fprintf(svgfile, "</g>\n");
234 }
235 
236 void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
237 {
238  double text_size;
239  const char *type;
240 
241  if (!svgfile)
242  return;
243 
244  if (svg_highlight && end - start > svg_highlight)
245  type = "sample_hi";
246  else
247  type = "sample";
248  fprintf(svgfile, "<g>\n");
249 
250  fprintf(svgfile, "<title>#%d running %s</title>\n",
251  cpu, time_to_string(end - start));
252  if (backtrace)
253  fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
254  fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
255  time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
256  type);
257 
258  text_size = (time2pixels(end)-time2pixels(start));
259  if (cpu > 9)
260  text_size = text_size/2;
261  if (text_size > 1.25)
262  text_size = 1.25;
263  text_size = round_text_size(text_size);
264 
265  if (text_size > MIN_TEXT_SIZE)
266  fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n",
267  time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
268 
269  fprintf(svgfile, "</g>\n");
270 }
271 
272 static char *time_to_string(u64 duration)
273 {
274  static char text[80];
275 
276  text[0] = 0;
277 
278  if (duration < NSEC_PER_USEC) /* less than 1 usec */
279  return text;
280 
281  if (duration < NSEC_PER_MSEC) { /* less than 1 msec */
282  sprintf(text, "%.1f us", duration / (double)NSEC_PER_USEC);
283  return text;
284  }
285  sprintf(text, "%.1f ms", duration / (double)NSEC_PER_MSEC);
286 
287  return text;
288 }
289 
290 void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
291 {
292  char *text;
293  const char *style;
294  double font_size;
295 
296  if (!svgfile)
297  return;
298 
299  style = "waiting";
300 
301  if (end-start > 10 * NSEC_PER_MSEC) /* 10 msec */
302  style = "WAITING";
303 
304  text = time_to_string(end-start);
305 
306  font_size = 1.0 * (time2pixels(end)-time2pixels(start));
307 
308  if (font_size > 3)
309  font_size = 3;
310 
311  font_size = round_text_size(font_size);
312 
313  fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
314  fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
315  if (backtrace)
316  fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
317  fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
318  time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
319  if (font_size > MIN_TEXT_SIZE)
320  fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n",
321  font_size, text);
322  fprintf(svgfile, "</g>\n");
323 }
324 
325 static char *cpu_model(void)
326 {
327  static char cpu_m[255];
328  char buf[256];
329  FILE *file;
330 
331  cpu_m[0] = 0;
332  /* CPU type */
333  file = fopen("/proc/cpuinfo", "r");
334  if (file) {
335  while (fgets(buf, 255, file)) {
336  if (strstr(buf, "model name")) {
337  strncpy(cpu_m, &buf[13], 255);
338  break;
339  }
340  }
341  fclose(file);
342  }
343 
344  /* CPU type */
345  file = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", "r");
346  if (file) {
347  while (fgets(buf, 255, file)) {
348  unsigned int freq;
349  freq = strtoull(buf, NULL, 10);
350  if (freq > max_freq)
351  max_freq = freq;
352  }
353  fclose(file);
354  }
355  return cpu_m;
356 }
357 
358 void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
359 {
360  char cpu_string[80];
361  if (!svgfile)
362  return;
363 
364  max_freq = __max_freq;
365  turbo_frequency = __turbo_freq;
366 
367  fprintf(svgfile, "<g>\n");
368 
369  fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n",
372  cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
373 
374  sprintf(cpu_string, "CPU %i", (int)cpu);
375  fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
376  10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
377 
378  fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n",
380 
381  fprintf(svgfile, "</g>\n");
382 }
383 
384 void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace)
385 {
386  double width;
387  const char *type;
388 
389  if (!svgfile)
390  return;
391 
392  if (svg_highlight && end - start >= svg_highlight)
393  type = "sample_hi";
394  else if (svg_highlight_name && strstr(name, svg_highlight_name))
395  type = "sample_hi";
396  else
397  type = "sample";
398 
399  fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu));
400  fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
401  if (backtrace)
402  fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
403  fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
404  time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
405  width = time2pixels(end)-time2pixels(start);
406  if (width > 6)
407  width = 6;
408 
409  width = round_text_size(width);
410 
411  if (width > MIN_TEXT_SIZE)
412  fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n",
413  width, name);
414 
415  fprintf(svgfile, "</g>\n");
416 }
417 
418 void svg_cstate(int cpu, u64 start, u64 end, int type)
419 {
420  double width;
421  char style[128];
422 
423  if (!svgfile)
424  return;
425 
426 
427  fprintf(svgfile, "<g>\n");
428 
429  if (type > 6)
430  type = 6;
431  sprintf(style, "c%i", type);
432 
433  fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n",
434  style,
435  time2pixels(start), time2pixels(end)-time2pixels(start),
436  cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
437 
438  width = (time2pixels(end)-time2pixels(start))/2.0;
439  if (width > 6)
440  width = 6;
441 
442  width = round_text_size(width);
443 
444  if (width > MIN_TEXT_SIZE)
445  fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n",
446  time2pixels(start), cpu2y(cpu)+width, width, type);
447 
448  fprintf(svgfile, "</g>\n");
449 }
450 
451 static char *HzToHuman(unsigned long hz)
452 {
453  static char buffer[1024];
454  unsigned long long Hz;
455 
456  memset(buffer, 0, 1024);
457 
458  Hz = hz;
459 
460  /* default: just put the Number in */
461  sprintf(buffer, "%9lli", Hz);
462 
463  if (Hz > 1000)
464  sprintf(buffer, " %6lli Mhz", (Hz+500)/1000);
465 
466  if (Hz > 1500000)
467  sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000);
468 
469  if (Hz == turbo_frequency)
470  sprintf(buffer, "Turbo");
471 
472  return buffer;
473 }
474 
475 void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
476 {
477  double height = 0;
478 
479  if (!svgfile)
480  return;
481 
482  fprintf(svgfile, "<g>\n");
483 
484  if (max_freq)
485  height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
486  height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
487  fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n",
488  time2pixels(start), time2pixels(end), height, height);
489  fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n",
490  time2pixels(start), height+0.9, HzToHuman(freq));
491 
492  fprintf(svgfile, "</g>\n");
493 }
494 
495 
496 void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace)
497 {
498  double height;
499 
500  if (!svgfile)
501  return;
502 
503 
504  fprintf(svgfile, "<g>\n");
505 
506  fprintf(svgfile, "<title>%s wakes up %s</title>\n",
507  desc1 ? desc1 : "?",
508  desc2 ? desc2 : "?");
509 
510  if (backtrace)
511  fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
512 
513  if (row1 < row2) {
514  if (row1) {
515  fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
516  time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
517  if (desc2)
518  fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
519  time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
520  }
521  if (row2) {
522  fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
523  time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
524  if (desc1)
525  fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
526  time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
527  }
528  } else {
529  if (row2) {
530  fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
531  time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
532  if (desc1)
533  fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
534  time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
535  }
536  if (row1) {
537  fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
538  time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
539  if (desc2)
540  fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
541  time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
542  }
543  }
544  height = row1 * SLOT_MULT;
545  if (row2 > row1)
546  height += SLOT_HEIGHT;
547  if (row1)
548  fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
549  time2pixels(start), height);
550 
551  fprintf(svgfile, "</g>\n");
552 }
553 
554 void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
555 {
556  double height;
557 
558  if (!svgfile)
559  return;
560 
561 
562  fprintf(svgfile, "<g>\n");
563 
564  if (backtrace)
565  fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
566 
567  if (row1 < row2)
568  fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
569  time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
570  else
571  fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
572  time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
573 
574  height = row1 * SLOT_MULT;
575  if (row2 > row1)
576  height += SLOT_HEIGHT;
577  fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
578  time2pixels(start), height);
579 
580  fprintf(svgfile, "</g>\n");
581 }
582 
583 void svg_interrupt(u64 start, int row, const char *backtrace)
584 {
585  if (!svgfile)
586  return;
587 
588  fprintf(svgfile, "<g>\n");
589 
590  fprintf(svgfile, "<title>Wakeup from interrupt</title>\n");
591 
592  if (backtrace)
593  fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
594 
595  fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
596  time2pixels(start), row * SLOT_MULT);
597  fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
598  time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
599 
600  fprintf(svgfile, "</g>\n");
601 }
602 
603 void svg_text(int Yslot, u64 start, const char *text)
604 {
605  if (!svgfile)
606  return;
607 
608  fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
609  time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
610 }
611 
612 static void svg_legenda_box(int X, const char *text, const char *style)
613 {
614  double boxsize;
615  boxsize = SLOT_HEIGHT / 2;
616 
617  fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
618  X, boxsize, boxsize, style);
619  fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n",
620  X + boxsize + 5, boxsize, 0.8 * boxsize, text);
621 }
622 
623 void svg_io_legenda(void)
624 {
625  if (!svgfile)
626  return;
627 
628  fprintf(svgfile, "<g>\n");
629  svg_legenda_box(0, "Disk", "disk");
630  svg_legenda_box(100, "Network", "net");
631  svg_legenda_box(200, "Sync", "sync");
632  svg_legenda_box(300, "Poll", "poll");
633  svg_legenda_box(400, "Error", "error");
634  fprintf(svgfile, "</g>\n");
635 }
636 
637 void svg_legenda(void)
638 {
639  if (!svgfile)
640  return;
641 
642  fprintf(svgfile, "<g>\n");
643  svg_legenda_box(0, "Running", "sample");
644  svg_legenda_box(100, "Idle","c1");
645  svg_legenda_box(200, "Deeper Idle", "c3");
646  svg_legenda_box(350, "Deepest Idle", "c6");
647  svg_legenda_box(550, "Sleeping", "process2");
648  svg_legenda_box(650, "Waiting for cpu", "waiting");
649  svg_legenda_box(800, "Blocked on IO", "blocked");
650  fprintf(svgfile, "</g>\n");
651 }
652 
653 void svg_time_grid(double min_thickness)
654 {
655  u64 i;
656 
657  if (!svgfile)
658  return;
659 
660  i = first_time;
661  while (i < last_time) {
662  int color = 220;
663  double thickness = 0.075;
664  if ((i % 100000000) == 0) {
665  thickness = 0.5;
666  color = 192;
667  }
668  if ((i % 1000000000) == 0) {
669  thickness = 2.0;
670  color = 128;
671  }
672 
673  if (thickness >= min_thickness)
674  fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n",
676  total_height, color, color, color, thickness);
677 
678  i += 10000000;
679  }
680 }
681 
682 void svg_close(void)
683 {
684  if (svgfile) {
685  fprintf(svgfile, "</svg>\n");
686  fclose(svgfile);
687  svgfile = NULL;
688  }
689 }
690 
691 #define cpumask_bits(maskp) ((maskp)->bits)
692 typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;
693 
694 struct topology {
699 };
700 
701 static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos)
702 {
703  int i;
704  int thr;
705 
706  for (i = 0; i < t->sib_thr_nr; i++) {
707  if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i])))
708  continue;
709 
710  for_each_set_bit(thr,
711  cpumask_bits(&t->sib_thr[i]),
712  MAX_NR_CPUS)
713  if (map[thr] == -1)
714  map[thr] = (*pos)++;
715  }
716 }
717 
718 static void scan_core_topology(int *map, struct topology *t)
719 {
720  int pos = 0;
721  int i;
722  int cpu;
723 
724  for (i = 0; i < t->sib_core_nr; i++)
725  for_each_set_bit(cpu,
726  cpumask_bits(&t->sib_core[i]),
727  MAX_NR_CPUS)
728  scan_thread_topology(map, t, cpu, &pos);
729 }
730 
731 static int str_to_bitmap(char *s, cpumask_t *b)
732 {
733  int i;
734  int ret = 0;
735  struct cpu_map *m;
736  int c;
737 
738  m = cpu_map__new(s);
739  if (!m)
740  return -1;
741 
742  for (i = 0; i < m->nr; i++) {
743  c = m->map[i];
744  if (c >= MAX_NR_CPUS) {
745  ret = -1;
746  break;
747  }
748 
749  set_bit(c, cpumask_bits(b));
750  }
751 
752  cpu_map__put(m);
753 
754  return ret;
755 }
756 
757 int svg_build_topology_map(char *sib_core, int sib_core_nr,
758  char *sib_thr, int sib_thr_nr)
759 {
760  int i;
761  struct topology t;
762 
765  t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t));
766  t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t));
767 
768  if (!t.sib_core || !t.sib_thr) {
769  fprintf(stderr, "topology: no memory\n");
770  goto exit;
771  }
772 
773  for (i = 0; i < sib_core_nr; i++) {
774  if (str_to_bitmap(sib_core, &t.sib_core[i])) {
775  fprintf(stderr, "topology: can't parse siblings map\n");
776  goto exit;
777  }
778 
779  sib_core += strlen(sib_core) + 1;
780  }
781 
782  for (i = 0; i < sib_thr_nr; i++) {
783  if (str_to_bitmap(sib_thr, &t.sib_thr[i])) {
784  fprintf(stderr, "topology: can't parse siblings map\n");
785  goto exit;
786  }
787 
788  sib_thr += strlen(sib_thr) + 1;
789  }
790 
791  topology_map = malloc(sizeof(int) * MAX_NR_CPUS);
792  if (!topology_map) {
793  fprintf(stderr, "topology: no memory\n");
794  goto exit;
795  }
796 
797  for (i = 0; i < MAX_NR_CPUS; i++)
798  topology_map[i] = -1;
799 
801 
802  return 0;
803 
804 exit:
805  zfree(&t.sib_core);
806  zfree(&t.sib_thr);
807 
808  return -1;
809 }
void svg_time_grid(double min_thickness)
Definition: svghelper.c:653
int nr
Definition: cpumap.h:14
void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
Definition: svghelper.c:358
void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
Definition: svghelper.c:290
void svg_box(int Yslot, u64 start, u64 end, const char *type)
Definition: svghelper.c:212
#define cpumask_bits(maskp)
Definition: svghelper.c:691
void svg_text(int Yslot, u64 start, const char *text)
Definition: svghelper.c:603
size_t size
Definition: evsel.c:60
const char * filename
Definition: hists_common.c:26
void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
Definition: svghelper.c:554
int int err
Definition: 5sec.c:44
void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
Definition: svghelper.c:193
int svg_page_width
Definition: svghelper.c:36
static char * HzToHuman(unsigned long hz)
Definition: svghelper.c:451
u64 svg_highlight
Definition: svghelper.c:37
static double round_text_size(double size)
Definition: svghelper.c:72
cpumask_t * sib_core
Definition: svghelper.c:695
Definition: cpumap.h:12
static u64 max_freq
Definition: svghelper.c:29
static double time2pixels(u64 __time)
Definition: svghelper.c:60
x86 movsq based memset() in arch/x86/lib/memset_64.S") MEMSET_FN(memset_erms
void svg_cstate(int cpu, u64 start, u64 end, int type)
Definition: svghelper.c:418
static char * time_to_string(u64 duration)
Definition: svghelper.c:272
void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
Definition: svghelper.c:475
void * malloc(YYSIZE_T)
void cpu_map__put(struct cpu_map *map)
Definition: cpumap.c:298
void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
Definition: svghelper.c:87
const char * name
#define SLOT_HALF
Definition: svghelper.c:34
int sib_thr_nr
Definition: svghelper.c:698
void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace)
Definition: svghelper.c:496
#define SLOT_MULT
Definition: svghelper.c:32
static FILE * svgfile
Definition: svghelper.c:43
static double cpu2y(int cpu)
Definition: svghelper.c:52
void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
Definition: svghelper.c:174
void svg_interrupt(u64 start, int row, const char *backtrace)
Definition: svghelper.c:583
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS)
static u64 total_height
Definition: svghelper.c:42
void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
Definition: svghelper.c:222
cpumask_t * sib_thr
Definition: svghelper.c:697
void svg_io_legenda(void)
Definition: svghelper.c:623
const char * svg_highlight_name
Definition: svghelper.c:38
list cpus
Definition: stat-cpi.py:7
int svg_build_topology_map(char *sib_core, int sib_core_nr, char *sib_thr, int sib_thr_nr)
Definition: svghelper.c:757
int sib_core_nr
Definition: svghelper.c:696
static double cpu2slot(int cpu)
Definition: svghelper.c:45
int map[]
Definition: cpumap.h:15
void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
Definition: svghelper.c:236
#define zfree(ptr)
Definition: util.h:25
u32 pid
Definition: hists_common.c:15
void svg_legenda(void)
Definition: svghelper.c:637
u64 start
Definition: hists_common.c:25
static int * topology_map
Definition: svghelper.c:50
static double normalize_height(double height)
Definition: svghelper.c:143
Definition: jevents.c:228
void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
Definition: svghelper.c:155
static u64 first_time
Definition: svghelper.c:28
void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace)
Definition: svghelper.c:384
#define MIN_TEXT_SIZE
Definition: svghelper.c:40
#define SLOT_HEIGHT
Definition: svghelper.c:33
static u64 last_time
Definition: svghelper.c:28
static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos)
Definition: svghelper.c:701
static u64 turbo_frequency
Definition: svghelper.c:29
static int str_to_bitmap(char *s, cpumask_t *b)
Definition: svghelper.c:731
static char * cpu_model(void)
Definition: svghelper.c:325
#define MAX_NR_CPUS
Definition: perf.h:27
static void svg_legenda_box(int X, const char *text, const char *style)
Definition: svghelper.c:612
static void scan_core_topology(int *map, struct topology *t)
Definition: svghelper.c:718
struct cpu_map * cpu_map__new(const char *cpu_list)
Definition: cpumap.c:125
void svg_close(void)
Definition: svghelper.c:682
Definition: target.h:8
char * target
Definition: builtin-probe.c:59