root/tools/perf/util/svghelper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cpu2slot
  2. cpu2y
  3. time2pixels
  4. round_text_size
  5. open_svg
  6. normalize_height
  7. svg_ubox
  8. svg_lbox
  9. svg_fbox
  10. svg_box
  11. svg_blocked
  12. svg_running
  13. time_to_string
  14. svg_waiting
  15. cpu_model
  16. svg_cpu_box
  17. svg_process
  18. svg_cstate
  19. HzToHuman
  20. svg_pstate
  21. svg_partial_wakeline
  22. svg_wakeline
  23. svg_interrupt
  24. svg_text
  25. svg_legenda_box
  26. svg_io_legenda
  27. svg_legenda
  28. svg_time_grid
  29. svg_close
  30. scan_thread_topology
  31. scan_core_topology
  32. str_to_bitmap
  33. svg_build_topology_map

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

/* [<][>][^][v][top][bottom][index][help] */