svg.c revision 4e5356169ac2ef7f22e5a101d86009f706b0ff7b
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright (C) 2009-2013 Intel Corporation
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Authors:
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Auke Kok <auke-jan.h.kok@intel.com>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
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
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
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 ***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdio.h>
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering#include <string.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <time.h>
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include <limits.h>
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include <unistd.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/utsname.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <fcntl.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "fileio.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "macro.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "store.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "svg.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "bootchart.h"
718db96199eb307751264e4163555662c9a389faLennart Poettering#include "list.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "utf8.h"
23c80348e656a4e6fd9ba8f17523a65b6fa349a0Kay Sievers
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#define time_to_graph(t) ((t) * arg_scale_x)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#define ps_to_graph(n) ((n) * arg_scale_y)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#define to_color(n) (192.0 - ((n) * 192.0))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic const char * const colorwheel[12] = {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(255,32,32)", // red
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(32,192,192)", // cyan
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(255,128,32)", // orange
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(128,32,192)", // blue-violet
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(255,255,32)", // yellow
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(192,32,128)", // red-violet
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(32,255,32)", // green
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(255,64,32)", // red-orange
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(32,32,255)", // blue
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering "rgb(255,192,32)", // yellow-orange
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(192,32,192)", // violet
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "rgb(32,192,32)" // yellow-green
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering};
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic double idletime = -1.0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int pfiltered = 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int pcount = 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic int kcount = 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic double psize = 0;
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poetteringstatic double ksize = 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic double esize = 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic struct list_sample_data *sampledata;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic struct list_sample_data *prev_sampledata;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic void svg_header(FILE *of, struct list_sample_data *head, double graph_start, int n_cpus) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double w;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering double h;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct list_sample_data *sampledata_last;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering assert(head);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sampledata_last = head;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering sampledata_last = sampledata;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* min width is about 1600px due to the label */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering w = 150.0 + 10.0 + time_to_graph(sampledata_last->sampletime - graph_start);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering w = ((w < 1600.0) ? 1600.0 : w);
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering /* height is variable based on pss, psize, ksize */
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering + psize + ksize + esize + (n_cpus * 15 * arg_scale_y);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering fprintf(of, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering fprintf(of, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering fprintf(of, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering //fprintf(of, "<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20));
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering fprintf(of, "<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ", w, h);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "xmlns=\"http://www.w3.org/2000/svg\">\n\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* write some basic info as a comment, including some help */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek fprintf(of, "<!-- such as Chrome, Chromium, or Firefox. Other applications that -->\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- render these files properly but more slowly are ImageMagick, gimp, -->\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- inkscape, etc. To display the files on your system, just point -->\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- your browser to file:///run/log/ and click. This bootchart was -->\n\n");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- generated by bootchart version %s, running with options: -->\n", VERSION);
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering fprintf(of, "<!-- hz=\"%f\" n=\"%d\" -->\n", arg_hz, arg_samples_len);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- x=\"%f\" y=\"%f\" -->\n", arg_scale_x, arg_scale_y);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- rel=\"%d\" f=\"%d\" -->\n", arg_relative, arg_filter);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, "<!-- p=\"%d\" e=\"%d\" -->\n", arg_pss, arg_entropy);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- o=\"%s\" i=\"%s\" -->\n\n", arg_output_path, arg_init_path);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* style sheet */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect { stroke-width: 1; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect.bg { fill: rgb(255,255,255); }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n");
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering fprintf(of, " rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, " rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " line { stroke: rgb(64,64,64); stroke-width: 1; }\n");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, "// line.sec1 { }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " line.sec5 { stroke-width: 2; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " line.dot { stroke-dasharray: 2 4; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " .run { font-size: 8; font-style: italic; }\n");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, " text { font-family: Verdana, Helvetica; font-size: 10; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " text.sec { font-size: 8; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " text.t1 { font-size: 24; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " text.t2 { font-size: 12; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " text.idle { font-size: 18; }\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " ]]>\n </style>\n</defs>\n\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int svg_title(FILE *of, const char *build, int pscount, double log_start, int overrun) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_free_ char *cmdline = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _cleanup_free_ char *model = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _cleanup_free_ char *buf = NULL;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering char date[256] = "Unknown";
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering char *cpu;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering char *c;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering time_t t;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int r;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering struct utsname uts;
8aec412ff697bc14995746953912ca6fdf2c9ba8Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = read_one_line_file("/proc/cmdline", &cmdline);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error_errno(r, "Unable to read cmdline: %m");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* extract root fs so we can find disk model name in sysfs */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* FIXME: this works only in the simple case */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering c = strstr(cmdline, "root=/dev/");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (c) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering char rootbdev[4];
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering char filename[32];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering rootbdev[3] = '\0';
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering snprintf(filename, sizeof(filename), "/sys/block/%s/device/model", rootbdev);
7f0d207d2c816e0a8cb2742b0a789911f7c99356Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = read_one_line_file(filename, &model);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_info("Error reading disk model for %s: %m\n", rootbdev);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* various utsname parameters */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = uname(&uts);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Error getting uname info\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* date */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering t = time(NULL);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_se(r > 0);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* CPU type */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = read_full_file("/proc/cpuinfo", &buf, NULL);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (r < 0)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return log_error_errno(r, "Unable to read cpuinfo: %m");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering cpu = strstr(buf, "model name");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (!cpu) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering log_error("Unable to read module name from cpuinfo.\n");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return -ENOENT;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering cpu += 13;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering c = strchr(cpu, '\n');
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (c)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *c = '\0';
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uts.nodename, date);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering uts.sysname, uts.release, uts.version, uts.machine);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n", cpu);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (model)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n", model);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n", cmdline);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n", build);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"20\" y=\"140\">Idle time: ");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (idletime >= 0.0)
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering fprintf(of, "%.03fs", idletime);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering else
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering fprintf(of, "Not detected");
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering fprintf(of, "</text>\n");
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering fprintf(of, "<text class=\"sec\" x=\"20\" y=\"155\">Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered</text>\n",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering arg_hz, arg_samples_len, overrun, pscount, pfiltered);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic void svg_graph_box(FILE *of, struct list_sample_data *head, int height, double graph_start) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering double d = 0.0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int i = 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering double finalsample = 0.0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct list_sample_data *sampledata_last;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sampledata_last = head;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sampledata_last = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering finalsample = sampledata_last->sampletime;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* outside box, fill */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(0.0),
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering time_to_graph(finalsample - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ps_to_graph(height));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (d = graph_start; d <= finalsample;
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 */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (i % 50 == 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, " <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering time_to_graph(d - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(d - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ps_to_graph(height));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (i % 10 == 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, " <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering time_to_graph(d - graph_start),
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering time_to_graph(d - graph_start),
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering ps_to_graph(height));
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering else
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering time_to_graph(d - graph_start),
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering time_to_graph(d - graph_start),
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering ps_to_graph(height));
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* time label */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (i % 10 == 0)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering time_to_graph(d - graph_start),
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering -5.0, d - graph_start);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering i++;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering}
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering/* xml comments must not contain "--" */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poetteringstatic char* xml_comment_encode(const char* name) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering char *enc_name, *p;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering enc_name = strdup(name);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (!enc_name)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return NULL;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering for (p = enc_name; *p; p++)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (p[0] == '-' && p[1] == '-')
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering p[1] = '_';
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return enc_name;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering}
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic void svg_pss_graph(FILE *of,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct list_sample_data *head,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct ps_struct *ps_first,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double graph_start) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct ps_struct *ps;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct list_sample_data *sampledata_last;
a3e7f417d72ba3251fd6b3a228a2721a4b725a03Zbigniew Jędrzejewski-Szmek
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering sampledata_last = head;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sampledata_last = sampledata;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering fprintf(of, "\n\n<!-- Pss memory size graph -->\n");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering fprintf(of, "\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* vsize 1000 == 1000mb */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering svg_graph_box(of, head, 100, graph_start);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* draw some hlines for usable memory sizes */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering for (i = 100000; i < 1000000; i += 100000) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n",
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering time_to_graph(.0),
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering kb_to_graph(i),
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering time_to_graph(sampledata_last->sampletime - graph_start),
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering kb_to_graph(i));
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n",
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering time_to_graph(sampledata_last->sampletime - graph_start) + 5,
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering kb_to_graph(i), (1000000 - i) / 1000);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering fprintf(of, "\n");
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* now plot the graph itself */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering i = 1;
8d90c8a8d6867ffcfb61a11b73205cd7b1a72f3aLennart Poettering prev_sampledata = head;
8d90c8a8d6867ffcfb61a11b73205cd7b1a72f3aLennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering int bottom;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering int top;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering struct ps_sched_struct *cross_place;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering bottom = 0;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering top = 0;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* put all the small pss blocks into the bottom */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering ps = ps_first;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering while (ps->next_ps) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering ps = ps->next_ps;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (!ps)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering continue;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering ps->sample = ps->first;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (ps->sample->next) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ps->sample = ps->sample->next;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ps->sample->sampledata == sampledata)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering break;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (ps->sample->sampledata == sampledata) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (ps->sample->pss <= (100 * arg_scale_y))
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering top += ps->sample->pss;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering break;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering }
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering while (ps->sample->cross) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering cross_place = ps->sample->cross;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps = ps->sample->cross->ps_new;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->sample = cross_place;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ps->sample->pss <= (100 * arg_scale_y))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering top += ps->sample->pss;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "rgb(64,64,64)",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering time_to_graph(prev_sampledata->sampletime - graph_start),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering kb_to_graph(1000000.0 - top),
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering kb_to_graph(top - bottom));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bottom = top;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* now plot the ones that are of significant size */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ps = ps_first;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering while (ps->next_ps) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps = ps->next_ps;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!ps)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering continue;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->sample = ps->first;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (ps->sample->next) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->sample = ps->sample->next;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (ps->sample->sampledata == sampledata)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* don't draw anything smaller than 2mb */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (ps->sample->sampledata != sampledata)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (ps->sample->pss > (100 * arg_scale_y)) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering top = bottom + ps->sample->pss;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering colorwheel[ps->pid % 12],
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering time_to_graph(prev_sampledata->sampletime - graph_start),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering kb_to_graph(1000000.0 - top),
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering kb_to_graph(top - bottom));
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering bottom = top;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering break;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering while ((cross_place = ps->sample->cross)) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering ps = ps->sample->cross->ps_new;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering ps->sample = cross_place;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (ps->sample->pss > (100 * arg_scale_y)) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering top = bottom + ps->sample->pss;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering colorwheel[ps->pid % 12],
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering time_to_graph(prev_sampledata->sampletime - graph_start),
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering kb_to_graph(1000000.0 - top),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering kb_to_graph(top - bottom));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bottom = top;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering prev_sampledata = sampledata;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering i++;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* overlay all the text labels */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering i = 1;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int bottom;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int top = 0;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering struct ps_sched_struct *prev_sample;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering struct ps_sched_struct *cross_place;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* put all the small pss blocks into the bottom */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering ps = ps_first->next_ps;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering while (ps->next_ps) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering ps = ps->next_ps;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (!ps)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering continue;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering ps->sample = ps->first;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering while (ps->sample->next) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering ps->sample = ps->sample->next;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (ps->sample->sampledata == sampledata)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering break;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (ps->sample->sampledata == sampledata) {
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering if (ps->sample->pss <= (100 * arg_scale_y))
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering top += ps->sample->pss;
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering break;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering while ((cross_place = ps->sample->cross)) {
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering ps = ps->sample->cross->ps_new;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering ps->sample = cross_place;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (ps->sample->pss <= (100 * arg_scale_y))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering top += ps->sample->pss;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bottom = top;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* now plot the ones that are of significant size */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering ps = ps_first;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (ps->next_ps) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prev_sample = ps->sample;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps = ps->next_ps;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!ps)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering continue;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ps->sample = ps->first;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (ps->sample->next) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prev_sample = ps->sample;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->sample = ps->sample->next;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ps->sample->sampledata == sampledata)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* don't draw anything smaller than 2mb */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (ps->sample->sampledata == sampledata) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (ps->sample->pss > (100 * arg_scale_y)) {
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering top = bottom + ps->sample->pss;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* draw a label with the process / PID */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y)))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering time_to_graph(sampledata->sampletime - graph_start),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->name, ps->pid);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bottom = top;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while ((cross_place = ps->sample->cross)) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering ps = ps->sample->cross->ps_new;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering ps->sample = cross_place;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering prev_sample = ps->sample->prev;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering if (ps->sample->pss > (100 * arg_scale_y)) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering top = bottom + ps->sample->pss;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* draw a label with the process / PID */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y)))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(sampledata->sampletime - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->name, ps->pid);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bottom = top;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering i++;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* debug output - full data dump */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, "\n\n<!-- PSS map - csv format -->\n");
554604b3073467af75dc94fac9e2343148603289Lennart Poettering ps = ps_first;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (ps->next_ps) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _cleanup_free_ char *enc_name = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps = ps->next_ps;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (!ps)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering continue;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering enc_name = xml_comment_encode(ps->name);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (!enc_name)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering continue;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fprintf(of, "<!-- %s [%d] pss=", enc_name, ps->pid);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->sample = ps->first;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (ps->sample->next) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ps->sample = ps->sample->next;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering fprintf(of, "%d," , ps->sample->pss);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering fprintf(of, " -->\n");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic void svg_io_bi_bar(FILE *of,
554604b3073467af75dc94fac9e2343148603289Lennart Poettering struct list_sample_data *head,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int n_samples,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double graph_start,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double interval) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double max = 0.0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double range;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering int max_here = 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering int i;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering int k;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering struct list_sample_data *start_sampledata;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering struct list_sample_data *stop_sampledata;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- IO utilization graph - In -->\n");
554604b3073467af75dc94fac9e2343148603289Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - read</text>\n");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /*
554604b3073467af75dc94fac9e2343148603289Lennart Poettering * calculate rounding range
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering *
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * We need to round IO data since IO block data is not updated on
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering * each poll. Applying a smoothing function loses some burst data,
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering * so keep the smoothing range short.
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering */
554604b3073467af75dc94fac9e2343148603289Lennart Poettering range = 0.25 / (1.0 / arg_hz);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (range < 2.0)
554604b3073467af75dc94fac9e2343148603289Lennart Poettering range = 2.0; /* no smoothing */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* surrounding box */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering svg_graph_box(of, head, 5, graph_start);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering /* find the max IO first */
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering i = 1;
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering int start;
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering int stop;
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering int diff;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering double tot;
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering start = MAX(i - ((range / 2) - 1), 0);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering stop = MIN(i + (range / 2), n_samples - 1);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering diff = (stop - start);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering start_sampledata = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering stop_sampledata = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (k = 0; k < ((range/2) - 1) && start_sampledata->link_next; k++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering start_sampledata = start_sampledata->link_next;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering stop_sampledata = stop_sampledata->link_prev;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (tot > max) {
554604b3073467af75dc94fac9e2343148603289Lennart Poettering max = tot;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering max_here = i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (tot > max)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering max = tot;
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering /* plot bi */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering i = 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prev_sampledata = head;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering int start;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int stop;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int diff;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering double tot;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double pbi = 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering start = MAX(i - ((range / 2) - 1), 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering stop = MIN(i + (range / 2), n_samples);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering diff = (stop - start);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering start_sampledata = sampledata;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering stop_sampledata = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering start_sampledata = start_sampledata->link_next;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering stop_sampledata = stop_sampledata->link_prev;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (max > 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering pbi = tot / max;
554604b3073467af75dc94fac9e2343148603289Lennart Poettering
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (pbi > 0.001)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<rect class=\"bi\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
554604b3073467af75dc94fac9e2343148603289Lennart Poettering time_to_graph(prev_sampledata->sampletime - graph_start),
554604b3073467af75dc94fac9e2343148603289Lennart Poettering (arg_scale_y * 5) - (pbi * (arg_scale_y * 5)),
554604b3073467af75dc94fac9e2343148603289Lennart Poettering time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
554604b3073467af75dc94fac9e2343148603289Lennart Poettering pbi * (arg_scale_y * 5));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* labels around highest value */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (i == max_here) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering time_to_graph(sampledata->sampletime - graph_start) + 5,
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering ((arg_scale_y * 5) - (pbi * (arg_scale_y * 5))) + 15,
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering max / 1024.0 / (interval / 1000000000.0));
86b8d289717bad2800342efca0a5023aa8374e9cLennart Poettering }
c49b30a23583ff39daaa26696bcab478d2fee0bbLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering i++;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prev_sampledata = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void svg_io_bo_bar(FILE *of,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct list_sample_data *head,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int n_samples,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double graph_start,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double interval) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering double max = 0.0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering double range;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int max_here = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int k;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct list_sample_data *start_sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering struct list_sample_data *stop_sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- IO utilization graph - out -->\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - write</text>\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /*
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * calculate rounding range
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering *
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * We need to round IO data since IO block data is not updated on
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * each poll. Applying a smoothing function loses some burst data,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * so keep the smoothing range short.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering range = 0.25 / (1.0 / arg_hz);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (range < 2.0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering range = 2.0; /* no smoothing */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* surrounding box */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering svg_graph_box(of, head, 5, graph_start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* find the max IO first */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering i = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int start;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering int stop;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering int diff;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering double tot;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering start = MAX(i - ((range / 2) - 1), 0);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering stop = MIN(i + (range / 2), n_samples - 1);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering diff = (stop - start);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering start_sampledata = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering stop_sampledata = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (k = 0; k < (range/2) - 1 && start_sampledata->link_next; k++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering start_sampledata = start_sampledata->link_next;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering stop_sampledata = stop_sampledata->link_prev;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (tot > max)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering max = tot;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (tot > max) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering max = tot;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering max_here = i;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering i++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
de58a50e24a0d55e3bbcc77f8f6170a7322acf52Lennart Poettering /* plot bo */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering prev_sampledata = head;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering i = 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int start, stop, diff;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering double tot, pbo;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering pbo = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering start = MAX(i - ((range / 2) - 1), 0);
a658cafa98ab55ea948c29bc87eb3945d515fb41Lennart Poettering stop = MIN(i + (range / 2), n_samples);
de58a50e24a0d55e3bbcc77f8f6170a7322acf52Lennart Poettering diff = (stop - start);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering start_sampledata = sampledata;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering stop_sampledata = sampledata;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering start_sampledata = start_sampledata->link_next;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering stop_sampledata = stop_sampledata->link_prev;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering / diff;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (max > 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering pbo = tot / max;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (pbo > 0.001)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<rect class=\"bo\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering time_to_graph(prev_sampledata->sampletime - graph_start),
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (arg_scale_y * 5) - (pbo * (arg_scale_y * 5)),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering pbo * (arg_scale_y * 5));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* labels around highest bo value */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (i == max_here) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering time_to_graph(sampledata->sampletime - graph_start) + 5,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ((arg_scale_y * 5) - (pbo * (arg_scale_y * 5))),
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering max / 1024.0 / (interval / 1000000000.0));
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering i++;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering prev_sampledata = sampledata;
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void svg_cpu_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<!-- CPU utilization graph -->\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (cpu_num < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] utilization</text>\n");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] utilization</text>\n", cpu_num);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* surrounding box */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering svg_graph_box(of, head, 5, graph_start);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek /* bars for each sample, proportional to the CPU util. */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering prev_sampledata = head;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering LIST_FOREACH_BEFORE(link, sampledata, head) {
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek int c;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double trt;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering double ptrt;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ptrt = trt = 0.0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (cpu_num < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (c = 0; c < n_cpus; c++)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering trt += sampledata->runtime[c] - prev_sampledata->runtime[c];
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering else
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering trt = sampledata->runtime[cpu_num] - prev_sampledata->runtime[cpu_num];
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering trt = trt / 1000000000.0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek if (cpu_num < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering trt = trt / (double)n_cpus;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek if (trt > 0.0)
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek ptrt = trt / (sampledata->sampletime - prev_sampledata->sampletime);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek if (ptrt > 1.0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering ptrt = 1.0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek if (ptrt > 0.001)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
bd16acf35e13a19cd2ded0a0c2ef774a98f73808Zbigniew Jędrzejewski-Szmek time_to_graph(prev_sampledata->sampletime - graph_start),
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)),
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers ptrt * (arg_scale_y * 5));
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers prev_sampledata = sampledata;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers }
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers}
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sieversstatic void svg_wait_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) {
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers fprintf(of, "<!-- Wait time aggregation box -->\n");
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (cpu_num < 0)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] wait</text>\n");
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers else
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] wait</text>\n", cpu_num);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers /* surrounding box */
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers svg_graph_box(of, head, 5, graph_start);
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers /* bars for each sample, proportional to the CPU util. */
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers prev_sampledata = head;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers LIST_FOREACH_BEFORE(link, sampledata, head) {
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers int c;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers double twt;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers double ptwt;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers ptwt = twt = 0.0;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (cpu_num < 0)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers for (c = 0; c < n_cpus; c++)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers twt += sampledata->waittime[c] - prev_sampledata->waittime[c];
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers else
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers twt = sampledata->waittime[cpu_num] - prev_sampledata->waittime[cpu_num];
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers twt = twt / 1000000000.0;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (cpu_num < 0)
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers twt = twt / (double)n_cpus;
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers
ab49725fd8587ef2b90dd0a67b2c915bc772d089Kay Sievers if (twt > 0.0)
ptwt = twt / (sampledata->sampletime - prev_sampledata->sampletime);
if (ptwt > 1.0)
ptwt = 1.0;
if (ptwt > 0.001)
fprintf(of, "<rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(prev_sampledata->sampletime - graph_start),
((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))),
time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
ptwt * (arg_scale_y * 5));
prev_sampledata = sampledata;
}
}
static void svg_entropy_bar(FILE *of, struct list_sample_data *head, double graph_start) {
fprintf(of, "<!-- entropy pool graph -->\n");
fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Entropy pool size</text>\n");
/* surrounding box */
svg_graph_box(of, head, 5, graph_start);
/* bars for each sample, scale 0-4096 */
prev_sampledata = head;
LIST_FOREACH_BEFORE(link, sampledata, head) {
fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(prev_sampledata->sampletime - graph_start),
((arg_scale_y * 5) - ((sampledata->entropy_avail / 4096.) * (arg_scale_y * 5))),
time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
(sampledata->entropy_avail / 4096.) * (arg_scale_y * 5));
prev_sampledata = sampledata;
}
}
static struct ps_struct *get_next_ps(struct ps_struct *ps, struct ps_struct *ps_first) {
/*
* 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 && ps->parent->next)
return ps->parent->next;
ps = ps->parent;
if (!ps)
return ps;
}
return NULL;
}
static bool ps_filter(struct ps_struct *ps) {
if (!arg_filter)
return false;
/* can't draw data when there is only 1 sample (need start + stop) */
if (ps->first == ps->last)
return true;
/* don't filter kthreadd */
if (ps->pid == 2)
return false;
/* drop stuff that doesn't use any real CPU time */
if (ps->total <= 0.001)
return true;
return 0;
}
static void svg_do_initcall(FILE *of, struct list_sample_data *head, int count_only, double graph_start) {
_cleanup_pclose_ FILE *f = NULL;
double t;
char func[256];
int ret;
int usecs;
/* can't plot initcall when disabled or in relative mode */
if (!arg_initcall || arg_relative) {
kcount = 0;
return;
}
if (!count_only) {
fprintf(of, "<!-- initcall -->\n");
fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Kernel init threads</text>\n");
/* surrounding box */
svg_graph_box(of, head, kcount, graph_start);
}
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;
}
fprintf(of, "<!-- thread=\"%s\" time=\"%.3f\" elapsed=\"%d\" result=\"%d\" -->\n",
func, t, usecs, ret);
if (usecs < 1000)
continue;
/* rect */
fprintf(of, " <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 */
fprintf(of, " <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(FILE *of,
struct list_sample_data *head,
int n_samples,
int n_cpus,
struct ps_struct *ps_first,
double graph_start,
double interval) {
struct ps_struct *ps;
int i = 0;
int j = 0;
int pid;
double w = 0.0;
fprintf(of, "<!-- Process graph -->\n");
fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Processes</text>\n");
/* surrounding box */
svg_graph_box(of, head, pcount, graph_start);
/* pass 2 - ps boxes */
ps = ps_first;
while ((ps = get_next_ps(ps, ps_first))) {
_cleanup_free_ char *enc_name = NULL, *escaped = NULL;
double endtime;
double starttime;
int t;
if (!utf8_is_printable(ps->name, strlen(ps->name)))
escaped = utf8_escape_non_printable(ps->name);
enc_name = xml_comment_encode(escaped ? escaped : ps->name);
if (!enc_name)
continue;
/* leave some trace of what we actually filtered etc. */
fprintf(of, "<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", enc_name, ps->pid,
ps->ppid, ps->total);
starttime = ps->first->sampledata->sampletime;
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 if (ps->parent){
/* 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))
fprintf(of, " <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;
}
endtime = ps->last->sampledata->sampletime;
fprintf(of, " <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(ps->last->sampledata->sampletime - starttime),
ps_to_graph(1));
/* paint cpu load over these */
ps->sample = ps->first;
t = 1;
while (ps->sample->next) {
double rt, prt;
double wt, wrt;
struct ps_sched_struct *prev;
prev = ps->sample;
ps->sample = ps->sample->next;
/* calculate over interval */
rt = ps->sample->runtime - prev->runtime;
wt = ps->sample->waittime - prev->waittime;
prt = (rt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime);
wrt = (wt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime);
/* 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;
fprintf(of, " <rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(prev->sampledata->sampletime - graph_start),
ps_to_graph(j),
time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
ps_to_graph(wrt));
/* draw cpu over wait - TODO figure out how/why run + wait > interval */
fprintf(of, " <rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
time_to_graph(prev->sampledata->sampletime - graph_start),
ps_to_graph(j + (1.0 - prt)),
time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
ps_to_graph(prt));
t++;
}
/* determine where to display the process name */
if ((endtime - starttime) < 1.5)
/* too small to fit label inside the box */
w = endtime;
else
w = starttime;
/* text label of process name */
fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan> %s</text>\n",
time_to_graph(w - graph_start) + 5.0,
ps_to_graph(j) + 14.0,
escaped ? escaped : ps->name,
ps->pid,
(ps->last->runtime - ps->first->runtime) / 1000000000.0,
arg_show_cgroup ? ps->cgroup : "");
/* paint lines to the parent process */
if (ps->parent) {
/* horizontal part */
fprintf(of, " <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)
fprintf(of, " <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 */
fprintf(of, "\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;
}
/* need to know last node first */
ps->sample = ps->first;
i = ps->sample->next->sampledata->counter;
while (ps->sample->next && i<(n_samples-(arg_hz/2))) {
double crt;
double brt;
int c;
int ii;
struct ps_sched_struct *sample_hz;
ps->sample = ps->sample->next;
sample_hz = ps->sample;
for (ii = 0; (ii < (int)arg_hz/2) && sample_hz->next; ii++)
sample_hz = sample_hz->next;
/* subtract bootchart cpu utilization from total */
crt = 0.0;
for (c = 0; c < n_cpus; c++)
crt += sample_hz->sampledata->runtime[c] - ps->sample->sampledata->runtime[c];
brt = sample_hz->runtime - ps->sample->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 = ps->sample->sampledata->sampletime - graph_start;
fprintf(of, "\n<!-- idle detected at %.03f seconds -->\n", idletime);
fprintf(of, "<line class=\"idle\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
time_to_graph(idletime),
-arg_scale_y,
time_to_graph(idletime),
ps_to_graph(pcount) + arg_scale_y);
fprintf(of, "<text class=\"idle\" x=\"%.03f\" y=\"%.03f\">%.01fs</text>\n",
time_to_graph(idletime) + 5.0,
ps_to_graph(pcount) + arg_scale_y,
idletime);
break;
}
i++;
}
}
static void svg_top_ten_cpu(FILE *of, struct ps_struct *ps_first) {
struct ps_struct *top[10];
struct ps_struct emptyps = {};
struct ps_struct *ps;
int n, m;
for (n = 0; n < (int) ELEMENTSOF(top); n++)
top[n] = &emptyps;
/* walk all ps's and setup ptrs */
ps = ps_first;
while ((ps = get_next_ps(ps, ps_first))) {
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;
}
}
fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top CPU consumers:</text>\n");
for (n = 0; n < 10; n++)
fprintf(of, "<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(FILE *of, struct ps_struct *ps_first) {
struct ps_struct *top[10];
struct ps_struct emptyps = {};
struct ps_struct *ps;
int n, m;
for (n = 0; n < (int) ELEMENTSOF(top); n++)
top[n] = &emptyps;
/* walk all ps's and setup ptrs */
ps = ps_first;
while ((ps = get_next_ps(ps, ps_first))) {
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;
}
}
fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top PSS consumers:</text>\n");
for (n = 0; n < 10; n++)
fprintf(of, "<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);
}
int svg_do(FILE *of,
const char *build,
struct list_sample_data *head,
struct ps_struct *ps_first,
int n_samples,
int pscount,
int n_cpus,
double graph_start,
double log_start,
double interval,
int overrun) {
struct ps_struct *ps;
double offset = 7;
int r, c;
sampledata = head;
LIST_FIND_TAIL(link, sampledata, head);
ps = ps_first;
/* count initcall thread count first */
svg_do_initcall(of, head, 1, graph_start);
ksize = kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0;
/* then count processes */
while ((ps = get_next_ps(ps, ps_first))) {
if (!ps_filter(ps))
pcount++;
else
pfiltered++;
}
psize = ps_to_graph(pcount) + (arg_scale_y * 2);
esize = (arg_entropy ? arg_scale_y * 7 : 0);
/* after this, we can draw the header with proper sizing */
svg_header(of, head, graph_start, arg_percpu ? n_cpus : 0);
fprintf(of, "<rect class=\"bg\" width=\"100%%\" height=\"100%%\" />\n\n");
fprintf(of, "<g transform=\"translate(10,400)\">\n");
svg_io_bi_bar(of, head, n_samples, graph_start, interval);
fprintf(of, "</g>\n\n");
fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
svg_io_bo_bar(of, head, n_samples, graph_start, interval);
fprintf(of, "</g>\n\n");
for (c = -1; c < (arg_percpu ? n_cpus : 0); c++) {
offset += 7;
fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
svg_cpu_bar(of, head, n_cpus, c, graph_start);
fprintf(of, "</g>\n\n");
offset += 7;
fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
svg_wait_bar(of, head, n_cpus, c, graph_start);
fprintf(of, "</g>\n\n");
}
if (kcount) {
offset += 7;
fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
svg_do_initcall(of, head, 0, graph_start);
fprintf(of, "</g>\n\n");
}
offset += 7;
fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize);
svg_ps_bars(of, head, n_samples, n_cpus, ps_first, graph_start, interval);
fprintf(of, "</g>\n\n");
fprintf(of, "<g transform=\"translate(10, 0)\">\n");
r = svg_title(of, build, pscount, log_start, overrun);
fprintf(of, "</g>\n\n");
if (r < 0)
return r;
fprintf(of, "<g transform=\"translate(10,200)\">\n");
svg_top_ten_cpu(of, ps_first);
fprintf(of, "</g>\n\n");
if (arg_entropy) {
fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize);
svg_entropy_bar(of, head, graph_start);
fprintf(of, "</g>\n\n");
}
if (arg_pss) {
fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize + esize);
svg_pss_graph(of, head, ps_first, graph_start);
fprintf(of, "</g>\n\n");
fprintf(of, "<g transform=\"translate(410,200)\">\n");
svg_top_ten_pss(of, ps_first);
fprintf(of, "</g>\n\n");
}
/* fprintf footer */
fprintf(of, "\n</svg>\n");
return 0;
}