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 <stdio.h> 16 #include <stdlib.h> 17 #include <unistd.h> 18 #include <string.h> 19 20 #include "svghelper.h" 21 22 static u64 first_time, last_time; 23 static u64 turbo_frequency, max_freq; 24 25 26 #define SLOT_MULT 30.0 27 #define SLOT_HEIGHT 25.0 28 #define WIDTH 1000.0 29 30 #define MIN_TEXT_SIZE 0.001 31 32 static u64 total_height; 33 static FILE *svgfile; 34 35 static double cpu2slot(int cpu) 36 { 37 return 2 * cpu + 1; 38 } 39 40 static double cpu2y(int cpu) 41 { 42 return cpu2slot(cpu) * SLOT_MULT; 43 } 44 45 static double time2pixels(u64 time) 46 { 47 double X; 48 49 X = WIDTH * (time - first_time) / (last_time - first_time); 50 return X; 51 } 52 53 void open_svg(const char *filename, int cpus, int rows) 54 { 55 56 svgfile = fopen(filename, "w"); 57 if (!svgfile) { 58 fprintf(stderr, "Cannot open %s for output\n", filename); 59 return; 60 } 61 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; 62 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); 63 fprintf(svgfile, "<svg width=\"%4.1f\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", WIDTH, total_height); 64 65 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); 66 67 fprintf(svgfile, " rect { stroke-width: 1; }\n"); 68 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 69 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 70 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 71 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 72 fprintf(svgfile, " rect.waiting { fill:rgb(255,255, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 73 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n"); 74 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n"); 75 fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n"); 76 fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n"); 77 fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n"); 78 fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n"); 79 fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n"); 80 fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n"); 81 fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n"); 82 83 fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); 84 } 85 86 void svg_box(int Yslot, u64 start, u64 end, const char *type) 87 { 88 if (!svgfile) 89 return; 90 91 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 92 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 93 } 94 95 void svg_sample(int Yslot, int cpu, u64 start, u64 end, const char *type) 96 { 97 double text_size; 98 if (!svgfile) 99 return; 100 101 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 102 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 103 104 text_size = (time2pixels(end)-time2pixels(start)); 105 if (cpu > 9) 106 text_size = text_size/2; 107 if (text_size > 1.25) 108 text_size = 1.25; 109 if (text_size > MIN_TEXT_SIZE) 110 fprintf(svgfile, "<text transform=\"translate(%1.8f,%1.8f)\" font-size=\"%1.6fpt\">%i</text>\n", 111 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 112 113 } 114 115 static char *cpu_model(void) 116 { 117 static char cpu_m[255]; 118 char buf[256]; 119 FILE *file; 120 121 cpu_m[0] = 0; 122 /* CPU type */ 123 file = fopen("/proc/cpuinfo", "r"); 124 if (file) { 125 while (fgets(buf, 255, file)) { 126 if (strstr(buf, "model name")) { 127 strncpy(cpu_m, &buf[13], 255); 128 break; 129 } 130 } 131 fclose(file); 132 } 133 return cpu_m; 134 } 135 136 void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) 137 { 138 char cpu_string[80]; 139 if (!svgfile) 140 return; 141 142 max_freq = __max_freq; 143 turbo_frequency = __turbo_freq; 144 145 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 146 time2pixels(first_time), 147 time2pixels(last_time)-time2pixels(first_time), 148 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 149 150 sprintf(cpu_string, "CPU %i", (int)cpu+1); 151 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\">%s</text>\n", 152 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 153 154 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 155 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 156 } 157 158 void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name) 159 { 160 double width; 161 162 if (!svgfile) 163 return; 164 165 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 166 time2pixels(start), time2pixels(end)-time2pixels(start), cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT, type); 167 width = time2pixels(end)-time2pixels(start); 168 if (width > 6) 169 width = 6; 170 171 if (width > MIN_TEXT_SIZE) 172 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"%3.4fpt\">%s</text>\n", 173 time2pixels(start), cpu2y(cpu), width, name); 174 } 175 176 void svg_cstate(int cpu, u64 start, u64 end, int type) 177 { 178 double width; 179 char style[128]; 180 181 if (!svgfile) 182 return; 183 184 185 if (type > 6) 186 type = 6; 187 sprintf(style, "c%i", type); 188 189 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", 190 style, 191 time2pixels(start), time2pixels(end)-time2pixels(start), 192 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 193 194 width = time2pixels(end)-time2pixels(start); 195 if (width > 6) 196 width = 6; 197 198 if (width > MIN_TEXT_SIZE) 199 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"%3.4fpt\">C%i</text>\n", 200 time2pixels(start), cpu2y(cpu), width, type); 201 } 202 203 static char *HzToHuman(unsigned long hz) 204 { 205 static char buffer[1024]; 206 unsigned long long Hz; 207 208 memset(buffer, 0, 1024); 209 210 Hz = hz; 211 212 /* default: just put the Number in */ 213 sprintf(buffer, "%9lli", Hz); 214 215 if (Hz > 1000) 216 sprintf(buffer, " %6lli Mhz", (Hz+500)/1000); 217 218 if (Hz > 1500000) 219 sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000); 220 221 if (Hz == turbo_frequency) 222 sprintf(buffer, "Turbo"); 223 224 return buffer; 225 } 226 227 void svg_pstate(int cpu, u64 start, u64 end, u64 freq) 228 { 229 double height = 0; 230 231 if (!svgfile) 232 return; 233 234 if (max_freq) 235 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 236 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 237 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", 238 time2pixels(start), time2pixels(end), height, height); 239 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"0.25pt\">%s</text>\n", 240 time2pixels(start), height+0.9, HzToHuman(freq)); 241 242 } 243 244 245 void svg_partial_wakeline(u64 start, int row1, int row2) 246 { 247 double height; 248 249 if (!svgfile) 250 return; 251 252 253 if (row1 < row2) { 254 if (row1) 255 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 256 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 257 258 if (row2) 259 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 260 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); 261 } else { 262 if (row2) 263 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 264 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 265 266 if (row1) 267 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 268 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); 269 } 270 height = row1 * SLOT_MULT; 271 if (row2 > row1) 272 height += SLOT_HEIGHT; 273 if (row1) 274 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 275 time2pixels(start), height); 276 } 277 278 void svg_wakeline(u64 start, int row1, int row2) 279 { 280 double height; 281 282 if (!svgfile) 283 return; 284 285 286 if (row1 < row2) 287 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 288 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 289 else 290 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 291 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); 292 293 height = row1 * SLOT_MULT; 294 if (row2 > row1) 295 height += SLOT_HEIGHT; 296 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 297 time2pixels(start), height); 298 } 299 300 void svg_interrupt(u64 start, int row) 301 { 302 if (!svgfile) 303 return; 304 305 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 306 time2pixels(start), row * SLOT_MULT); 307 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 308 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 309 } 310 311 void svg_text(int Yslot, u64 start, const char *text) 312 { 313 if (!svgfile) 314 return; 315 316 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\">%s</text>\n", 317 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); 318 } 319 320 static void svg_legenda_box(int X, const char *text, const char *style) 321 { 322 double boxsize; 323 boxsize = SLOT_HEIGHT / 2; 324 325 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 326 X, boxsize, boxsize, style); 327 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.4fpt\">%s</text>\n", 328 X + boxsize + 5, boxsize, 0.8 * boxsize, text); 329 } 330 331 void svg_legenda(void) 332 { 333 if (!svgfile) 334 return; 335 336 svg_legenda_box(0, "Running", "sample"); 337 svg_legenda_box(100, "Idle","rect.c1"); 338 svg_legenda_box(200, "Deeper Idle", "rect.c3"); 339 svg_legenda_box(350, "Deepest Idle", "rect.c6"); 340 svg_legenda_box(550, "Sleeping", "process2"); 341 svg_legenda_box(650, "Waiting for cpu", "waiting"); 342 svg_legenda_box(800, "Blocked on IO", "blocked"); 343 } 344 345 void svg_time_grid(u64 start, u64 end) 346 { 347 u64 i; 348 349 first_time = start; 350 last_time = end; 351 352 first_time = first_time / 100000000 * 100000000; 353 354 if (!svgfile) 355 return; 356 357 i = first_time; 358 while (i < last_time) { 359 int color = 220; 360 double thickness = 0.075; 361 if ((i % 100000000) == 0) { 362 thickness = 0.5; 363 color = 192; 364 } 365 if ((i % 1000000000) == 0) { 366 thickness = 2.0; 367 color = 128; 368 } 369 370 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n", 371 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 372 373 i += 10000000; 374 } 375 } 376 377 void svg_close(void) 378 { 379 if (svgfile) { 380 fprintf(svgfile, "</svg>\n"); 381 fclose(svgfile); 382 svgfile = NULL; 383 } 384 } 385