0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <inttypes.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <unistd.h>
0015 #include <string.h>
0016 #include <linux/bitmap.h>
0017 #include <linux/string.h>
0018 #include <linux/time64.h>
0019 #include <linux/zalloc.h>
0020 #include <internal/cpumap.h>
0021 #include <perf/cpumap.h>
0022
0023 #include "env.h"
0024 #include "svghelper.h"
0025
0026 static u64 first_time, last_time;
0027 static u64 turbo_frequency, max_freq;
0028
0029
0030 #define SLOT_MULT 30.0
0031 #define SLOT_HEIGHT 25.0
0032 #define SLOT_HALF (SLOT_HEIGHT / 2)
0033
0034 int svg_page_width = 1000;
0035 u64 svg_highlight;
0036 const char *svg_highlight_name;
0037
0038 #define MIN_TEXT_SIZE 0.01
0039
0040 static u64 total_height;
0041 static FILE *svgfile;
0042
0043 static double cpu2slot(int cpu)
0044 {
0045 return 2 * cpu + 1;
0046 }
0047
0048 static int *topology_map;
0049
0050 static double cpu2y(int cpu)
0051 {
0052 if (topology_map)
0053 return cpu2slot(topology_map[cpu]) * SLOT_MULT;
0054 else
0055 return cpu2slot(cpu) * SLOT_MULT;
0056 }
0057
0058 static double time2pixels(u64 __time)
0059 {
0060 double X;
0061
0062 X = 1.0 * svg_page_width * (__time - first_time) / (last_time - first_time);
0063 return X;
0064 }
0065
0066
0067
0068
0069
0070 static double round_text_size(double size)
0071 {
0072 int loop = 100;
0073 double target = 10.0;
0074
0075 if (size >= 10.0)
0076 return size;
0077 while (loop--) {
0078 if (size >= target)
0079 return target;
0080 target = target / 2.0;
0081 }
0082 return size;
0083 }
0084
0085 void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
0086 {
0087 int new_width;
0088
0089 svgfile = fopen(filename, "w");
0090 if (!svgfile) {
0091 fprintf(stderr, "Cannot open %s for output\n", filename);
0092 return;
0093 }
0094 first_time = start;
0095 first_time = first_time / 100000000 * 100000000;
0096 last_time = end;
0097
0098
0099
0100
0101
0102 new_width = (last_time - first_time) / 5000000;
0103
0104 if (new_width > svg_page_width)
0105 svg_page_width = new_width;
0106
0107 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
0108 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
0109 fprintf(svgfile, "<!DOCTYPE svg SYSTEM \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
0110 fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
0111
0112 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
0113
0114 fprintf(svgfile, " rect { stroke-width: 1; }\n");
0115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
0116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0117 fprintf(svgfile, " rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0118 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0119 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0120 fprintf(svgfile, " rect.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0121 fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0122 fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0123 fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0124 fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0125 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0126 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0127 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
0128 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
0129 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
0130 fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n");
0131 fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n");
0132 fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n");
0133 fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n");
0134 fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n");
0135 fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n");
0136 fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n");
0137
0138 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
0139 }
0140
0141 static double normalize_height(double height)
0142 {
0143 if (height < 0.25)
0144 return 0.25;
0145 else if (height < 0.50)
0146 return 0.50;
0147 else if (height < 0.75)
0148 return 0.75;
0149 else
0150 return 0.100;
0151 }
0152
0153 void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
0154 {
0155 double w = time2pixels(end) - time2pixels(start);
0156 height = normalize_height(height);
0157
0158 if (!svgfile)
0159 return;
0160
0161 fprintf(svgfile, "<g>\n");
0162 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
0163 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
0164 time2pixels(start),
0165 w,
0166 Yslot * SLOT_MULT,
0167 SLOT_HALF * height,
0168 type);
0169 fprintf(svgfile, "</g>\n");
0170 }
0171
0172 void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
0173 {
0174 double w = time2pixels(end) - time2pixels(start);
0175 height = normalize_height(height);
0176
0177 if (!svgfile)
0178 return;
0179
0180 fprintf(svgfile, "<g>\n");
0181 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
0182 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
0183 time2pixels(start),
0184 w,
0185 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height,
0186 SLOT_HALF * height,
0187 type);
0188 fprintf(svgfile, "</g>\n");
0189 }
0190
0191 void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
0192 {
0193 double w = time2pixels(end) - time2pixels(start);
0194 height = normalize_height(height);
0195
0196 if (!svgfile)
0197 return;
0198
0199 fprintf(svgfile, "<g>\n");
0200 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
0201 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
0202 time2pixels(start),
0203 w,
0204 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height,
0205 SLOT_HEIGHT * height,
0206 type);
0207 fprintf(svgfile, "</g>\n");
0208 }
0209
0210 void svg_box(int Yslot, u64 start, u64 end, const char *type)
0211 {
0212 if (!svgfile)
0213 return;
0214
0215 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
0216 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
0217 }
0218
0219 static char *time_to_string(u64 duration);
0220 void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
0221 {
0222 if (!svgfile)
0223 return;
0224
0225 fprintf(svgfile, "<g>\n");
0226 fprintf(svgfile, "<title>#%d blocked %s</title>\n", cpu,
0227 time_to_string(end - start));
0228 if (backtrace)
0229 fprintf(svgfile, "<desc>Blocked on:\n%s</desc>\n", backtrace);
0230 svg_box(Yslot, start, end, "blocked");
0231 fprintf(svgfile, "</g>\n");
0232 }
0233
0234 void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
0235 {
0236 double text_size;
0237 const char *type;
0238
0239 if (!svgfile)
0240 return;
0241
0242 if (svg_highlight && end - start > svg_highlight)
0243 type = "sample_hi";
0244 else
0245 type = "sample";
0246 fprintf(svgfile, "<g>\n");
0247
0248 fprintf(svgfile, "<title>#%d running %s</title>\n",
0249 cpu, time_to_string(end - start));
0250 if (backtrace)
0251 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
0252 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
0253 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
0254 type);
0255
0256 text_size = (time2pixels(end)-time2pixels(start));
0257 if (cpu > 9)
0258 text_size = text_size/2;
0259 if (text_size > 1.25)
0260 text_size = 1.25;
0261 text_size = round_text_size(text_size);
0262
0263 if (text_size > MIN_TEXT_SIZE)
0264 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n",
0265 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
0266
0267 fprintf(svgfile, "</g>\n");
0268 }
0269
0270 static char *time_to_string(u64 duration)
0271 {
0272 static char text[80];
0273
0274 text[0] = 0;
0275
0276 if (duration < NSEC_PER_USEC)
0277 return text;
0278
0279 if (duration < NSEC_PER_MSEC) {
0280 sprintf(text, "%.1f us", duration / (double)NSEC_PER_USEC);
0281 return text;
0282 }
0283 sprintf(text, "%.1f ms", duration / (double)NSEC_PER_MSEC);
0284
0285 return text;
0286 }
0287
0288 void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
0289 {
0290 char *text;
0291 const char *style;
0292 double font_size;
0293
0294 if (!svgfile)
0295 return;
0296
0297 style = "waiting";
0298
0299 if (end-start > 10 * NSEC_PER_MSEC)
0300 style = "WAITING";
0301
0302 text = time_to_string(end-start);
0303
0304 font_size = 1.0 * (time2pixels(end)-time2pixels(start));
0305
0306 if (font_size > 3)
0307 font_size = 3;
0308
0309 font_size = round_text_size(font_size);
0310
0311 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
0312 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
0313 if (backtrace)
0314 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
0315 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
0316 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
0317 if (font_size > MIN_TEXT_SIZE)
0318 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n",
0319 font_size, text);
0320 fprintf(svgfile, "</g>\n");
0321 }
0322
0323 static char *cpu_model(void)
0324 {
0325 static char cpu_m[255];
0326 char buf[256];
0327 FILE *file;
0328
0329 cpu_m[0] = 0;
0330
0331 file = fopen("/proc/cpuinfo", "r");
0332 if (file) {
0333 while (fgets(buf, 255, file)) {
0334 if (strstr(buf, "model name")) {
0335 strlcpy(cpu_m, &buf[13], 255);
0336 break;
0337 }
0338 }
0339 fclose(file);
0340 }
0341
0342
0343 file = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", "r");
0344 if (file) {
0345 while (fgets(buf, 255, file)) {
0346 unsigned int freq;
0347 freq = strtoull(buf, NULL, 10);
0348 if (freq > max_freq)
0349 max_freq = freq;
0350 }
0351 fclose(file);
0352 }
0353 return cpu_m;
0354 }
0355
0356 void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
0357 {
0358 char cpu_string[80];
0359 if (!svgfile)
0360 return;
0361
0362 max_freq = __max_freq;
0363 turbo_frequency = __turbo_freq;
0364
0365 fprintf(svgfile, "<g>\n");
0366
0367 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n",
0368 time2pixels(first_time),
0369 time2pixels(last_time)-time2pixels(first_time),
0370 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
0371
0372 sprintf(cpu_string, "CPU %i", (int)cpu);
0373 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
0374 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
0375
0376 fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n",
0377 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
0378
0379 fprintf(svgfile, "</g>\n");
0380 }
0381
0382 void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace)
0383 {
0384 double width;
0385 const char *type;
0386
0387 if (!svgfile)
0388 return;
0389
0390 if (svg_highlight && end - start >= svg_highlight)
0391 type = "sample_hi";
0392 else if (svg_highlight_name && strstr(name, svg_highlight_name))
0393 type = "sample_hi";
0394 else
0395 type = "sample";
0396
0397 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu));
0398 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
0399 if (backtrace)
0400 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
0401 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
0402 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
0403 width = time2pixels(end)-time2pixels(start);
0404 if (width > 6)
0405 width = 6;
0406
0407 width = round_text_size(width);
0408
0409 if (width > MIN_TEXT_SIZE)
0410 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n",
0411 width, name);
0412
0413 fprintf(svgfile, "</g>\n");
0414 }
0415
0416 void svg_cstate(int cpu, u64 start, u64 end, int type)
0417 {
0418 double width;
0419 char style[128];
0420
0421 if (!svgfile)
0422 return;
0423
0424
0425 fprintf(svgfile, "<g>\n");
0426
0427 if (type > 6)
0428 type = 6;
0429 sprintf(style, "c%i", type);
0430
0431 fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n",
0432 style,
0433 time2pixels(start), time2pixels(end)-time2pixels(start),
0434 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
0435
0436 width = (time2pixels(end)-time2pixels(start))/2.0;
0437 if (width > 6)
0438 width = 6;
0439
0440 width = round_text_size(width);
0441
0442 if (width > MIN_TEXT_SIZE)
0443 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n",
0444 time2pixels(start), cpu2y(cpu)+width, width, type);
0445
0446 fprintf(svgfile, "</g>\n");
0447 }
0448
0449 static char *HzToHuman(unsigned long hz)
0450 {
0451 static char buffer[1024];
0452 unsigned long long Hz;
0453
0454 memset(buffer, 0, 1024);
0455
0456 Hz = hz;
0457
0458
0459 sprintf(buffer, "%9lli", Hz);
0460
0461 if (Hz > 1000)
0462 sprintf(buffer, " %6lli Mhz", (Hz+500)/1000);
0463
0464 if (Hz > 1500000)
0465 sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000);
0466
0467 if (Hz == turbo_frequency)
0468 sprintf(buffer, "Turbo");
0469
0470 return buffer;
0471 }
0472
0473 void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
0474 {
0475 double height = 0;
0476
0477 if (!svgfile)
0478 return;
0479
0480 fprintf(svgfile, "<g>\n");
0481
0482 if (max_freq)
0483 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
0484 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
0485 fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n",
0486 time2pixels(start), time2pixels(end), height, height);
0487 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n",
0488 time2pixels(start), height+0.9, HzToHuman(freq));
0489
0490 fprintf(svgfile, "</g>\n");
0491 }
0492
0493
0494 void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace)
0495 {
0496 double height;
0497
0498 if (!svgfile)
0499 return;
0500
0501
0502 fprintf(svgfile, "<g>\n");
0503
0504 fprintf(svgfile, "<title>%s wakes up %s</title>\n",
0505 desc1 ? desc1 : "?",
0506 desc2 ? desc2 : "?");
0507
0508 if (backtrace)
0509 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
0510
0511 if (row1 < row2) {
0512 if (row1) {
0513 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
0514 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
0515 if (desc2)
0516 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s ></text></g>\n",
0517 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
0518 }
0519 if (row2) {
0520 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
0521 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
0522 if (desc1)
0523 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s ></text></g>\n",
0524 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
0525 }
0526 } else {
0527 if (row2) {
0528 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
0529 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
0530 if (desc1)
0531 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s <</text></g>\n",
0532 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
0533 }
0534 if (row1) {
0535 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
0536 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
0537 if (desc2)
0538 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s <</text></g>\n",
0539 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
0540 }
0541 }
0542 height = row1 * SLOT_MULT;
0543 if (row2 > row1)
0544 height += SLOT_HEIGHT;
0545 if (row1)
0546 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
0547 time2pixels(start), height);
0548
0549 fprintf(svgfile, "</g>\n");
0550 }
0551
0552 void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
0553 {
0554 double height;
0555
0556 if (!svgfile)
0557 return;
0558
0559
0560 fprintf(svgfile, "<g>\n");
0561
0562 if (backtrace)
0563 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
0564
0565 if (row1 < row2)
0566 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
0567 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
0568 else
0569 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
0570 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
0571
0572 height = row1 * SLOT_MULT;
0573 if (row2 > row1)
0574 height += SLOT_HEIGHT;
0575 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
0576 time2pixels(start), height);
0577
0578 fprintf(svgfile, "</g>\n");
0579 }
0580
0581 void svg_interrupt(u64 start, int row, const char *backtrace)
0582 {
0583 if (!svgfile)
0584 return;
0585
0586 fprintf(svgfile, "<g>\n");
0587
0588 fprintf(svgfile, "<title>Wakeup from interrupt</title>\n");
0589
0590 if (backtrace)
0591 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
0592
0593 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
0594 time2pixels(start), row * SLOT_MULT);
0595 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
0596 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
0597
0598 fprintf(svgfile, "</g>\n");
0599 }
0600
0601 void svg_text(int Yslot, u64 start, const char *text)
0602 {
0603 if (!svgfile)
0604 return;
0605
0606 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
0607 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
0608 }
0609
0610 static void svg_legenda_box(int X, const char *text, const char *style)
0611 {
0612 double boxsize;
0613 boxsize = SLOT_HEIGHT / 2;
0614
0615 fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
0616 X, boxsize, boxsize, style);
0617 fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n",
0618 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
0619 }
0620
0621 void svg_io_legenda(void)
0622 {
0623 if (!svgfile)
0624 return;
0625
0626 fprintf(svgfile, "<g>\n");
0627 svg_legenda_box(0, "Disk", "disk");
0628 svg_legenda_box(100, "Network", "net");
0629 svg_legenda_box(200, "Sync", "sync");
0630 svg_legenda_box(300, "Poll", "poll");
0631 svg_legenda_box(400, "Error", "error");
0632 fprintf(svgfile, "</g>\n");
0633 }
0634
0635 void svg_legenda(void)
0636 {
0637 if (!svgfile)
0638 return;
0639
0640 fprintf(svgfile, "<g>\n");
0641 svg_legenda_box(0, "Running", "sample");
0642 svg_legenda_box(100, "Idle","c1");
0643 svg_legenda_box(200, "Deeper Idle", "c3");
0644 svg_legenda_box(350, "Deepest Idle", "c6");
0645 svg_legenda_box(550, "Sleeping", "process2");
0646 svg_legenda_box(650, "Waiting for cpu", "waiting");
0647 svg_legenda_box(800, "Blocked on IO", "blocked");
0648 fprintf(svgfile, "</g>\n");
0649 }
0650
0651 void svg_time_grid(double min_thickness)
0652 {
0653 u64 i;
0654
0655 if (!svgfile)
0656 return;
0657
0658 i = first_time;
0659 while (i < last_time) {
0660 int color = 220;
0661 double thickness = 0.075;
0662 if ((i % 100000000) == 0) {
0663 thickness = 0.5;
0664 color = 192;
0665 }
0666 if ((i % 1000000000) == 0) {
0667 thickness = 2.0;
0668 color = 128;
0669 }
0670
0671 if (thickness >= min_thickness)
0672 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n",
0673 time2pixels(i), SLOT_MULT/2, time2pixels(i),
0674 total_height, color, color, color, thickness);
0675
0676 i += 10000000;
0677 }
0678 }
0679
0680 void svg_close(void)
0681 {
0682 if (svgfile) {
0683 fprintf(svgfile, "</svg>\n");
0684 fclose(svgfile);
0685 svgfile = NULL;
0686 }
0687 }
0688
0689 #define cpumask_bits(maskp) ((maskp)->bits)
0690 typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;
0691
0692 struct topology {
0693 cpumask_t *sib_core;
0694 int sib_core_nr;
0695 cpumask_t *sib_thr;
0696 int sib_thr_nr;
0697 };
0698
0699 static void scan_thread_topology(int *map, struct topology *t, int cpu,
0700 int *pos, int nr_cpus)
0701 {
0702 int i;
0703 int thr;
0704
0705 for (i = 0; i < t->sib_thr_nr; i++) {
0706 if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i])))
0707 continue;
0708
0709 for_each_set_bit(thr, cpumask_bits(&t->sib_thr[i]), nr_cpus)
0710 if (map[thr] == -1)
0711 map[thr] = (*pos)++;
0712 }
0713 }
0714
0715 static void scan_core_topology(int *map, struct topology *t, int nr_cpus)
0716 {
0717 int pos = 0;
0718 int i;
0719 int cpu;
0720
0721 for (i = 0; i < t->sib_core_nr; i++)
0722 for_each_set_bit(cpu, cpumask_bits(&t->sib_core[i]), nr_cpus)
0723 scan_thread_topology(map, t, cpu, &pos, nr_cpus);
0724 }
0725
0726 static int str_to_bitmap(char *s, cpumask_t *b, int nr_cpus)
0727 {
0728 int i;
0729 int ret = 0;
0730 struct perf_cpu_map *m;
0731 struct perf_cpu c;
0732
0733 m = perf_cpu_map__new(s);
0734 if (!m)
0735 return -1;
0736
0737 for (i = 0; i < perf_cpu_map__nr(m); i++) {
0738 c = perf_cpu_map__cpu(m, i);
0739 if (c.cpu >= nr_cpus) {
0740 ret = -1;
0741 break;
0742 }
0743
0744 set_bit(c.cpu, cpumask_bits(b));
0745 }
0746
0747 perf_cpu_map__put(m);
0748
0749 return ret;
0750 }
0751
0752 int svg_build_topology_map(struct perf_env *env)
0753 {
0754 int i, nr_cpus;
0755 struct topology t;
0756 char *sib_core, *sib_thr;
0757
0758 nr_cpus = min(env->nr_cpus_online, MAX_NR_CPUS);
0759
0760 t.sib_core_nr = env->nr_sibling_cores;
0761 t.sib_thr_nr = env->nr_sibling_threads;
0762 t.sib_core = calloc(env->nr_sibling_cores, sizeof(cpumask_t));
0763 t.sib_thr = calloc(env->nr_sibling_threads, sizeof(cpumask_t));
0764
0765 sib_core = env->sibling_cores;
0766 sib_thr = env->sibling_threads;
0767
0768 if (!t.sib_core || !t.sib_thr) {
0769 fprintf(stderr, "topology: no memory\n");
0770 goto exit;
0771 }
0772
0773 for (i = 0; i < env->nr_sibling_cores; i++) {
0774 if (str_to_bitmap(sib_core, &t.sib_core[i], nr_cpus)) {
0775 fprintf(stderr, "topology: can't parse siblings map\n");
0776 goto exit;
0777 }
0778
0779 sib_core += strlen(sib_core) + 1;
0780 }
0781
0782 for (i = 0; i < env->nr_sibling_threads; i++) {
0783 if (str_to_bitmap(sib_thr, &t.sib_thr[i], nr_cpus)) {
0784 fprintf(stderr, "topology: can't parse siblings map\n");
0785 goto exit;
0786 }
0787
0788 sib_thr += strlen(sib_thr) + 1;
0789 }
0790
0791 topology_map = malloc(sizeof(int) * nr_cpus);
0792 if (!topology_map) {
0793 fprintf(stderr, "topology: no memory\n");
0794 goto exit;
0795 }
0796
0797 for (i = 0; i < nr_cpus; i++)
0798 topology_map[i] = -1;
0799
0800 scan_core_topology(topology_map, &t, nr_cpus);
0801
0802 return 0;
0803
0804 exit:
0805 zfree(&t.sib_core);
0806 zfree(&t.sib_thr);
0807
0808 return -1;
0809 }