svg.c revision 1f3523baf7418adf3b2738b3917ef956a8414ab7
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/***
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bootchart.c - This file is part of systemd-bootchart
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Copyright (C) 2009-2013 Intel Coproration
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Authors:
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Auke Kok <auke-jan.h.kok@intel.com>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is free software; you can redistribute it and/or modify it
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering under the terms of the GNU Lesser General Public License as published by
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (at your option) any later version.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is distributed in the hope that it will be useful, but
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Lesser General Public License for more details.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering You should have received a copy of the GNU Lesser General Public License
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ***/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell#include <stdio.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <stdarg.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <stdlib.h>
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#include <string.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <time.h>
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering#include <limits.h>
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmek#include <unistd.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <sys/utsname.h>
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include <sys/stat.h>
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#include <fcntl.h>
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen
6482f6269c87d2249e52e889a63adbdd50f2d691Ronny Chevalier#include "bootchart.h"
0b452006de98294d1690f045f6ea2f7f6630ec3bRonny Chevalier#include "util.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "macro.h"
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering#define time_to_graph(t) ((t) * scale_x)
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering#define ps_to_graph(n) ((n) * scale_y)
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek#define kb_to_graph(m) ((m) * scale_y * 0.0001)
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering#define to_color(n) (192.0 - ((n) * 192.0))
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek#define max(x, y) (((x) > (y)) ? (x) : (y))
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek#define min(x, y) (((x) < (y)) ? (x) : (y))
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmekstatic char str[8092];
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering#define svg(a...) do { snprintf(str, 8092, ## a); fputs(str, of); fflush(of); } while (0)
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
f8294e4175918117ca6c131720bcf287eadcd029Josh Triplettstatic const char *colorwheel[12] = {
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek "rgb(255,32,32)", // red
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(32,192,192)", // cyan
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(255,128,32)", // orange
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(128,32,192)", // blue-violet
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(255,255,32)", // yellow
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(192,32,128)", // red-violet
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(32,255,32)", // green
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(255,64,32)", // red-orange
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(32,32,255)", // blue
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(255,192,32)", // yellow-orange
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(192,32,192)", // violet
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(32,192,32)" // yellow-green
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering};
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic double idletime = -1.0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int pfiltered = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int pcount = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic int kcount = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic float psize = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic float ksize = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic float esize = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void svg_header(void)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering{
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering float w;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering float h;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* min width is about 1600px due to the label */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering w = 150.0 + 10.0 + time_to_graph(sampletime[samples-1] - graph_start);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering w = ((w < 1600.0) ? 1600.0 : w);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* height is variable based on pss, psize, ksize */
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering h = 400.0 + (scale_y * 30.0) /* base graphs and title */
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering + (pss ? (100.0 * scale_y) + (scale_y * 7.0) : 0.0) /* pss estimate */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering + psize + ksize + esize;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<?xml version=\"1.0\" standalone=\"no\"?>\n");
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler svg("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering //svg("<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20));
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler svg("<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ",
ccf23ad5faf228d450d263d7291156a948b61af2Christian Seiler w, h);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("xmlns=\"http://www.w3.org/2000/svg\">\n\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* write some basic info as a comment, including some help */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- such as Chrome, Chromium, or Firefox. Other applications that -->\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- render these files properly but more slowly are ImageMagick, gimp, -->\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- inkscape, etc. To display the files on your system, just point -->\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- your browser to file:///run/log/ and click. This bootchart was -->\n\n");
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering svg("<!-- generated by bootchart version %s, running with options: -->\n", VERSION);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- hz=\"%f\" n=\"%d\" -->\n", hz, samples_len);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering svg("<!-- x=\"%f\" y=\"%f\" -->\n", scale_x, scale_y);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- rel=\"%d\" f=\"%d\" -->\n", relative, filter);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- p=\"%d\" e=\"%d\" -->\n", pss, entropy);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- o=\"%s\" i=\"%s\" -->\n\n", output_path, init_path);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* style sheet */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect { stroke-width: 1; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" line { stroke: rgb(64,64,64); stroke-width: 1; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("// line.sec1 { }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" line.sec5 { stroke-width: 2; }\n");
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering svg(" line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" line.dot { stroke-dasharray: 2 4; }\n");
3b97fcbd28f92a1e51887fef5de8844a89bde523Lennart Poettering svg(" line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n");
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" .run { font-size: 8; font-style: italic; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" text { font-family: Verdana, Helvetica; font-size: 10; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" text.sec { font-size: 8; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" text.t1 { font-size: 24; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" text.t2 { font-size: 12; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" text.idle { font-size: 18; }\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" ]]>\n </style>\n</defs>\n\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void svg_title(const char *build)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering{
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek char cmdline[256] = "";
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char filename[PATH_MAX];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char buf[256];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char rootbdev[16] = "Unknown";
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char model[256] = "Unknown";
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char date[256] = "Unknown";
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char cpu[256] = "Unknown";
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char *c;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering FILE *f;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering time_t t;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int fd;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering struct utsname uts;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* grab /proc/cmdline */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fd = openat(procfd, "cmdline", O_RDONLY);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering f = fdopen(fd, "r");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (f) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!fgets(cmdline, 255, f))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering sprintf(cmdline, "Unknown");
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek fclose(f);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* extract root fs so we can find disk model name in sysfs */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* FIXME: this works only in the simple case */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering c = strstr(cmdline, "root=/dev/");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (c) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strncpy(rootbdev, &c[10], 3);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering rootbdev[3] = '\0';
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering sprintf(filename, "block/%s/device/model", rootbdev);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fd = openat(sysfd, filename, O_RDONLY);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering f = fdopen(fd, "r");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (f) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!fgets(model, 255, f))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fprintf(stderr, "Error reading disk model for %s\n", rootbdev);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fclose(f);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* various utsname parameters */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (uname(&uts))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fprintf(stderr, "Error getting uname info\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* date */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering t = time(NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek /* CPU type */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fd = openat(procfd, "cpuinfo", O_RDONLY);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering f = fdopen(fd, "r");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (f) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (fgets(buf, 255, f)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (strstr(buf, "model name")) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering strncpy(cpu, &buf[13], 255);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering break;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fclose(f);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering uts.nodename, date);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek uts.sysname, uts.release, uts.version, uts.machine);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering cpu);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering model);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering cmdline);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering build);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"140\">Idle time: ");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (idletime >= 0.0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("%.03fs", idletime);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering else
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("Not detected");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("</text>\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart 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",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering hz, samples_len, overrun, pscount, pfiltered);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic void svg_graph_box(int height)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering{
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering double d = 0.0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int i = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* outside box, fill */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering time_to_graph(0.0),
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek time_to_graph(sampletime[samples-1] - graph_start),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps_to_graph(height));
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (d = graph_start; d <= sampletime[samples-1];
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering d += (scale_x < 2.0 ? 60.0 : scale_x < 10.0 ? 1.0 : 0.1)) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* lines for each second */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (i % 50 == 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(d - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(d - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering ps_to_graph(height));
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering else if (i % 10 == 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(d - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(d - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering ps_to_graph(height));
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering else
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(d - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(d - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering ps_to_graph(height));
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* time label */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (i % 10 == 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(d - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering -5.0,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering d - graph_start);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering i++;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering/* xml comments must not contain "--" */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic char* xml_comment_encode(const char* name) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering char *enc_name, *p;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering enc_name = strdup(name);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!enc_name)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return NULL;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering for (p = enc_name; *p; p++)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (p[0] == '-' && p[1] == '-')
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering p[1] = '_';
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return enc_name;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering}
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringstatic void svg_pss_graph(void)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering{
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering struct ps_struct *ps;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int i;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg("\n\n<!-- Pss memory size graph -->\n");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg("\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* vsize 1000 == 1000mb */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg_graph_box(100);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* draw some hlines for usable memory sizes */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering for (i = 100000; i < 1000000; i += 100000) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n",
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(.0),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering kb_to_graph(i),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(sampletime[samples-1] - graph_start),
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering kb_to_graph(i));
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n",
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering time_to_graph(sampletime[samples-1] - graph_start) + 5,
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering kb_to_graph(i), (1000000 - i) / 1000);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering }
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering svg("\n");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering /* now plot the graph itself */
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering for (i = 1; i < samples ; i++) {
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering int bottom;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int top;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bottom = 0;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering top = 0;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* put all the small pss blocks into the bottom */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps = ps_first;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (ps->next_ps) {
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering ps = ps->next_ps;
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering if (!ps)
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (ps->sample[i].pss <= (100 * scale_y))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering top += ps->sample[i].pss;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering };
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering "rgb(64,64,64)",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering time_to_graph(sampletime[i - 1] - graph_start),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering kb_to_graph(1000000.0 - top),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering time_to_graph(sampletime[i] - sampletime[i - 1]),
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering kb_to_graph(top - bottom));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek bottom = top;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* now plot the ones that are of significant size */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps = ps_first;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (ps->next_ps) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps = ps->next_ps;
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (!ps)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* don't draw anything smaller than 2mb */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (ps->sample[i].pss > (100 * scale_y)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering top = bottom + ps->sample[i].pss;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering colorwheel[ps->pid % 12],
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering time_to_graph(sampletime[i - 1] - graph_start),
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen kb_to_graph(1000000.0 - top),
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen time_to_graph(sampletime[i] - sampletime[i - 1]),
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen kb_to_graph(top - bottom));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bottom = top;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering }
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering /* overlay all the text labels */
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering for (i = 1; i < samples ; i++) {
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering int bottom;
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering int top;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bottom = 0;
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering top = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* put all the small pss blocks into the bottom */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps = ps_first;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (ps->next_ps) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps = ps->next_ps;
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering if (!ps)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (ps->sample[i].pss <= (100 * scale_y))
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering top += ps->sample[i].pss;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering };
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bottom = top;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* now plot the ones that are of significant size */
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek ps = ps_first;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering while (ps->next_ps) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps = ps->next_ps;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!ps)
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering continue;
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering /* don't draw anything smaller than 2mb */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (ps->sample[i].pss > (100 * scale_y)) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering top = bottom + ps->sample[i].pss;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* draw a label with the process / PID */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if ((i == 1) || (ps->sample[i - 1].pss <= (100 * scale_y)))
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering svg(" <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek time_to_graph(sampletime[i] - graph_start),
03ee5c38cb0da193dd08733fb4c0c2809cee6a99Lennart Poettering kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek ps->name,
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps->pid);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering bottom = top;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt }
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering /* debug output - full data dump */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("\n\n<!-- PSS map - csv format -->\n");
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt ps = ps_first;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt while (ps->next_ps) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char _cleanup_free_*enc_name;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering ps = ps->next_ps;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (!ps)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering enc_name = xml_comment_encode(ps->name);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if(!enc_name)
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt continue;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- %s [%d] pss=", enc_name, ps->pid);
6baa7db00812437bbc87e73faa1a11b6cf631958Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering for (i = 0; i < samples ; i++) {
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering svg("%d," , ps->sample[i].pss);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt }
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering svg(" -->\n");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering }
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering}
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidtstatic void svg_io_bi_bar(void)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering{
8531ae707d4d0203e83304d4af948b8169a5fce1Lennart Poettering double max = 0.0;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt double range;
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt int max_here = 0;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering int i;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering svg("<!-- IO utilization graph - In -->\n");
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering svg("<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - read</text>\n");
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering /*
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering * calculate rounding range
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering *
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering * We need to round IO data since IO block data is not updated on
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering * each poll. Applying a smoothing function loses some burst data,
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering * so keep the smoothing range short.
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering */
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering range = 0.25 / (1.0 / hz);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering if (range < 2.0)
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering range = 2.0; /* no smoothing */
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering /* surrounding box */
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering svg_graph_box(5);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering
/* find the max IO first */
for (i = 1; i < samples; i++) {
int start;
int stop;
double tot;
start = max(i - ((range / 2) - 1), 0);
stop = min(i + (range / 2), samples - 1);
tot = (double)(blockstat[stop].bi - blockstat[start].bi)
/ (stop - start);
if (tot > max) {
max = tot;
max_here = i;
}
tot = (double)(blockstat[stop].bo - blockstat[start].bo)
/ (stop - start);
if (tot > max)
max = tot;
}
/* plot bi */
for (i = 1; i < samples; i++) {
int start;
int stop;
double tot;
double pbi;
start = max(i - ((range / 2) - 1), 0);
stop = min(i + (range / 2), samples);
tot = (double)(blockstat[stop].bi - blockstat[start].bi)
/ (stop - start);
pbi = tot / max;
if (pbi > 0.001)
svg("<rect class=\"bi\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(sampletime[i - 1] - graph_start),
(scale_y * 5) - (pbi * (scale_y * 5)),
time_to_graph(sampletime[i] - sampletime[i - 1]),
pbi * (scale_y * 5));
/* labels around highest value */
if (i == max_here) {
svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
time_to_graph(sampletime[i] - graph_start) + 5,
((scale_y * 5) - (pbi * (scale_y * 5))) + 15,
max / 1024.0 / (interval / 1000000000.0));
}
}
}
static void svg_io_bo_bar(void)
{
double max = 0.0;
double range;
int max_here = 0;
int i;
svg("<!-- IO utilization graph - out -->\n");
svg("<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - write</text>\n");
/*
* calculate rounding range
*
* We need to round IO data since IO block data is not updated on
* each poll. Applying a smoothing function loses some burst data,
* so keep the smoothing range short.
*/
range = 0.25 / (1.0 / hz);
if (range < 2.0)
range = 2.0; /* no smoothing */
/* surrounding box */
svg_graph_box(5);
/* find the max IO first */
for (i = 1; i < samples; i++) {
int start;
int stop;
double tot;
start = max(i - ((range / 2) - 1), 0);
stop = min(i + (range / 2), samples - 1);
tot = (double)(blockstat[stop].bi - blockstat[start].bi)
/ (stop - start);
if (tot > max)
max = tot;
tot = (double)(blockstat[stop].bo - blockstat[start].bo)
/ (stop - start);
if (tot > max) {
max = tot;
max_here = i;
}
}
/* plot bo */
for (i = 1; i < samples; i++) {
int start;
int stop;
double tot;
double pbo;
start = max(i - ((range / 2) - 1), 0);
stop = min(i + (range / 2), samples);
tot = (double)(blockstat[stop].bo - blockstat[start].bo)
/ (stop - start);
pbo = tot / max;
if (pbo > 0.001)
svg("<rect class=\"bo\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(sampletime[i - 1] - graph_start),
(scale_y * 5) - (pbo * (scale_y * 5)),
time_to_graph(sampletime[i] - sampletime[i - 1]),
pbo * (scale_y * 5));
/* labels around highest bo value */
if (i == max_here) {
svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
time_to_graph(sampletime[i] - graph_start) + 5,
((scale_y * 5) - (pbo * (scale_y * 5))),
max / 1024.0 / (interval / 1000000000.0));
}
}
}
static void svg_cpu_bar(void)
{
int i;
svg("<!-- CPU utilization graph -->\n");
svg("<text class=\"t2\" x=\"5\" y=\"-15\">CPU utilization</text>\n");
/* surrounding box */
svg_graph_box(5);
/* bars for each sample, proportional to the CPU util. */
for (i = 1; i < samples; i++) {
int c;
double trt;
double ptrt;
ptrt = trt = 0.0;
for (c = 0; c < cpus; c++)
trt += cpustat[c].sample[i].runtime - cpustat[c].sample[i - 1].runtime;
trt = trt / 1000000000.0;
trt = trt / (double)cpus;
if (trt > 0.0)
ptrt = trt / (sampletime[i] - sampletime[i - 1]);
if (ptrt > 1.0)
ptrt = 1.0;
if (ptrt > 0.001) {
svg("<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(sampletime[i - 1] - graph_start),
(scale_y * 5) - (ptrt * (scale_y * 5)),
time_to_graph(sampletime[i] - sampletime[i - 1]),
ptrt * (scale_y * 5));
}
}
}
static void svg_wait_bar(void)
{
int i;
svg("<!-- Wait time aggregation box -->\n");
svg("<text class=\"t2\" x=\"5\" y=\"-15\">CPU wait</text>\n");
/* surrounding box */
svg_graph_box(5);
/* bars for each sample, proportional to the CPU util. */
for (i = 1; i < samples; i++) {
int c;
double twt;
double ptwt;
ptwt = twt = 0.0;
for (c = 0; c < cpus; c++)
twt += cpustat[c].sample[i].waittime - cpustat[c].sample[i - 1].waittime;
twt = twt / 1000000000.0;
twt = twt / (double)cpus;
if (twt > 0.0)
ptwt = twt / (sampletime[i] - sampletime[i - 1]);
if (ptwt > 1.0)
ptwt = 1.0;
if (ptwt > 0.001) {
svg("<rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(sampletime[i - 1] - graph_start),
((scale_y * 5) - (ptwt * (scale_y * 5))),
time_to_graph(sampletime[i] - sampletime[i - 1]),
ptwt * (scale_y * 5));
}
}
}
static void svg_entropy_bar(void)
{
int i;
svg("<!-- entropy pool graph -->\n");
svg("<text class=\"t2\" x=\"5\" y=\"-15\">Entropy pool size</text>\n");
/* surrounding box */
svg_graph_box(5);
/* bars for each sample, scale 0-4096 */
for (i = 1; i < samples; i++) {
/* svg("<!-- entropy %.03f %i -->\n", sampletime[i], entropy_avail[i]); */
svg("<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(sampletime[i - 1] - graph_start),
((scale_y * 5) - ((entropy_avail[i] / 4096.) * (scale_y * 5))),
time_to_graph(sampletime[i] - sampletime[i - 1]),
(entropy_avail[i] / 4096.) * (scale_y * 5));
}
}
static struct ps_struct *get_next_ps(struct ps_struct *ps)
{
/*
* walk the list of processes and return the next one to be
* painted
*/
if (ps == ps_first)
return ps->next_ps;
/* go deep */
if (ps->children)
return ps->children;
/* find siblings */
if (ps->next)
return ps->next;
/* go back for parent siblings */
while (1) {
if (ps->parent)
if (ps->parent->next)
return ps->parent->next;
ps = ps->parent;
if (!ps)
return ps;
}
return NULL;
}
static int ps_filter(struct ps_struct *ps)
{
if (!filter)
return 0;
/* can't draw data when there is only 1 sample (need start + stop) */
if (ps->first == ps->last)
return -1;
/* don't filter kthreadd */
if (ps->pid == 2)
return 0;
/* drop stuff that doesn't use any real CPU time */
if (ps->total <= 0.001)
return -1;
return 0;
}
static void svg_do_initcall(int count_only)
{
FILE _cleanup_pclose_ *f = NULL;
double t;
char func[256];
int ret;
int usecs;
/* can't plot initcall when disabled or in relative mode */
if (!initcall || relative) {
kcount = 0;
return;
}
if (!count_only) {
svg("<!-- initcall -->\n");
svg("<text class=\"t2\" x=\"5\" y=\"-15\">Kernel init threads</text>\n");
/* surrounding box */
svg_graph_box(kcount);
}
kcount = 0;
/*
* Initcall graphing - parses dmesg buffer and displays kernel threads
* This somewhat uses the same methods and scaling to show processes
* but looks a lot simpler. It's overlaid entirely onto the PS graph
* when appropriate.
*/
f = popen("dmesg", "r");
if (!f)
return;
while (!feof(f)) {
int c;
int z = 0;
char l[256];
if (fgets(l, sizeof(l) - 1, f) == NULL)
continue;
c = sscanf(l, "[%lf] initcall %s %*s %d %*s %d %*s",
&t, func, &ret, &usecs);
if (c != 4) {
/* also parse initcalls done by module loading */
c = sscanf(l, "[%lf] initcall %s %*s %*s %d %*s %d %*s",
&t, func, &ret, &usecs);
if (c != 4)
continue;
}
/* chop the +0xXX/0xXX stuff */
while(func[z] != '+')
z++;
func[z] = 0;
if (count_only) {
/* filter out irrelevant stuff */
if (usecs >= 1000)
kcount++;
continue;
}
svg("<!-- thread=\"%s\" time=\"%.3f\" elapsed=\"%d\" result=\"%d\" -->\n",
func, t, usecs, ret);
if (usecs < 1000)
continue;
/* rect */
svg(" <rect class=\"krnl\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(t - (usecs / 1000000.0)),
ps_to_graph(kcount),
time_to_graph(usecs / 1000000.0),
ps_to_graph(1));
/* label */
svg(" <text x=\"%.03f\" y=\"%.03f\">%s <tspan class=\"run\">%.03fs</tspan></text>\n",
time_to_graph(t - (usecs / 1000000.0)) + 5,
ps_to_graph(kcount) + 15,
func,
usecs / 1000000.0);
kcount++;
}
}
static void svg_ps_bars(void)
{
struct ps_struct *ps;
int i = 0;
int j = 0;
int w;
int pid;
svg("<!-- Process graph -->\n");
svg("<text class=\"t2\" x=\"5\" y=\"-15\">Processes</text>\n");
/* surrounding box */
svg_graph_box(pcount);
/* pass 2 - ps boxes */
ps = ps_first;
while ((ps = get_next_ps(ps))) {
char _cleanup_free_*enc_name;
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("<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", enc_name, ps->pid,
ps->ppid, ps->total);
/* it would be nice if we could use exec_start from /proc/pid/sched,
* but it's unreliable and gives bogus numbers */
starttime = sampletime[ps->first];
if (!ps_filter(ps)) {
/* remember where _to_ our children need to draw a line */
ps->pos_x = time_to_graph(starttime - graph_start);
ps->pos_y = ps_to_graph(j+1); /* bottom left corner */
} else {
/* hook children to our parent coords instead */
ps->pos_x = ps->parent->pos_x;
ps->pos_y = ps->parent->pos_y;
/* if this is the last child, we might still need to draw a connecting line */
if ((!ps->next) && (ps->parent))
svg(" <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
ps->parent->pos_x,
ps_to_graph(j-1) + 10.0, /* whee, use the last value here */
ps->parent->pos_x,
ps->parent->pos_y);
continue;
}
svg(" <rect class=\"ps\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(starttime - graph_start),
ps_to_graph(j),
time_to_graph(sampletime[ps->last] - starttime),
ps_to_graph(1));
/* paint cpu load over these */
for (t = ps->first + 1; t < ps->last; t++) {
double rt, prt;
double wt, wrt;
/* calculate over interval */
rt = ps->sample[t].runtime - ps->sample[t-1].runtime;
wt = ps->sample[t].waittime - ps->sample[t-1].waittime;
prt = (rt / 1000000000) / (sampletime[t] - sampletime[t-1]);
wrt = (wt / 1000000000) / (sampletime[t] - sampletime[t-1]);
/* this can happen if timekeeping isn't accurate enough */
if (prt > 1.0)
prt = 1.0;
if (wrt > 1.0)
wrt = 1.0;
if ((prt < 0.1) && (wrt < 0.1)) /* =~ 26 (color threshold) */
continue;
svg(" <rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(sampletime[t - 1] - graph_start),
ps_to_graph(j),
time_to_graph(sampletime[t] - sampletime[t - 1]),
ps_to_graph(wrt));
/* draw cpu over wait - TODO figure out how/why run + wait > interval */
svg(" <rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(sampletime[t - 1] - graph_start),
ps_to_graph(j + (1.0 - prt)),
time_to_graph(sampletime[t] - sampletime[t - 1]),
ps_to_graph(prt));
}
/* determine where to display the process name */
if (sampletime[ps->last] - sampletime[ps->first] < 1.5)
/* too small to fit label inside the box */
w = ps->last;
else
w = ps->first;
/* text label of process name */
svg(" <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan></text>\n",
time_to_graph(sampletime[w] - graph_start) + 5.0,
ps_to_graph(j) + 14.0,
ps->name,
ps->pid,
(ps->sample[ps->last].runtime - ps->sample[ps->first].runtime) / 1000000000.0);
/* paint lines to the parent process */
if (ps->parent) {
/* horizontal part */
svg(" <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
time_to_graph(starttime - graph_start),
ps_to_graph(j) + 10.0,
ps->parent->pos_x,
ps_to_graph(j) + 10.0);
/* one vertical line connecting all the horizontal ones up */
if (!ps->next)
svg(" <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
ps->parent->pos_x,
ps_to_graph(j) + 10.0,
ps->parent->pos_x,
ps->parent->pos_y);
}
j++; /* count boxes */
svg("\n");
}
/* last pass - determine when idle */
pid = getpid();
/* make sure we start counting from the point where we actually have
* data: assume that bootchart's first sample is when data started
*/
ps = ps_first;
while (ps->next_ps) {
ps = ps->next_ps;
if (ps->pid == pid)
break;
}
for (i = ps->first; i < samples - (hz / 2); i++) {
double crt;
double brt;
int c;
/* 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;
/*
* our definition of "idle":
*
* if for (hz / 2) we've used less CPU than (interval / 2) ...
* defaults to 4.0%, which experimentally, is where atom idles
*/
if ((crt - brt) < (interval / 2.0)) {
idletime = sampletime[i] - graph_start;
svg("\n<!-- idle detected at %.03f seconds -->\n",
idletime);
svg("<line class=\"idle\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
time_to_graph(idletime),
-scale_y,
time_to_graph(idletime),
ps_to_graph(pcount) + scale_y);
svg("<text class=\"idle\" x=\"%.03f\" y=\"%.03f\">%.01fs</text>\n",
time_to_graph(idletime) + 5.0,
ps_to_graph(pcount) + scale_y,
idletime);
break;
}
}
}
static void svg_top_ten_cpu(void)
{
struct ps_struct *top[10];
struct ps_struct emptyps;
struct ps_struct *ps;
int n, m;
memset(&emptyps, 0, sizeof(struct ps_struct));
for (n=0; n < 10; n++)
top[n] = &emptyps;
/* walk all ps's and setup ptrs */
ps = ps_first;
while ((ps = get_next_ps(ps))) {
for (n = 0; n < 10; n++) {
if (ps->total <= top[n]->total)
continue;
/* cascade insert */
for (m = 9; m > n; m--)
top[m] = top[m-1];
top[n] = ps;
break;
}
}
svg("<text class=\"t2\" x=\"20\" y=\"0\">Top CPU consumers:</text>\n");
for (n = 0; n < 10; n++)
svg("<text class=\"t3\" x=\"20\" y=\"%d\">%3.03fs - <![CDATA[%s]]> [%d]</text>\n",
20 + (n * 13),
top[n]->total,
top[n]->name,
top[n]->pid);
}
static void svg_top_ten_pss(void)
{
struct ps_struct *top[10];
struct ps_struct emptyps;
struct ps_struct *ps;
int n, m;
memset(&emptyps, 0, sizeof(struct ps_struct));
for (n=0; n < 10; n++)
top[n] = &emptyps;
/* walk all ps's and setup ptrs */
ps = ps_first;
while ((ps = get_next_ps(ps))) {
for (n = 0; n < 10; n++) {
if (ps->pss_max <= top[n]->pss_max)
continue;
/* cascade insert */
for (m = 9; m > n; m--)
top[m] = top[m-1];
top[n] = ps;
break;
}
}
svg("<text class=\"t2\" x=\"20\" y=\"0\">Top PSS consumers:</text>\n");
for (n = 0; n < 10; n++)
svg("<text class=\"t3\" x=\"20\" y=\"%d\">%dK - <![CDATA[%s]]> [%d]</text>\n",
20 + (n * 13),
top[n]->pss_max,
top[n]->name,
top[n]->pid);
}
void svg_do(const char *build)
{
struct ps_struct *ps;
memset(&str, 0, sizeof(str));
ps = ps_first;
/* count initcall thread count first */
svg_do_initcall(1);
ksize = (kcount ? ps_to_graph(kcount) + (scale_y * 2) : 0);
/* then count processes */
while ((ps = get_next_ps(ps))) {
if (!ps_filter(ps))
pcount++;
else
pfiltered++;
}
psize = ps_to_graph(pcount) + (scale_y * 2);
esize = (entropy ? scale_y * 7 : 0);
/* after this, we can draw the header with proper sizing */
svg_header();
svg("<g transform=\"translate(10,400)\">\n");
svg_io_bi_bar();
svg("</g>\n\n");
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (scale_y * 7.0));
svg_io_bo_bar();
svg("</g>\n\n");
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (scale_y * 14.0));
svg_cpu_bar();
svg("</g>\n\n");
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (scale_y * 21.0));
svg_wait_bar();
svg("</g>\n\n");
if (kcount) {
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (scale_y * 28.0));
svg_do_initcall(0);
svg("</g>\n\n");
}
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (scale_y * 28.0) + ksize);
svg_ps_bars();
svg("</g>\n\n");
svg("<g transform=\"translate(10, 0)\">\n");
svg_title(build);
svg("</g>\n\n");
svg("<g transform=\"translate(10,200)\">\n");
svg_top_ten_cpu();
svg("</g>\n\n");
if (entropy) {
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (scale_y * 28.0) + ksize + psize);
svg_entropy_bar();
svg("</g>\n\n");
}
if (pss) {
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (scale_y * 28.0) + ksize + psize + esize);
svg_pss_graph();
svg("</g>\n\n");
svg("<g transform=\"translate(410,200)\">\n");
svg_top_ten_pss();
svg("</g>\n\n");
}
/* svg footer */
svg("\n</svg>\n");
}