Commit | Line | Data |
---|---|---|
f48d55ce AV |
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 | ||
964a0b3d AV |
30 | #define MIN_TEXT_SIZE 0.001 |
31 | ||
f48d55ce AV |
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"); | |
a92fe7b3 AV |
72 | fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
73 | fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | |
f48d55ce AV |
74 | fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n"); |
75 | fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n"); | |
76 | fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n"); | |
77 | fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n"); | |
78 | fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n"); | |
79 | fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n"); | |
80 | fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n"); | |
81 | fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n"); | |
82 | fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n"); | |
83 | ||
84 | fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); | |
85 | } | |
86 | ||
87 | void svg_box(int Yslot, u64 start, u64 end, const char *type) | |
88 | { | |
89 | if (!svgfile) | |
90 | return; | |
91 | ||
92 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", | |
93 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); | |
94 | } | |
95 | ||
a92fe7b3 | 96 | void svg_sample(int Yslot, int cpu, u64 start, u64 end) |
f48d55ce AV |
97 | { |
98 | double text_size; | |
99 | if (!svgfile) | |
100 | return; | |
101 | ||
a92fe7b3 AV |
102 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n", |
103 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT); | |
f48d55ce AV |
104 | |
105 | text_size = (time2pixels(end)-time2pixels(start)); | |
106 | if (cpu > 9) | |
107 | text_size = text_size/2; | |
108 | if (text_size > 1.25) | |
109 | text_size = 1.25; | |
964a0b3d AV |
110 | if (text_size > MIN_TEXT_SIZE) |
111 | fprintf(svgfile, "<text transform=\"translate(%1.8f,%1.8f)\" font-size=\"%1.6fpt\">%i</text>\n", | |
f48d55ce AV |
112 | time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); |
113 | ||
114 | } | |
115 | ||
a92fe7b3 AV |
116 | static char *time_to_string(u64 duration) |
117 | { | |
118 | static char text[80]; | |
119 | ||
120 | text[0] = 0; | |
121 | ||
122 | if (duration < 1000) /* less than 1 usec */ | |
123 | return text; | |
124 | ||
125 | if (duration < 1000 * 1000) { /* less than 1 msec */ | |
126 | sprintf(text, "%4.1f us", duration / 1000.0); | |
127 | return text; | |
128 | } | |
129 | sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); | |
130 | ||
131 | return text; | |
132 | } | |
133 | ||
134 | void svg_waiting(int Yslot, u64 start, u64 end) | |
135 | { | |
136 | char *text; | |
137 | const char *style; | |
138 | double font_size; | |
139 | ||
140 | if (!svgfile) | |
141 | return; | |
142 | ||
143 | style = "waiting"; | |
144 | ||
145 | if (end-start > 10 * 1000000) /* 10 msec */ | |
146 | style = "WAITING"; | |
147 | ||
148 | text = time_to_string(end-start); | |
149 | ||
150 | font_size = 1.0 * (time2pixels(end)-time2pixels(start)) / strlen(text); | |
151 | ||
152 | if (font_size > 0.2) | |
153 | font_size = 0.2; | |
154 | ||
155 | ||
156 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", | |
157 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, style); | |
158 | if (font_size > MIN_TEXT_SIZE) | |
159 | fprintf(svgfile, "<text transform=\"translate(%1.8f,%1.8f)\" font-size=\"%1.6fpt\">%s</text>\n", | |
160 | time2pixels(start), Yslot * SLOT_MULT + 2, font_size, text); | |
161 | } | |
162 | ||
f48d55ce AV |
163 | static char *cpu_model(void) |
164 | { | |
165 | static char cpu_m[255]; | |
166 | char buf[256]; | |
167 | FILE *file; | |
168 | ||
169 | cpu_m[0] = 0; | |
170 | /* CPU type */ | |
171 | file = fopen("/proc/cpuinfo", "r"); | |
172 | if (file) { | |
173 | while (fgets(buf, 255, file)) { | |
174 | if (strstr(buf, "model name")) { | |
175 | strncpy(cpu_m, &buf[13], 255); | |
176 | break; | |
177 | } | |
178 | } | |
179 | fclose(file); | |
180 | } | |
181 | return cpu_m; | |
182 | } | |
183 | ||
184 | void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) | |
185 | { | |
186 | char cpu_string[80]; | |
187 | if (!svgfile) | |
188 | return; | |
189 | ||
190 | max_freq = __max_freq; | |
191 | turbo_frequency = __turbo_freq; | |
192 | ||
193 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", | |
194 | time2pixels(first_time), | |
195 | time2pixels(last_time)-time2pixels(first_time), | |
196 | cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); | |
197 | ||
198 | sprintf(cpu_string, "CPU %i", (int)cpu+1); | |
964a0b3d | 199 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\">%s</text>\n", |
f48d55ce AV |
200 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); |
201 | ||
964a0b3d | 202 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", |
f48d55ce AV |
203 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); |
204 | } | |
205 | ||
206 | void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name) | |
207 | { | |
208 | double width; | |
209 | ||
210 | if (!svgfile) | |
211 | return; | |
212 | ||
213 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", | |
214 | time2pixels(start), time2pixels(end)-time2pixels(start), cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT, type); | |
215 | width = time2pixels(end)-time2pixels(start); | |
216 | if (width > 6) | |
217 | width = 6; | |
218 | ||
964a0b3d AV |
219 | if (width > MIN_TEXT_SIZE) |
220 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"%3.4fpt\">%s</text>\n", | |
f48d55ce AV |
221 | time2pixels(start), cpu2y(cpu), width, name); |
222 | } | |
223 | ||
224 | void svg_cstate(int cpu, u64 start, u64 end, int type) | |
225 | { | |
226 | double width; | |
227 | char style[128]; | |
228 | ||
229 | if (!svgfile) | |
230 | return; | |
231 | ||
232 | ||
233 | if (type > 6) | |
234 | type = 6; | |
235 | sprintf(style, "c%i", type); | |
236 | ||
237 | fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", | |
238 | style, | |
239 | time2pixels(start), time2pixels(end)-time2pixels(start), | |
240 | cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); | |
241 | ||
242 | width = time2pixels(end)-time2pixels(start); | |
243 | if (width > 6) | |
244 | width = 6; | |
245 | ||
964a0b3d AV |
246 | if (width > MIN_TEXT_SIZE) |
247 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"%3.4fpt\">C%i</text>\n", | |
f48d55ce AV |
248 | time2pixels(start), cpu2y(cpu), width, type); |
249 | } | |
250 | ||
251 | static char *HzToHuman(unsigned long hz) | |
252 | { | |
253 | static char buffer[1024]; | |
254 | unsigned long long Hz; | |
255 | ||
256 | memset(buffer, 0, 1024); | |
257 | ||
258 | Hz = hz; | |
259 | ||
260 | /* default: just put the Number in */ | |
261 | sprintf(buffer, "%9lli", Hz); | |
262 | ||
263 | if (Hz > 1000) | |
264 | sprintf(buffer, " %6lli Mhz", (Hz+500)/1000); | |
265 | ||
266 | if (Hz > 1500000) | |
267 | sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000); | |
268 | ||
269 | if (Hz == turbo_frequency) | |
270 | sprintf(buffer, "Turbo"); | |
271 | ||
272 | return buffer; | |
273 | } | |
274 | ||
275 | void svg_pstate(int cpu, u64 start, u64 end, u64 freq) | |
276 | { | |
277 | double height = 0; | |
278 | ||
279 | if (!svgfile) | |
280 | return; | |
281 | ||
282 | if (max_freq) | |
283 | height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); | |
284 | height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; | |
285 | fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", | |
286 | time2pixels(start), time2pixels(end), height, height); | |
964a0b3d | 287 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"0.25pt\">%s</text>\n", |
f48d55ce AV |
288 | time2pixels(start), height+0.9, HzToHuman(freq)); |
289 | ||
290 | } | |
291 | ||
292 | ||
4f1202c8 | 293 | void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2) |
f48d55ce AV |
294 | { |
295 | double height; | |
296 | ||
297 | if (!svgfile) | |
298 | return; | |
299 | ||
300 | ||
301 | if (row1 < row2) { | |
4f1202c8 | 302 | if (row1) { |
f48d55ce AV |
303 | 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", |
304 | time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); | |
4f1202c8 AV |
305 | if (desc2) |
306 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"0.02pt\">%s ></text>\n", | |
307 | time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); | |
308 | } | |
309 | if (row2) { | |
f48d55ce AV |
310 | 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", |
311 | time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); | |
4f1202c8 AV |
312 | if (desc1) |
313 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"0.02pt\">%s ></text>\n", | |
314 | time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); | |
315 | } | |
f48d55ce | 316 | } else { |
4f1202c8 | 317 | if (row2) { |
f48d55ce AV |
318 | 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", |
319 | time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); | |
4f1202c8 AV |
320 | if (desc1) |
321 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"0.02pt\">%s <</text>\n", | |
322 | time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); | |
323 | } | |
324 | if (row1) { | |
f48d55ce AV |
325 | 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", |
326 | time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); | |
4f1202c8 AV |
327 | if (desc2) |
328 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f) rotate(90)\" font-size=\"0.02pt\">%s <</text>\n", | |
329 | time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); | |
330 | } | |
f48d55ce AV |
331 | } |
332 | height = row1 * SLOT_MULT; | |
333 | if (row2 > row1) | |
334 | height += SLOT_HEIGHT; | |
335 | if (row1) | |
336 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", | |
337 | time2pixels(start), height); | |
338 | } | |
339 | ||
340 | void svg_wakeline(u64 start, int row1, int row2) | |
341 | { | |
342 | double height; | |
343 | ||
344 | if (!svgfile) | |
345 | return; | |
346 | ||
347 | ||
348 | if (row1 < row2) | |
349 | 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", | |
350 | time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); | |
351 | else | |
352 | 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", | |
353 | time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); | |
354 | ||
355 | height = row1 * SLOT_MULT; | |
356 | if (row2 > row1) | |
357 | height += SLOT_HEIGHT; | |
358 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", | |
359 | time2pixels(start), height); | |
360 | } | |
361 | ||
362 | void svg_interrupt(u64 start, int row) | |
363 | { | |
364 | if (!svgfile) | |
365 | return; | |
366 | ||
367 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", | |
368 | time2pixels(start), row * SLOT_MULT); | |
369 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", | |
370 | time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); | |
371 | } | |
372 | ||
373 | void svg_text(int Yslot, u64 start, const char *text) | |
374 | { | |
375 | if (!svgfile) | |
376 | return; | |
377 | ||
964a0b3d | 378 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\">%s</text>\n", |
f48d55ce AV |
379 | time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); |
380 | } | |
381 | ||
382 | static void svg_legenda_box(int X, const char *text, const char *style) | |
383 | { | |
384 | double boxsize; | |
385 | boxsize = SLOT_HEIGHT / 2; | |
386 | ||
387 | fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", | |
388 | X, boxsize, boxsize, style); | |
964a0b3d | 389 | fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.4fpt\">%s</text>\n", |
f48d55ce AV |
390 | X + boxsize + 5, boxsize, 0.8 * boxsize, text); |
391 | } | |
392 | ||
393 | void svg_legenda(void) | |
394 | { | |
395 | if (!svgfile) | |
396 | return; | |
397 | ||
398 | svg_legenda_box(0, "Running", "sample"); | |
399 | svg_legenda_box(100, "Idle","rect.c1"); | |
400 | svg_legenda_box(200, "Deeper Idle", "rect.c3"); | |
401 | svg_legenda_box(350, "Deepest Idle", "rect.c6"); | |
402 | svg_legenda_box(550, "Sleeping", "process2"); | |
403 | svg_legenda_box(650, "Waiting for cpu", "waiting"); | |
404 | svg_legenda_box(800, "Blocked on IO", "blocked"); | |
405 | } | |
406 | ||
407 | void svg_time_grid(u64 start, u64 end) | |
408 | { | |
409 | u64 i; | |
410 | ||
411 | first_time = start; | |
412 | last_time = end; | |
413 | ||
414 | first_time = first_time / 100000000 * 100000000; | |
415 | ||
416 | if (!svgfile) | |
417 | return; | |
418 | ||
419 | i = first_time; | |
420 | while (i < last_time) { | |
421 | int color = 220; | |
422 | double thickness = 0.075; | |
423 | if ((i % 100000000) == 0) { | |
424 | thickness = 0.5; | |
425 | color = 192; | |
426 | } | |
427 | if ((i % 1000000000) == 0) { | |
428 | thickness = 2.0; | |
429 | color = 128; | |
430 | } | |
431 | ||
432 | 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", | |
433 | time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); | |
434 | ||
435 | i += 10000000; | |
436 | } | |
437 | } | |
438 | ||
439 | void svg_close(void) | |
440 | { | |
441 | if (svgfile) { | |
442 | fprintf(svgfile, "</svg>\n"); | |
443 | fclose(svgfile); | |
444 | svgfile = NULL; | |
445 | } | |
446 | } |