svg.c revision e985665d2d226cb42b52bfcad6fd5b1586ad57d7
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering * Copyright (C) 2009-2012 Intel Coproration
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering * Auke Kok <auke-jan.h.kok@intel.com>
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering * This program is free software; you can redistribute it and/or
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering * modify it under the terms of the GNU General Public License
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering * as published by the Free Software Foundation; version 2
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering * of the License.
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#define kb_to_graph(m) ((m) * scale_y * 0.0001)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#define to_color(n) (192.0 - ((n) * 192.0))
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#define max(x, y) (((x) > (y)) ? (x) : (y))
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#define min(x, y) (((x) < (y)) ? (x) : (y))
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#define svg(a...) do { snprintf(str, 8092, ## a); fputs(str, of); fflush(of); } while (0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int pcount = 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int kcount = 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic float psize = 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic float ksize = 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic float esize = 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic void svg_header(void)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* min width is about 1600px due to the label */
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek w = 150.0 + 10.0 + time_to_graph(sampletime[samples-1] - graph_start);
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek w = ((w < 1600.0) ? 1600.0 : w);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* height is variable based on pss, psize, ksize */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering h = 400.0 + (scale_y * 30.0) /* base graphs and title */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering + (pss ? (100.0 * scale_y) + (scale_y * 7.0) : 0.0) /* pss estimate */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<?xml version=\"1.0\" standalone=\"no\"?>\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering //svg("<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20));
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ",
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("xmlns=\"http://www.w3.org/2000/svg\">\n\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* write some basic info as a comment, including some help */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- such as Chrome/Chromium, firefox. Other applications that render -->\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- these files properly but much more slow are ImageMagick, gimp, -->\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- inkscape, etc.. To display the files on your system, just point -->\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- your browser to file:///var/log/ and click. This bootchart was -->\n\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- generated by bootchart version %s, running with options: -->\n", VERSION);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- hz=\"%f\" n=\"%d\" -->\n", hz, len);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- x=\"%f\" y=\"%f\" -->\n", scale_x, scale_y);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- rel=\"%d\" f=\"%d\" -->\n", relative, filter);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- p=\"%d\" e=\"%d\" -->\n", pss, entropy);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<!-- o=\"%s\" i=\"%s\" -->\n\n", output_path, init_path);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* style sheet */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" line { stroke: rgb(64,64,64); stroke-width: 1; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" line.sec5 { stroke-width: 2; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" line.dot { stroke-dasharray: 2 4; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" .run { font-size: 8; font-style: italic; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" text { font-family: Verdana, Helvetica; font-size: 10; }\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic void svg_title(void)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* extract root fs so we can find disk model name in sysfs */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering sprintf(filename, "/sys/block/%s/device/model", rootbdev);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering fprintf(stderr, "Error reading disk model for %s\n", rootbdev);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* various utsname parameters */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering fprintf(stderr, "Error getting uname info\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* CPU type */
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (strstr(buf, "model name")) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* Build - 1st line from /etc/system-release */
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek f = fopen("/etc/system-release", "r");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler uts.sysname, uts.release, uts.version, uts.machine);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett svg("<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n",
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler svg("<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n",
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett svg("<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n",
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n",
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett svg("<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett svg("<text class=\"t2\" x=\"20\" y=\"140\">Idle time: ");
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering svg("<text class=\"sec\" x=\"20\" y=\"155\">Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered</text>\n",
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler double d = 0.0;
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov /* outside box, fill */
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov svg("<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler time_to_graph(sampletime[samples-1] - graph_start),
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov for (d = graph_start; d <= sampletime[samples-1];
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler d += (scale_x < 2.0 ? 60.0 : scale_x < 10.0 ? 1.0 : 0.1)) {
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler /* lines for each second */
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (i % 50 == 0)
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov else if (i % 10 == 0)
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett /* time label */
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (i % 10 == 0)
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
7b909d7407965c03caaba30daae7aee113627a83Josh Triplettstatic void svg_pss_graph(void)
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering svg("\n\n<!-- Pss memory size graph -->\n");
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler svg("\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n");
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering /* vsize 1000 == 1000mb */
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering /* draw some hlines for usable memory sizes */
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering for (i = 100000; i < 1000000; i += 100000) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n",
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering time_to_graph(sampletime[samples-1] - graph_start),
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n",
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering time_to_graph(sampletime[samples-1] - graph_start) + 5,
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek /* now plot the graph itself */
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek for (i = 1; i < samples ; i++) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering /* put all the small pss blocks into the bottom */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ps->sample[i].pss <= (100 * scale_y))
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering "rgb(64,64,64)",
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering time_to_graph(sampletime[i - 1] - graph_start),
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering time_to_graph(sampletime[i] - sampletime[i - 1]),
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* now plot the ones that are of significant size */
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek /* don't draw anything smaller than 2mb */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ps->sample[i].pss > (100 * scale_y)) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek top = bottom + ps->sample[i].pss;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek time_to_graph(sampletime[i - 1] - graph_start),
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering time_to_graph(sampletime[i] - sampletime[i - 1]),
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler /* overlay all the text labels */
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering /* put all the small pss blocks into the bottom */
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering if (ps->sample[i].pss <= (100 * scale_y))
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering /* now plot the ones that are of significant size */
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering /* don't draw anything smaller than 2mb */
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (ps->sample[i].pss > (100 * scale_y)) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek top = bottom + ps->sample[i].pss;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering /* draw a label with the process / PID */
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if ((i == 1) || (ps->sample[i - 1].pss <= (100 * scale_y)))
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering svg(" <text x=\"%.03f\" y=\"%.03f\">%s [%i]</text>\n",
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering time_to_graph(sampletime[i] - graph_start),
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering /* debug output - full data dump */
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering svg("\n\n<!-- PSS map - csv format -->\n");
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering svg("<!-- %s [%d] pss=", ps->name, ps->pid);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek for (i = 0; i < samples ; i++) {
7b909d7407965c03caaba30daae7aee113627a83Josh Triplettstatic void svg_io_bi_bar(void)
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering svg("<!-- IO utilization graph - In -->\n");
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering svg("<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - read</text>\n");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * calculate rounding range
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * We need to round IO data since IO block data is not updated on
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * each poll. Applying a smoothing function loses some burst data,
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering * so keep the smoothing range short.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering /* surrounding box */
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek /* find the max IO first */
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering stop = min(i + (range / 2), samples - 1);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering tot = (double)(blockstat[stop].bi - blockstat[start].bi)
max_here = i;
int start;
int stop;
double tot;
double pbi;
if (i == max_here) {
static void svg_io_bo_bar(void)
double range;
int max_here = 0;
int start;
int stop;
double tot;
max_here = i;
int start;
int stop;
double tot;
double pbo;
if (i == max_here) {
static void svg_cpu_bar(void)
double trt;
double ptrt;
for (c = 0; c < cpus; c++)
static void svg_wait_bar(void)
double twt;
double ptwt;
for (c = 0; c < cpus; c++)
static void svg_entropy_bar(void)
if (!ps)
return ps;
return NULL;
if (!filter)
int ret;
int usecs;
kcount = 0;
if (!count_only) {
kcount = 0;
while (!feof(f)) {
func[z] = 0;
if (count_only) {
kcount++;
func,
kcount++;
static void svg_ps_bars(void)
int pid;
double starttime;
if (!ps)
ps_to_graph(j),
ps_to_graph(j),
double crt;
double brt;
for (c = 0; c < cpus; c++)
idletime);
-scale_y,
idletime);
static void svg_top_ten_cpu(void)
static void svg_top_ten_pss(void)
void svg_do(void)
pcount++;
pfiltered++;
svg_header();
svg_cpu_bar();
svg_wait_bar();
if (kcount) {
svg_do_initcall(0);
svg_ps_bars();
svg_title();
if (entropy) {
if (pss) {