2017-05-08 00:25:26 +03:00
#!/usr/bin/env perl
2008-09-13 20:36:06 +04:00
# Copyright 2008, Intel Corporation
#
# This file is part of the Linux kernel
#
# This program file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; version 2 of the License.
#
# This program 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 General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#
# Authors:
# Arjan van de Ven <arjan@linux.intel.com>
#
# This script turns a dmesg output into a SVG graphic that shows which
# functions take how much time. You can view SVG graphics with various
# programs, including Inkscape, The Gimp and Firefox.
#
#
# For this script to work, the kernel needs to be compiled with the
# CONFIG_PRINTK_TIME configuration option enabled, and with
# "initcall_debug" passed on the kernel command line.
#
# usage:
# dmesg | perl scripts/bootgraph.pl > output.svg
#
2008-10-14 17:18:07 +04:00
use strict ;
2014-04-02 23:39:52 +04:00
use Getopt::Long ;
my $ header = 0 ;
sub help {
my $ text = << "EOM" ;
Usage:
1 ) dmesg | perl scripts / bootgraph . pl [ OPTION ] > output . svg
2 ) perl scripts / bootgraph . pl - h
Options:
- header Insert kernel version and date
EOM
my $ std = shift ;
if ( $ std == 1 ) {
print STDERR $ text ;
} else {
print $ text ;
}
exit ;
}
GetOptions (
'h|help' = > \ & help ,
'header' = > \ $ header
) ;
2008-10-14 17:18:07 +04:00
my % start ;
my % end ;
2009-01-10 21:03:05 +03:00
my % type ;
2008-09-13 20:36:06 +04:00
my $ done = 0 ;
my $ maxtime = 0 ;
2011-06-10 01:40:10 +04:00
my $ firsttime = 99999 ;
2008-09-13 20:36:06 +04:00
my $ count = 0 ;
2008-10-04 23:35:48 +04:00
my % pids ;
2009-01-10 21:03:05 +03:00
my % pidctr ;
2008-10-04 23:35:48 +04:00
2014-04-02 23:39:52 +04:00
my $ headerstep = 20 ;
my $ xheader = 15 ;
my $ yheader = 25 ;
my $ cyheader = 0 ;
2008-09-13 20:36:06 +04:00
while ( < > ) {
my $ line = $ _ ;
2009-02-15 12:20:30 +03:00
if ( $ line =~ /([0-9\.]+)\] calling ([a-zA-Z0-9\_\.]+)\+/ ) {
2008-09-13 20:36:06 +04:00
my $ func = $ 2 ;
if ( $ done == 0 ) {
$ start { $ func } = $ 1 ;
2009-01-10 21:03:05 +03:00
$ type { $ func } = 0 ;
2008-09-15 02:30:52 +04:00
if ( $ 1 < $ firsttime ) {
$ firsttime = $ 1 ;
}
2008-09-13 20:36:06 +04:00
}
if ( $ line =~ /\@ ([0-9]+)/ ) {
2008-10-04 23:35:48 +04:00
$ pids { $ func } = $ 1 ;
2008-09-13 20:36:06 +04:00
}
$ count = $ count + 1 ;
}
2009-01-10 21:03:05 +03:00
if ( $ line =~ /([0-9\.]+)\] async_waiting @ ([0-9]+)/ ) {
my $ pid = $ 2 ;
my $ func ;
if ( ! defined ( $ pidctr { $ pid } ) ) {
$ func = "wait_" . $ pid . "_1" ;
$ pidctr { $ pid } = 1 ;
} else {
$ pidctr { $ pid } = $ pidctr { $ pid } + 1 ;
$ func = "wait_" . $ pid . "_" . $ pidctr { $ pid } ;
}
if ( $ done == 0 ) {
$ start { $ func } = $ 1 ;
$ type { $ func } = 1 ;
if ( $ 1 < $ firsttime ) {
$ firsttime = $ 1 ;
}
}
$ pids { $ func } = $ pid ;
$ count = $ count + 1 ;
}
2009-02-15 12:20:30 +03:00
if ( $ line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_\.]+)\+.*returned/ ) {
2008-09-13 20:36:06 +04:00
if ( $ done == 0 ) {
$ end { $ 2 } = $ 1 ;
$ maxtime = $ 1 ;
}
}
2009-01-10 21:03:05 +03:00
if ( $ line =~ /([0-9\.]+)\] async_continuing @ ([0-9]+)/ ) {
my $ pid = $ 2 ;
my $ func = "wait_" . $ pid . "_" . $ pidctr { $ pid } ;
$ end { $ func } = $ 1 ;
$ maxtime = $ 1 ;
}
2008-09-13 20:36:06 +04:00
if ( $ line =~ /Write protecting the/ ) {
$ done = 1 ;
}
2008-09-15 02:30:52 +04:00
if ( $ line =~ /Freeing unused kernel memory/ ) {
$ done = 1 ;
}
2008-09-13 20:36:06 +04:00
}
if ( $ count == 0 ) {
2008-11-13 19:33:00 +03:00
print STDERR << END ;
No data found in the dmesg . Make sure that 'printk.time=1' and
'initcall_debug' are passed on the kernel command line .
END
2014-04-02 23:39:52 +04:00
help ( 1 ) ;
2008-11-13 19:33:00 +03:00
exit 1 ;
2008-09-13 20:36:06 +04:00
}
print "<?xml version=\"1.0\" standalone=\"no\"?> \n" ;
2009-01-04 18:16:38 +03:00
print "<svg width=\"2000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n" ;
2008-09-13 20:36:06 +04:00
2014-04-02 23:39:52 +04:00
if ( $ header ) {
my $ version = `uname -a` ;
my $ date = `date` ;
print "<text transform=\"translate($xheader,$yheader)\">Kernel version: $version</text>\n" ;
$ cyheader = $ yheader + $ headerstep ;
print "<text transform=\"translate($xheader,$cyheader)\">Date: $date</text>\n" ;
}
2008-09-13 20:36:06 +04:00
my @ styles ;
$ styles [ 0 ] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 1 ] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 2 ] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 3 ] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 4 ] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 5 ] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 6 ] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 7 ] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 8 ] = "fill:rgb(255,0,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 9 ] = "fill:rgb(255,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 10 ] = "fill:rgb(255,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
$ styles [ 11 ] = "fill:rgb(128,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)" ;
2009-01-10 21:03:05 +03:00
my $ style_wait = "fill:rgb(128,128,128);fill-opacity:0.5;stroke-width:0;stroke:rgb(0,0,0)" ;
2009-01-04 18:16:38 +03:00
my $ mult = 1950.0 / ( $ maxtime - $ firsttime ) ;
my $ threshold2 = ( $ maxtime - $ firsttime ) / 120.0 ;
my $ threshold = $ threshold2 / 10 ;
2008-09-13 20:36:06 +04:00
my $ stylecounter = 0 ;
2008-10-04 23:35:48 +04:00
my % rows ;
my $ rowscount = 1 ;
2008-10-14 17:19:15 +04:00
my @ initcalls = sort { $ start { $ a } <=> $ start { $ b } } keys ( % start ) ;
2008-11-12 21:21:01 +03:00
foreach my $ key ( @ initcalls ) {
2008-09-13 20:36:06 +04:00
my $ duration = $ end { $ key } - $ start { $ key } ;
if ( $ duration >= $ threshold ) {
2009-01-04 18:16:38 +03:00
my ( $ s , $ s2 , $ s3 , $ e , $ w , $ y , $ y2 , $ style ) ;
2008-10-14 17:18:07 +04:00
my $ pid = $ pids { $ key } ;
2008-10-04 23:35:48 +04:00
if ( ! defined ( $ rows { $ pid } ) ) {
$ rows { $ pid } = $ rowscount ;
$ rowscount = $ rowscount + 1 ;
}
2008-10-14 17:19:15 +04:00
$ s = ( $ start { $ key } - $ firsttime ) * $ mult ;
2008-09-13 20:36:06 +04:00
$ s2 = $ s + 6 ;
2009-01-04 18:16:38 +03:00
$ s3 = $ s + 1 ;
2008-09-15 02:30:52 +04:00
$ e = ( $ end { $ key } - $ firsttime ) * $ mult ;
2008-09-13 20:36:06 +04:00
$ w = $ e - $ s ;
2008-10-04 23:35:48 +04:00
$ y = $ rows { $ pid } * 150 ;
2008-09-13 20:36:06 +04:00
$ y2 = $ y + 4 ;
$ style = $ styles [ $ stylecounter ] ;
$ stylecounter = $ stylecounter + 1 ;
if ( $ stylecounter > 11 ) {
$ stylecounter = 0 ;
} ;
2009-01-10 21:03:05 +03:00
if ( $ type { $ key } == 1 ) {
$ y = $ y + 15 ;
print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"115\" style=\"$style_wait\"/>\n" ;
2009-01-04 18:16:38 +03:00
} else {
2009-01-10 21:03:05 +03:00
print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"145\" style=\"$style\"/>\n" ;
if ( $ duration >= $ threshold2 ) {
print "<text transform=\"translate($s2,$y2) rotate(90)\">$key</text>\n" ;
} else {
print "<text transform=\"translate($s3,$y2) rotate(90)\" font-size=\"3pt\">$key</text>\n" ;
}
2009-01-04 18:16:38 +03:00
}
2008-09-13 20:36:06 +04:00
}
}
# print the time line on top
2008-09-15 02:30:52 +04:00
my $ time = $ firsttime ;
my $ step = ( $ maxtime - $ firsttime ) / 15 ;
2008-09-13 20:36:06 +04:00
while ( $ time < $ maxtime ) {
2008-10-14 17:18:07 +04:00
my $ s3 = ( $ time - $ firsttime ) * $ mult ;
2008-09-15 02:30:52 +04:00
my $ tm = int ( $ time * 100 ) / 100.0 ;
2008-10-14 17:18:07 +04:00
print "<text transform=\"translate($s3,89) rotate(90)\">$tm</text>\n" ;
2008-09-15 02:30:52 +04:00
$ time = $ time + $ step ;
2008-09-13 20:36:06 +04:00
}
print "</svg>\n" ;