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