Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * svghelper.c - helper functions for outputting svg
0004  *
0005  * (C) Copyright 2009 Intel Corporation
0006  *
0007  * Authors:
0008  *     Arjan van de Ven <arjan@linux.intel.com>
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  * Round text sizes so that the svg viewer only needs a discrete
0068  * number of renderings of the font
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      * if the recording is short, we default to a width of 1000, but
0100      * for longer recordings we want at least 200 units of width per second
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) /* less than 1 usec */
0277         return text;
0278 
0279     if (duration < NSEC_PER_MSEC) { /* less than 1 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) /* 10 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     /* CPU type */
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     /* CPU type */
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     /* default: just put the Number in */
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 &gt;</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 &gt;</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 &lt;</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 &lt;</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 }