svg.c revision 40c2cce772ed74e7c6d302a6143ad818e9a2720d
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright (C) 2009-2013 Intel Coproration
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Auke Kok <auke-jan.h.kok@intel.com>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define time_to_graph(t) ((t) * arg_scale_x)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define ps_to_graph(n) ((n) * arg_scale_y)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define to_color(n) (192.0 - ((n) * 192.0))
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt#define max(x, y) (((x) > (y)) ? (x) : (y))
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt#define min(x, y) (((x) < (y)) ? (x) : (y))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#define svg(a...) do { snprintf(str, 8092, ## a); fputs(str, of); fflush(of); } while (0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic const char * const colorwheel[12] = {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int pcount = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int kcount = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic float psize = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic float ksize = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic float esize = 0;
d3e84ddb885e9d5f0ae9930eb905910e3a81f157Lennart Poetteringstatic void svg_header(void) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* min width is about 1600px due to the label */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering w = 150.0 + 10.0 + time_to_graph(sampletime[samples-1] - graph_start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* height is variable based on pss, psize, ksize */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<?xml version=\"1.0\" standalone=\"no\"?>\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering //svg("<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("xmlns=\"http://www.w3.org/2000/svg\">\n\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* write some basic info as a comment, including some help */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- such as Chrome, Chromium, or Firefox. Other applications that -->\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- render these files properly but more slowly are ImageMagick, gimp, -->\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- inkscape, etc. To display the files on your system, just point -->\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- your browser to file:///run/log/ and click. This bootchart was -->\n\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- generated by bootchart version %s, running with options: -->\n", VERSION);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- hz=\"%f\" n=\"%d\" -->\n", arg_hz, arg_samples_len);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<!-- x=\"%f\" y=\"%f\" -->\n", arg_scale_x, arg_scale_y);
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering svg("<!-- rel=\"%d\" f=\"%d\" -->\n", arg_relative, arg_filter);
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering svg("<!-- p=\"%d\" e=\"%d\" -->\n", arg_pss, arg_entropy);
b87633c4b20e3221748d6c98336cf6c85123cd66Lennart Poettering svg("<!-- o=\"%s\" i=\"%s\" -->\n\n", arg_output_path, arg_init_path);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* style sheet */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" line { stroke: rgb(64,64,64); stroke-width: 1; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" line.sec5 { stroke-width: 2; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" line.dot { stroke-dasharray: 2 4; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering svg(" .run { font-size: 8; font-style: italic; }\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" text { font-family: Verdana, Helvetica; font-size: 10; }\n");
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poetteringstatic void svg_title(const char *build) {
ebeccf9eecf5939a2ef772c3160e89efcad96194Lennart Poettering fd = openat(procfd, "cmdline", O_RDONLY);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* extract root fs so we can find disk model name in sysfs */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* FIXME: this works only in the simple case */
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt sprintf(filename, "block/%s/device/model", rootbdev);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(stderr, "Error reading disk model for %s\n", rootbdev);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* various utsname parameters */
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt fprintf(stderr, "Error getting uname info\n");
19befb2d5fc087f96e40ddc432b2cc9385666209Lennart Poettering strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* CPU type */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fd = openat(procfd, "cpuinfo", O_RDONLY);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering svg("<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering uts.sysname, uts.release, uts.version, uts.machine);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt svg("<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n",
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<text class=\"t2\" x=\"20\" y=\"140\">Idle time: ");
5bb658a1784a0fd4f0f32adb4b1fb636ff503f7dKay Sievers 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",
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt arg_hz, arg_samples_len, overrun, pscount, pfiltered);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt double d = 0.0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* outside box, fill */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg("<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(sampletime[samples-1] - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (d = graph_start; d <= sampletime[samples-1];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering d += (arg_scale_x < 2.0 ? 60.0 : arg_scale_x < 10.0 ? 1.0 : 0.1)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* lines for each second */
71fda00f320379f5cbee8e118848de98caaa229dLennart Poettering if (i % 50 == 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (i % 10 == 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* time label */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (i % 10 == 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/* xml comments must not contain "--" */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic char* xml_comment_encode(const char* name) {
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering for (p = enc_name; *p; p++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void svg_pss_graph(void) {
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering svg("\n\n<!-- Pss memory size graph -->\n");
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering svg("\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n");
d9e34bfda3d34dcde00a876cb052e7de0655e1cbLennart Poettering /* vsize 1000 == 1000mb */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* draw some hlines for usable memory sizes */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 100000; i < 1000000; i += 100000) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(sampletime[samples-1] - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(sampletime[samples-1] - graph_start) + 5,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* now plot the graph itself */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* put all the small pss blocks into the bottom */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ps->sample[i].pss <= (100 * arg_scale_y))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "rgb(64,64,64)",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(sampletime[i - 1] - graph_start),
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt time_to_graph(sampletime[i] - sampletime[i - 1]),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* now plot the ones that are of significant size */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* don't draw anything smaller than 2mb */
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek if (ps->sample[i].pss > (100 * arg_scale_y)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(sampletime[i - 1] - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(sampletime[i] - sampletime[i - 1]),
int bottom;
int top;
bottom = 0;
top = 0;
if (!ps)
if (!ps)
if (!ps)
if(!enc_name)
for (i = 0; i < samples ; i++) {
static void svg_io_bi_bar(void) {
double range;
int max_here = 0;
int start;
int stop;
double tot;
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 (!arg_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)
if(!enc_name)
ps_to_graph(j),
ps_to_graph(j),
svg(" <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan></text>\n",
double crt;
double brt;
for (c = 0; c < cpus; c++)
idletime);
idletime);
static void svg_top_ten_cpu(void) {
static void svg_top_ten_pss(void) {
pcount++;
pfiltered++;
svg_header();
svg_cpu_bar();
svg_wait_bar();
if (kcount) {
svg_do_initcall(0);
svg_ps_bars();
if (arg_entropy) {
if (arg_pss) {
svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * 28.0) + ksize + psize + esize);