cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

svghelper.c (23279B)


      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
     26static u64 first_time, last_time;
     27static 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
     34int svg_page_width = 1000;
     35u64 svg_highlight;
     36const char *svg_highlight_name;
     37
     38#define MIN_TEXT_SIZE 0.01
     39
     40static u64 total_height;
     41static FILE *svgfile;
     42
     43static double cpu2slot(int cpu)
     44{
     45	return 2 * cpu + 1;
     46}
     47
     48static int *topology_map;
     49
     50static 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
     58static 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 */
     70static 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
     85void 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
    141static 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
    153void 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
    172void 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
    191void 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
    210void 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
    219static char *time_to_string(u64 duration);
    220void 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
    234void 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
    270static 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
    288void 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
    323static 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
    356void 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
    382void 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
    416void 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
    449static 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
    473void 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
    494void 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
    552void 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
    581void 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
    601void 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
    610static 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
    621void 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
    635void 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
    651void 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
    680void 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)
    690typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;
    691
    692struct topology {
    693	cpumask_t *sib_core;
    694	int sib_core_nr;
    695	cpumask_t *sib_thr;
    696	int sib_thr_nr;
    697};
    698
    699static 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
    715static 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
    726static 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	struct perf_cpu c;
    732
    733	m = perf_cpu_map__new(s);
    734	if (!m)
    735		return -1;
    736
    737	for (i = 0; i < perf_cpu_map__nr(m); i++) {
    738		c = perf_cpu_map__cpu(m, i);
    739		if (c.cpu >= nr_cpus) {
    740			ret = -1;
    741			break;
    742		}
    743
    744		set_bit(c.cpu, cpumask_bits(b));
    745	}
    746
    747	perf_cpu_map__put(m);
    748
    749	return ret;
    750}
    751
    752int 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
    804exit:
    805	zfree(&t.sib_core);
    806	zfree(&t.sib_thr);
    807
    808	return -1;
    809}