X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fbootchart%2Fsvg.c;h=cd896895c9ba2adf650d60b0d8b91150351be3e1;hb=40c2cce772ed74e7c6d302a6143ad818e9a2720d;hp=dc55cb3797a7fdf8813dc7fdb7a223e0a251a765;hpb=b823b5e272d07d31c12625a268e8d563289a4db5;p=elogind.git diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c index dc55cb379..cd896895c 100644 --- a/src/bootchart/svg.c +++ b/src/bootchart/svg.c @@ -1,5 +1,7 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + /*** - bootchart.c - This file is part of systemd-bootchart + This file is part of systemd. Copyright (C) 2009-2013 Intel Coproration @@ -31,14 +33,15 @@ #include #include -#include "bootchart.h" #include "util.h" #include "macro.h" +#include "store.h" +#include "svg.h" +#include "bootchart.h" - -#define time_to_graph(t) ((t) * scale_x) -#define ps_to_graph(n) ((n) * scale_y) -#define kb_to_graph(m) ((m) * scale_y * 0.0001) +#define time_to_graph(t) ((t) * arg_scale_x) +#define ps_to_graph(n) ((n) * arg_scale_y) +#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001) #define to_color(n) (192.0 - ((n) * 192.0)) #define max(x, y) (((x) > (y)) ? (x) : (y)) @@ -48,7 +51,7 @@ static char str[8092]; #define svg(a...) do { snprintf(str, 8092, ## a); fputs(str, of); fflush(of); } while (0) -static const char *colorwheel[12] = { +static const char * const colorwheel[12] = { "rgb(255,32,32)", // red "rgb(32,192,192)", // cyan "rgb(255,128,32)", // orange @@ -71,9 +74,7 @@ static float psize = 0; static float ksize = 0; static float esize = 0; - -static void svg_header(void) -{ +static void svg_header(void) { float w; float h; @@ -82,8 +83,8 @@ static void svg_header(void) w = ((w < 1600.0) ? 1600.0 : w); /* height is variable based on pss, psize, ksize */ - h = 400.0 + (scale_y * 30.0) /* base graphs and title */ - + (pss ? (100.0 * scale_y) + (scale_y * 7.0) : 0.0) /* pss estimate */ + h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */ + + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */ + psize + ksize + esize; svg("\n"); @@ -103,11 +104,11 @@ static void svg_header(void) svg("\n\n"); svg("\n", VERSION); - svg("\n", hz, len); - svg("\n", scale_x, scale_y); - svg("\n", relative, filter); - svg("\n", pss, entropy); - svg("\n\n", output_path, init_path); + svg("\n", arg_hz, arg_samples_len); + svg("\n", arg_scale_x, arg_scale_y); + svg("\n", arg_relative, arg_filter); + svg("\n", arg_pss, arg_entropy); + svg("\n\n", arg_output_path, arg_init_path); /* style sheet */ svg("\n \n\n\n"); - } - -static void svg_title(void) -{ +static void svg_title(const char *build) { char cmdline[256] = ""; char filename[PATH_MAX]; char buf[256]; @@ -149,7 +147,6 @@ static void svg_title(void) char model[256] = "Unknown"; char date[256] = "Unknown"; char cpu[256] = "Unknown"; - char build[256] = "Unknown"; char *c; FILE *f; time_t t; @@ -166,18 +163,19 @@ static void svg_title(void) } /* extract root fs so we can find disk model name in sysfs */ + /* FIXME: this works only in the simple case */ c = strstr(cmdline, "root=/dev/"); if (c) { strncpy(rootbdev, &c[10], 3); rootbdev[3] = '\0'; - } - sprintf(filename, "block/%s/device/model", rootbdev); - fd = openat(sysfd, filename, O_RDONLY); - f = fdopen(fd, "r"); - if (f) { - if (!fgets(model, 255, f)) - fprintf(stderr, "Error reading disk model for %s\n", rootbdev); - fclose(f); + sprintf(filename, "block/%s/device/model", rootbdev); + fd = openat(sysfd, filename, O_RDONLY); + f = fdopen(fd, "r"); + if (f) { + if (!fgets(model, 255, f)) + fprintf(stderr, "Error reading disk model for %s\n", rootbdev); + fclose(f); + } } /* various utsname parameters */ @@ -201,14 +199,6 @@ static void svg_title(void) fclose(f); } - /* Build - 1st line from /etc/system-release */ - f = fopen("/etc/system-release", "r"); - if (f) { - if (fgets(buf, 255, f)) - strncpy(build, buf, 255); - fclose(f); - } - svg("Bootchart for %s - %s\n", uts.nodename, date); svg("System: %s %s %s %s\n", @@ -230,12 +220,10 @@ static void svg_title(void) svg("Not detected"); svg("\n"); svg("Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered\n", - hz, len, overrun, pscount, pfiltered); + arg_hz, arg_samples_len, overrun, pscount, pfiltered); } - -static void svg_graph_box(int height) -{ +static void svg_graph_box(int height) { double d = 0.0; int i = 0; @@ -246,7 +234,7 @@ static void svg_graph_box(int height) ps_to_graph(height)); for (d = graph_start; d <= sampletime[samples-1]; - d += (scale_x < 2.0 ? 60.0 : scale_x < 10.0 ? 1.0 : 0.1)) { + d += (arg_scale_x < 2.0 ? 60.0 : arg_scale_x < 10.0 ? 1.0 : 0.1)) { /* lines for each second */ if (i % 50 == 0) svg(" \n", @@ -275,9 +263,22 @@ static void svg_graph_box(int height) } } +/* xml comments must not contain "--" */ +static char* xml_comment_encode(const char* name) { + char *enc_name, *p; + + enc_name = strdup(name); + if (!enc_name) + return NULL; -static void svg_pss_graph(void) -{ + for (p = enc_name; *p; p++) + if (p[0] == '-' && p[1] == '-') + p[1] = '_'; + + return enc_name; +} + +static void svg_pss_graph(void) { struct ps_struct *ps; int i; @@ -314,7 +315,7 @@ static void svg_pss_graph(void) ps = ps->next_ps; if (!ps) continue; - if (ps->sample[i].pss <= (100 * scale_y)) + if (ps->sample[i].pss <= (100 * arg_scale_y)) top += ps->sample[i].pss; }; svg(" \n", @@ -333,7 +334,7 @@ static void svg_pss_graph(void) if (!ps) continue; /* don't draw anything smaller than 2mb */ - if (ps->sample[i].pss > (100 * scale_y)) { + if (ps->sample[i].pss > (100 * arg_scale_y)) { top = bottom + ps->sample[i].pss; svg(" \n", colorwheel[ps->pid % 12], @@ -360,7 +361,7 @@ static void svg_pss_graph(void) ps = ps->next_ps; if (!ps) continue; - if (ps->sample[i].pss <= (100 * scale_y)) + if (ps->sample[i].pss <= (100 * arg_scale_y)) top += ps->sample[i].pss; }; @@ -373,11 +374,11 @@ static void svg_pss_graph(void) if (!ps) continue; /* don't draw anything smaller than 2mb */ - if (ps->sample[i].pss > (100 * scale_y)) { + if (ps->sample[i].pss > (100 * arg_scale_y)) { top = bottom + ps->sample[i].pss; /* draw a label with the process / PID */ - if ((i == 1) || (ps->sample[i - 1].pss <= (100 * scale_y))) - svg(" %s [%i]\n", + if ((i == 1) || (ps->sample[i - 1].pss <= (100 * arg_scale_y))) + svg(" [%i]\n", time_to_graph(sampletime[i] - graph_start), kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), ps->name, @@ -391,10 +392,17 @@ static void svg_pss_graph(void) svg("\n\n\n"); ps = ps_first; while (ps->next_ps) { + char _cleanup_free_ *enc_name = NULL; ps = ps->next_ps; if (!ps) continue; - svg("\n"); @@ -592,15 +596,14 @@ static void svg_cpu_bar(void) if (ptrt > 0.001) { svg("\n", time_to_graph(sampletime[i - 1] - graph_start), - (scale_y * 5) - (ptrt * (scale_y * 5)), + (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)), time_to_graph(sampletime[i] - sampletime[i - 1]), - ptrt * (scale_y * 5)); + ptrt * (arg_scale_y * 5)); } } } -static void svg_wait_bar(void) -{ +static void svg_wait_bar(void) { int i; svg("\n"); @@ -634,16 +637,15 @@ static void svg_wait_bar(void) if (ptwt > 0.001) { svg("\n", time_to_graph(sampletime[i - 1] - graph_start), - ((scale_y * 5) - (ptwt * (scale_y * 5))), + ((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))), time_to_graph(sampletime[i] - sampletime[i - 1]), - ptwt * (scale_y * 5)); + ptwt * (arg_scale_y * 5)); } } } -static void svg_entropy_bar(void) -{ +static void svg_entropy_bar(void) { int i; svg("\n"); @@ -657,15 +659,13 @@ static void svg_entropy_bar(void) /* svg("\n", sampletime[i], entropy_avail[i]); */ svg("\n", time_to_graph(sampletime[i - 1] - graph_start), - ((scale_y * 5) - ((entropy_avail[i] / 4096.) * (scale_y * 5))), + ((arg_scale_y * 5) - ((entropy_avail[i] / 4096.) * (arg_scale_y * 5))), time_to_graph(sampletime[i] - sampletime[i - 1]), - (entropy_avail[i] / 4096.) * (scale_y * 5)); + (entropy_avail[i] / 4096.) * (arg_scale_y * 5)); } } - -static struct ps_struct *get_next_ps(struct ps_struct *ps) -{ +static struct ps_struct *get_next_ps(struct ps_struct *ps) { /* * walk the list of processes and return the next one to be * painted @@ -694,10 +694,8 @@ static struct ps_struct *get_next_ps(struct ps_struct *ps) return NULL; } - -static int ps_filter(struct ps_struct *ps) -{ - if (!filter) +static int ps_filter(struct ps_struct *ps) { + if (!arg_filter) return 0; /* can't draw data when there is only 1 sample (need start + stop) */ @@ -715,9 +713,7 @@ static int ps_filter(struct ps_struct *ps) return 0; } - -static void svg_do_initcall(int count_only) -{ +static void svg_do_initcall(int count_only) { FILE _cleanup_pclose_ *f = NULL; double t; char func[256]; @@ -725,7 +721,7 @@ static void svg_do_initcall(int count_only) int usecs; /* can't plot initcall when disabled or in relative mode */ - if (!initcall || relative) { + if (!initcall || arg_relative) { kcount = 0; return; } @@ -805,9 +801,7 @@ static void svg_do_initcall(int count_only) } } - -static void svg_ps_bars(void) -{ +static void svg_ps_bars(void) { struct ps_struct *ps; int i = 0; int j = 0; @@ -824,14 +818,20 @@ static void svg_ps_bars(void) /* pass 2 - ps boxes */ ps = ps_first; while ((ps = get_next_ps(ps))) { + char _cleanup_free_ *enc_name = NULL; + double starttime; int t; if (!ps) continue; + enc_name = xml_comment_encode(ps->name); + if(!enc_name) + continue; + /* leave some trace of what we actually filtered etc. */ - svg("\n", ps->name, ps->pid, + svg("\n", enc_name, ps->pid, ps->ppid, ps->total); /* it would be nice if we could use exec_start from /proc/pid/sched, @@ -906,7 +906,7 @@ static void svg_ps_bars(void) w = ps->first; /* text label of process name */ - svg(" %s [%i] %.03fs\n", + svg(" [%i]%.03fs\n", time_to_graph(sampletime[w] - graph_start) + 5.0, ps_to_graph(j) + 14.0, ps->name, @@ -947,7 +947,7 @@ static void svg_ps_bars(void) break; } - for (i = ps->first; i < samples - (hz / 2); i++) { + for (i = ps->first; i < samples - (arg_hz / 2); i++) { double crt; double brt; int c; @@ -955,8 +955,8 @@ static void svg_ps_bars(void) /* subtract bootchart cpu utilization from total */ crt = 0.0; for (c = 0; c < cpus; c++) - crt += cpustat[c].sample[i + ((int)hz / 2)].runtime - cpustat[c].sample[i].runtime; - brt = ps->sample[i + ((int)hz / 2)].runtime - ps->sample[i].runtime; + crt += cpustat[c].sample[i + ((int)arg_hz / 2)].runtime - cpustat[c].sample[i].runtime; + brt = ps->sample[i + ((int)arg_hz / 2)].runtime - ps->sample[i].runtime; /* * our definition of "idle": @@ -970,21 +970,19 @@ static void svg_ps_bars(void) idletime); svg("\n", time_to_graph(idletime), - -scale_y, + -arg_scale_y, time_to_graph(idletime), - ps_to_graph(pcount) + scale_y); + ps_to_graph(pcount) + arg_scale_y); svg("%.01fs\n", time_to_graph(idletime) + 5.0, - ps_to_graph(pcount) + scale_y, + ps_to_graph(pcount) + arg_scale_y, idletime); break; } } } - -static void svg_top_ten_cpu(void) -{ +static void svg_top_ten_cpu(void) { struct ps_struct *top[10]; struct ps_struct emptyps; struct ps_struct *ps; @@ -1010,16 +1008,14 @@ static void svg_top_ten_cpu(void) svg("Top CPU consumers:\n"); for (n = 0; n < 10; n++) - svg("%3.03fs - %s[%d]\n", + svg("%3.03fs - [%d]\n", 20 + (n * 13), top[n]->total, top[n]->name, top[n]->pid); } - -static void svg_top_ten_pss(void) -{ +static void svg_top_ten_pss(void) { struct ps_struct *top[10]; struct ps_struct emptyps; struct ps_struct *ps; @@ -1045,16 +1041,14 @@ static void svg_top_ten_pss(void) svg("Top PSS consumers:\n"); for (n = 0; n < 10; n++) - svg("%dK - %s[%d]\n", + svg("%dK - [%d]\n", 20 + (n * 13), top[n]->pss_max, top[n]->name, top[n]->pid); } - -void svg_do(void) -{ +void svg_do(const char *build) { struct ps_struct *ps; memset(&str, 0, sizeof(str)); @@ -1063,7 +1057,7 @@ void svg_do(void) /* count initcall thread count first */ svg_do_initcall(1); - ksize = (kcount ? ps_to_graph(kcount) + (scale_y * 2) : 0); + ksize = (kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0); /* then count processes */ while ((ps = get_next_ps(ps))) { @@ -1072,9 +1066,9 @@ void svg_do(void) else pfiltered++; } - psize = ps_to_graph(pcount) + (scale_y * 2); + psize = ps_to_graph(pcount) + (arg_scale_y * 2); - esize = (entropy ? scale_y * 7 : 0); + esize = (arg_entropy ? arg_scale_y * 7 : 0); /* after this, we can draw the header with proper sizing */ svg_header(); @@ -1083,44 +1077,44 @@ void svg_do(void) svg_io_bi_bar(); svg("\n\n"); - svg("\n", 400.0 + (scale_y * 7.0)); + svg("\n", 400.0 + (arg_scale_y * 7.0)); svg_io_bo_bar(); svg("\n\n"); - svg("\n", 400.0 + (scale_y * 14.0)); + svg("\n", 400.0 + (arg_scale_y * 14.0)); svg_cpu_bar(); svg("\n\n"); - svg("\n", 400.0 + (scale_y * 21.0)); + svg("\n", 400.0 + (arg_scale_y * 21.0)); svg_wait_bar(); svg("\n\n"); if (kcount) { - svg("\n", 400.0 + (scale_y * 28.0)); + svg("\n", 400.0 + (arg_scale_y * 28.0)); svg_do_initcall(0); svg("\n\n"); } - svg("\n", 400.0 + (scale_y * 28.0) + ksize); + svg("\n", 400.0 + (arg_scale_y * 28.0) + ksize); svg_ps_bars(); svg("\n\n"); svg("\n"); - svg_title(); + svg_title(build); svg("\n\n"); svg("\n"); svg_top_ten_cpu(); svg("\n\n"); - if (entropy) { - svg("\n", 400.0 + (scale_y * 28.0) + ksize + psize); + if (arg_entropy) { + svg("\n", 400.0 + (arg_scale_y * 28.0) + ksize + psize); svg_entropy_bar(); svg("\n\n"); } - if (pss) { - svg("\n", 400.0 + (scale_y * 28.0) + ksize + psize + esize); + if (arg_pss) { + svg("\n", 400.0 + (arg_scale_y * 28.0) + ksize + psize + esize); svg_pss_graph(); svg("\n\n");