update to 1.20 [release 1.20-1mamba;Sat Dec 01 2012]
This commit is contained in:
parent
77cf926d60
commit
53cad0810a
@ -1,2 +1,10 @@
|
||||
# bootchart
|
||||
|
||||
Bootchart is a tool for performance analysis and visualization of the GNU/Linux boot process.
|
||||
Resource utilization and process information are collected during the boot process and are later rendered in a PNG, SVG or EPS encoded chart.
|
||||
Bootchart provides a shell script to be run by the kernel in the init phase.
|
||||
The script will run in background and collect process information, CPU statistics and disk usage statistics from the /proc file system.
|
||||
The performance data are stored in memory and are written to disk once the boot process completes.
|
||||
The boot log file is later processed using a Java application (or the web form) which builds the process tree and renders a performance chart in different formats: SVG e EPS.
|
||||
The chart can then be analyzed to examine process dependency and overall resource utilization.
|
||||
|
||||
|
37
bootchart-0.9-nojavafunctions.patch
Normal file
37
bootchart-0.9-nojavafunctions.patch
Normal file
@ -0,0 +1,37 @@
|
||||
--- bootchart-0.9/script/bootchart.orig 2006-06-26 16:03:51.000000000 +0200
|
||||
+++ bootchart-0.9/script/bootchart 2006-06-26 16:07:21.000000000 +0200
|
||||
@@ -4,21 +4,23 @@
|
||||
# JPackage Project <http://www.jpackage.org/>
|
||||
|
||||
# Source functions library
|
||||
-if [ -f /usr/share/java-utils/java-functions ] ; then
|
||||
- . /usr/share/java-utils/java-functions
|
||||
-else
|
||||
- echo "Can't find functions library, aborting"
|
||||
- exit 1
|
||||
-fi
|
||||
+#if [ -f /usr/share/java-utils/java-functions ] ; then
|
||||
+# . /usr/share/java-utils/java-functions
|
||||
+#else
|
||||
+# echo "Can't find functions library, aborting"
|
||||
+# exit 1
|
||||
+#fi
|
||||
|
||||
# Configuration
|
||||
MAIN_CLASS="org.bootchart.Main"
|
||||
-BASE_JARS="commons-cli.jar bootchart.jar"
|
||||
-FLAGS="-Djava.awt.headless=true -Dgnu.java.awt.peer.gtk.Graphics=Graphics2D"
|
||||
+BASE_JARS="/usr/share/java/bootchart.jar"
|
||||
+#BASE_JARS="commons-cli.jar bootchart.jar"
|
||||
+#FLAGS="-Djava.awt.headless=true -Dgnu.java.awt.peer.gtk.Graphics=Graphics2D"
|
||||
|
||||
# Set parameters
|
||||
-set_jvm
|
||||
-set_classpath $BASE_JARS
|
||||
+#set_jvm
|
||||
+#set_classpath $BASE_JARS
|
||||
|
||||
# Let's start
|
||||
-run "$@"
|
||||
+#run "$@"
|
||||
+java -cp $BASE_JARS $MAIN_CLASS $@
|
15
bootchart-0.9-svg_path.patch
Normal file
15
bootchart-0.9-svg_path.patch
Normal file
@ -0,0 +1,15 @@
|
||||
--- bootchart-0.9/bootchart.pl.orig 2006-06-26 11:33:31.000000000 +0200
|
||||
+++ bootchart-0.9/bootchart.pl 2006-06-26 11:35:22.000000000 +0200
|
||||
@@ -37,9 +37,9 @@
|
||||
my %ps_info;
|
||||
my %ps_by_parent;
|
||||
|
||||
-my $chart_svg_template = `cat svg/bootchart.svg.template` || die;
|
||||
-my $process_svg_template = `cat svg/process.svg.template` || die;
|
||||
-my $svg_css_file = `cat svg/style.css` || die;
|
||||
+my $chart_svg_template = `cat /usr/share/bootchart/svg/bootchart.svg.template` || die;
|
||||
+my $process_svg_template = `cat /usr/share/bootchart/svg/process.svg.template` || die;
|
||||
+my $svg_css_file = `cat /usr/share/bootchart/svg/style.css` || die;
|
||||
$svg_css_file =~ s/^/\t\t\t/mg;
|
||||
$svg_css_file =~ s/^\s+//g;
|
||||
|
120
bootchart-grub2
Normal file
120
bootchart-grub2
Normal file
@ -0,0 +1,120 @@
|
||||
#! /bin/sh -e
|
||||
|
||||
# update-grub helper script, modified for bootchart entry.
|
||||
# Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
|
||||
#
|
||||
# GRUB 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, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
prefix=/usr
|
||||
exec_prefix=/usr
|
||||
libdir=/usr/lib
|
||||
. ${libdir}/grub/grub-mkconfig_lib
|
||||
|
||||
if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
|
||||
OS=GNU/Linux
|
||||
else
|
||||
OS="${GRUB_DISTRIBUTOR} GNU/Linux"
|
||||
fi
|
||||
|
||||
test_numeric ()
|
||||
{
|
||||
local a=$1
|
||||
local cmp=$2
|
||||
local b=$3
|
||||
if [ "$a" = "$b" ] ; then
|
||||
case $cmp in
|
||||
ge|eq|le) return 0 ;;
|
||||
gt|lt) return 1 ;;
|
||||
esac
|
||||
fi
|
||||
if [ "$cmp" = "lt" ] ; then
|
||||
c=$a
|
||||
a=$b
|
||||
b=$c
|
||||
fi
|
||||
if (echo $a ; echo $b) | sort -n | head -n 1 | grep -qx $b ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
test_gt ()
|
||||
{
|
||||
local a=`echo $1 | sed -e "s/vmlinu[zx]-//g"`
|
||||
local b=`echo $2 | sed -e "s/vmlinu[zx]-//g"`
|
||||
local cmp=gt
|
||||
if [ "x$b" = "x" ] ; then
|
||||
return 0
|
||||
fi
|
||||
case $a:$b in
|
||||
*.old:*.old) ;;
|
||||
*.old:*) a=`echo -n $a | sed -e s/\.old$//g` ; cmp=gt ;;
|
||||
*:*.old) b=`echo -n $b | sed -e s/\.old$//g` ; cmp=ge ;;
|
||||
esac
|
||||
test_numeric $a $cmp $b
|
||||
return $?
|
||||
}
|
||||
|
||||
find_latest ()
|
||||
{
|
||||
local a=""
|
||||
for i in $@ ; do
|
||||
if test_gt "$i" "$a" ; then
|
||||
a="$i"
|
||||
fi
|
||||
done
|
||||
echo "$a"
|
||||
}
|
||||
|
||||
list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do
|
||||
if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
|
||||
done`
|
||||
|
||||
while [ "x$list" != "x" ] ; do
|
||||
linux=`find_latest $list`
|
||||
echo "Found linux image: $linux" >&2
|
||||
basename=`basename $linux`
|
||||
dirname=`dirname $linux`
|
||||
grub_dirname=`echo ${dirname} | sed -e "s%^/boot%${GRUB_DRIVE_BOOT}%g"`
|
||||
version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
|
||||
alt_version=`echo $version | sed -e "s,\.old$,,g"`
|
||||
|
||||
initrd=
|
||||
for i in "initramfs.img-${version}" "initramfs-${version}.img" \
|
||||
"initramfs.img-${alt_version}" "initramfs-${alt_version}.img"; do
|
||||
if test -e "${dirname}/${i}" ; then
|
||||
initrd="$i"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "${initrd}" ; then
|
||||
echo "Found initrd image: ${dirname}/${initrd}" >&2
|
||||
fi
|
||||
|
||||
cat << EOF
|
||||
menuentry "${OS}, linux ${version} (bootchart)" {
|
||||
linux ${grub_dirname}/${basename} root=${GRUB_DEVICE} ro ${GRUB_CMDLINE_LINUX} init=/sbin/bootchartd
|
||||
EOF
|
||||
if test -n "${initrd}" ; then
|
||||
cat << EOF
|
||||
initrd ${grub_dirname}/${initrd}
|
||||
EOF
|
||||
fi
|
||||
cat << EOF
|
||||
}
|
||||
EOF
|
||||
|
||||
list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
|
||||
done
|
49
bootchart.sh
Normal file
49
bootchart.sh
Normal file
@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Bootchart shell script - use the web renderer for bootchart
|
||||
#
|
||||
# Copyright (c) 2006 by Stefano Cotta Ramusino <stefano.cotta@qilinux.it>
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
format="png"
|
||||
output_dir="."
|
||||
else
|
||||
if [[ "$1" == "png" || "$1" == "svg" || "$1" == "eps" ]]; then
|
||||
format=$1
|
||||
else
|
||||
echo "$0 : invalid format. Try: png, svg or eps"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -d "$2" ]]; then
|
||||
output_dir=$2
|
||||
else
|
||||
echo "$0: output directory not found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
bootchart_log="/var/log/bootchart.tgz"
|
||||
webrenderer_url="http://render.bootchart.org:8080/bootchart/render"
|
||||
|
||||
if [ ! -f "$bootchart_log" ]; then
|
||||
echo "$0: bootchart log not found."
|
||||
echo "Try adding \`init=/sbin/bootchartd' to your kernel entries in grub configuration file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $format == "svg" ]; then
|
||||
output_ext_file="svgz"
|
||||
else
|
||||
if [ $format == "eps" ]; then
|
||||
output_ext_file="eps.gz"
|
||||
else
|
||||
output_ext_file=$format
|
||||
fi
|
||||
fi
|
||||
|
||||
curl \
|
||||
--form format=$format \
|
||||
--form log=@$bootchart_log \
|
||||
$webrenderer_url > $output_dir/bootchart.$output_ext_file
|
||||
|
||||
exit $?
|
203
bootchart.spec
Normal file
203
bootchart.spec
Normal file
@ -0,0 +1,203 @@
|
||||
Name: bootchart
|
||||
Version: 1.20
|
||||
Release: 1mamba
|
||||
Summary: Bootchart is a tool for performance analysis and visualization of the GNU/Linux boot process
|
||||
Group: System/Benchmarks
|
||||
Vendor: openmamba
|
||||
Distribution: openmamba
|
||||
Packager: Stefano Cotta Ramusino <stefano.cotta@qilinux.it>
|
||||
URL: http://www.bootchart.org/
|
||||
Source: http://foo-projects.org/~sofar/bootchart/bootchart-%{version}.tar.gz
|
||||
#Source: http://downloads.sourceforge.net/sourceforge/bootchart/bootchart-%{version}.tar.bz2
|
||||
Source1: http://zerodeux.net/misc/bootchart/bootchart_pl
|
||||
Source2: bootchart.sh
|
||||
Source3: kbootchart
|
||||
Source4: kbootchart.png
|
||||
Source5: bootchart-grub2
|
||||
Patch0: %{name}-0.9-nojavafunctions.patch
|
||||
Patch1: %{name}-0.9-svg_path.patch
|
||||
License: GPL
|
||||
Requires: curl
|
||||
Requires: %{name}-logger
|
||||
BuildRequires: apache-ant
|
||||
BuildRequires: jdk
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-root
|
||||
|
||||
%description
|
||||
Bootchart is a tool for performance analysis and visualization of the GNU/Linux boot process.
|
||||
Resource utilization and process information are collected during the boot process and are later rendered in a PNG, SVG or EPS encoded chart.
|
||||
Bootchart provides a shell script to be run by the kernel in the init phase.
|
||||
The script will run in background and collect process information, CPU statistics and disk usage statistics from the /proc file system.
|
||||
The performance data are stored in memory and are written to disk once the boot process completes.
|
||||
The boot log file is later processed using a Java application (or the web form) which builds the process tree and renders a performance chart in different formats: SVG e EPS.
|
||||
The chart can then be analyzed to examine process dependency and overall resource utilization.
|
||||
|
||||
%package logger
|
||||
Summary: Boot logging script for %{name}
|
||||
Group: System/Kernel and Hardware
|
||||
|
||||
%description logger
|
||||
Boot logging script for %{name}.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
#%patch0 -p1
|
||||
|
||||
cp %{S:1} %{name}.pl
|
||||
%patch1 -p1
|
||||
|
||||
%build
|
||||
#JAVA_HOME=%{_jvmdir}/jdk ANT_HOME=/opt/java/ant ant
|
||||
%configure
|
||||
%make
|
||||
|
||||
%install
|
||||
[ "%{buildroot}" != / ] && rm -rf "%{buildroot}"
|
||||
%makeinstall
|
||||
|
||||
## install scripts
|
||||
#install -D -m 755 script/%{name} \
|
||||
# %{buildroot}%{_bindir}/%{name}
|
||||
#install -D -m 755 %{name}.pl \
|
||||
# %{buildroot}%{_bindir}/%{name}.pl
|
||||
#install -D -m 755 %{S:2} \
|
||||
# %{buildroot}%{_bindir}/%{name}.sh
|
||||
#install -d %{buildroot}%{_datadir}/%{name}/svg
|
||||
#install -m 644 svg/* \
|
||||
# %{buildroot}%{_datadir}/%{name}/svg
|
||||
#
|
||||
## install java files
|
||||
#install -D -m 644 %{name}.jar \
|
||||
# %{buildroot}%{_javadir}/%{name}-%{version}.jar
|
||||
#ln -s %{name}-%{version}.jar %{buildroot}%{_javadir}/%{name}.jar
|
||||
#install -d -m 755 %{buildroot}%{_javadocdir}/%{name}-%{version}
|
||||
#cp -pr javadoc/* \
|
||||
# %{buildroot}%{_javadocdir}/%{name}-%{version}
|
||||
#ln -s %{name}-%{version} %{buildroot}%{_javadocdir}/%{name}
|
||||
|
||||
## install logger
|
||||
#install -D -m 755 script/bootchartd \
|
||||
# %{buildroot}/sbin/bootchartd
|
||||
##install -D -m 644 script/bootchartd.conf \
|
||||
# %{buildroot}%{_sysconfdir}/bootchartd.conf
|
||||
#
|
||||
# install kde frontend
|
||||
install -D -m 755 %{S:3} \
|
||||
%{buildroot}%{_bindir}/k%{name}
|
||||
install -D -m 644 %{S:4} \
|
||||
%{buildroot}%{_datadir}/icons/crystalsvg/32x32/apps/k%{name}.png
|
||||
|
||||
# install grub.d file
|
||||
install -D -m 0755 %{S:5} %{buildroot}%{_sysconfdir}/grub.d/15_bootchart
|
||||
|
||||
# create KDE menu link
|
||||
install -d %{buildroot}/%{_datadir}/applications
|
||||
cat > %{buildroot}/%{_datadir}/applications/k%{name}.desktop <<EOF
|
||||
[Desktop Entry]
|
||||
Name=KBootchart
|
||||
GenericName=Bootchart image generator
|
||||
GenericName[it]=Generatore del grafico d'avvio
|
||||
Exec=kbootchart
|
||||
Type=Application
|
||||
Icon=kbootchart
|
||||
Terminal=false
|
||||
Categories=Qt;KDE;System
|
||||
EOF
|
||||
|
||||
%clean
|
||||
[ "%{buildroot}" != / ] && rm -rf "%{buildroot}"
|
||||
|
||||
%post logger
|
||||
if [ $1 -ge 1 ]; then
|
||||
# new install or upgrade
|
||||
%if "%{_target_cpu}" == "i586"
|
||||
for i in $(ls %{_sysconfdir}/grub/conf.d/%{distribution}-* 2>/dev/null); do
|
||||
if [ $(grep init=/sbin/%{name}d $i >> /dev/null; echo $?) -ne 0 ]; then
|
||||
sed -i "s|^kernel\(.*\)|kernel \1 init=/sbin/%{name}d|" $i 2> /dev/null
|
||||
fi
|
||||
done
|
||||
%endif
|
||||
%if "%{_target_cpu}" == "ppc"
|
||||
for i in $(ls %{_sysconfdir}/yaboot/conf.d/%{distribution}-* 2>/dev/null); do
|
||||
if [ $(grep init=/sbin/%{name}d $i >> /dev/null; echo $?) -ne 0 ]; then
|
||||
sed -i "s|^append=\"\(.*\)\"|append=\"\1 init=/sbin/%{name}d\"|" $i 2> /dev/null
|
||||
fi
|
||||
done
|
||||
%endif
|
||||
fi
|
||||
|
||||
if [ $1 -eq 1 ]; then
|
||||
# new install
|
||||
%if "%{_target_cpu}" == "i586"
|
||||
[ -x /usr/sbin/update-grub ] && /usr/sbin/update-grub
|
||||
%endif
|
||||
%if "%{_target_cpu}" == "ppc"
|
||||
[ -x /usr/sbin/yaboot-update ] && /usr/sbin/yaboot-update
|
||||
%endif
|
||||
fi
|
||||
exit 0
|
||||
|
||||
%postun logger
|
||||
if [ $1 -eq 0 ]; then
|
||||
# uninstall
|
||||
%if "%{_target_cpu}" == "i586"
|
||||
for i in $(ls %{_sysconfdir}/grub/conf.d/%{distribution}-* 2>/dev/null); do
|
||||
if [ $(grep init=/sbin/%{name}d $i >> /dev/null; echo $?) -eq 0 ]; then
|
||||
sed -i "s|^kernel\(.*\) init=/sbin/%{name}d\(.*\)|kernel \1\2|" $i 2> /dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
%endif
|
||||
%if "%{_target_cpu}" == "ppc"
|
||||
for i in $(ls %{_sysconfdir}/yaboot/conf.d/%{distribution}-* 2>/dev/null); do
|
||||
if [ $(grep init=/sbin/%{name}d $i >> /dev/null; echo $?) -eq 0 ]; then
|
||||
sed -i "s|^append=\"\(.*\) init=/sbin/%{name}d\(.*\)\"|append=\"\1\2\"|" $i 2> /dev/null
|
||||
fi
|
||||
done
|
||||
%endif
|
||||
fi
|
||||
exit 0
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%{_bindir}/kbootchart
|
||||
#%{_datadir}/%{name}/svg
|
||||
#%{_javadir}/*
|
||||
%{_datadir}/applications/k%{name}.desktop
|
||||
%{_datadir}/icons/crystalsvg/32x32/apps/k%{name}.png
|
||||
#%{_javadocdir}/*
|
||||
%doc COPYING README
|
||||
#%doc TODO
|
||||
|
||||
%files logger
|
||||
%defattr(-,root,root)
|
||||
%{_sysconfdir}/grub.d/15_bootchart
|
||||
%{_sbindir}/bootchartd
|
||||
%{_datadir}/doc/bootchart/bootchartd.conf.example
|
||||
#%config(noreplace) %{_sysconfdir}/%{name}d.conf
|
||||
#%doc README.logger
|
||||
|
||||
%changelog
|
||||
* Sat Dec 01 2012 Automatic Build System <autodist@mambasoft.it> 1.20-1mamba
|
||||
- update to 1.20
|
||||
|
||||
* Mon May 09 2011 Silvan Calarco <silvan.calarco@mambasoft.it> 0.9-7mamba
|
||||
- updated grub2 configuration file to use grub-mkconfig_lib instead of deprecated update-grub_lib
|
||||
|
||||
* Fri Feb 05 2010 Silvan Calarco <silvan.calarco@mambasoft.it> 0.9-6mamba
|
||||
- rebuilt to remove executable requirements
|
||||
|
||||
* Tue Oct 14 2008 Silvan Calarco <silvan.calarco@mambasoft.it> 0.9-5mamba
|
||||
- updated for grub2
|
||||
|
||||
* Tue Oct 14 2008 Silvan Calarco <silvan.calarco@mambasoft.it> 0.9-4mamba
|
||||
- rebuilt
|
||||
|
||||
* Mon Feb 19 2007 Silvan Calarco <silvan.calarco@mambasoft.it> 0.9-3qilnx
|
||||
- add an exit 0 to scripts
|
||||
|
||||
* Wed Nov 15 2006 Stefano Cotta Ramusino <stefano.cotta@qilinux.it> 0.9-2qilnx
|
||||
- added %%post and %%postun scriplets
|
||||
|
||||
* Mon Jun 26 2006 Stefano Cotta Ramusino <stefano.cotta@qilinux.it> 0.9-1qilnx
|
||||
- package created by autospec
|
467
bootchart_pl
Normal file
467
bootchart_pl
Normal file
@ -0,0 +1,467 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# A basic perl port of the bootchart renderer, SVG only
|
||||
# (c) 2005 Vincent Caron <v.caron@zerodeux.net>
|
||||
|
||||
# This program 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; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
# BUGS
|
||||
# - ignore number of CPUs (disk util.)
|
||||
|
||||
# 2005-06-29 - fixes
|
||||
# - process name is latest sample argv value
|
||||
# - sibling processes are properly PID-sorted from top to bottom
|
||||
# - process start is now parsed from proc_ps
|
||||
# - hiding bootchartd-related processes
|
||||
#
|
||||
# 2005-06-28
|
||||
# - initial release
|
||||
|
||||
use strict;
|
||||
|
||||
my %headers;
|
||||
my @disk_samples;
|
||||
my @cpu_samples;
|
||||
my %ps_info;
|
||||
my %ps_by_parent;
|
||||
|
||||
my $chart_svg_template = `cat svg/bootchart.svg.template` || die;
|
||||
my $process_svg_template = `cat svg/process.svg.template` || die;
|
||||
my $svg_css_file = `cat svg/style.css` || die;
|
||||
$svg_css_file =~ s/^/\t\t\t/mg;
|
||||
$svg_css_file =~ s/^\s+//g;
|
||||
|
||||
my $HZ = 100;
|
||||
my $min_img_w = 800;
|
||||
my $sec_w = 25;
|
||||
my $proc_h = 16;
|
||||
my $header_h = 300;
|
||||
my $img_w;
|
||||
my $img_h;
|
||||
my $t_begin;
|
||||
my $t_end;
|
||||
my $t_dur;
|
||||
|
||||
|
||||
sub parse_logs {
|
||||
my $logfile = shift;
|
||||
my $tmp = "/tmp/bootchart-$$";
|
||||
|
||||
mkdir $tmp or die;
|
||||
system "cd $tmp && tar xzf $logfile";
|
||||
|
||||
parse_log_header($tmp);
|
||||
parse_log_cpu($tmp);
|
||||
parse_log_disk($tmp);
|
||||
parse_log_ps($tmp);
|
||||
|
||||
system('rm', '-rf', $tmp);
|
||||
print STDERR "Disk samples: ".scalar(@disk_samples)."\n";
|
||||
print STDERR "CPU samples : ".scalar(@cpu_samples)."\n";
|
||||
print STDERR "Processes : ".scalar(keys %ps_info)."\n";
|
||||
}
|
||||
|
||||
sub parse_log_header {
|
||||
my $tmp = shift;
|
||||
|
||||
open(HEADER, "<$tmp/header");
|
||||
while (<HEADER>) {
|
||||
chomp;
|
||||
my ($key, $val) = split /\s*=\s*/, $_, 2;
|
||||
$headers{$key} = $val;
|
||||
}
|
||||
close HEADER;
|
||||
}
|
||||
|
||||
sub parse_log_cpu {
|
||||
my $tmp = shift;
|
||||
|
||||
# Reads in: time, user, system, iowait
|
||||
my ($time, $ltime);
|
||||
my (@timings, @ltimings);
|
||||
|
||||
open(PROC_STAT, "<$tmp/proc_stat.log");
|
||||
while (<PROC_STAT>) {
|
||||
chomp;
|
||||
$time = $1, next if /^(\d+)$/;
|
||||
|
||||
if (/^$/) {
|
||||
if (defined $ltime) {
|
||||
my $dtime = ($time - $ltime) / $HZ; # in seconds
|
||||
my $user = ($timings[0] + $timings[1]) - ($ltimings[0] + $ltimings[1]);
|
||||
my $system = ($timings[2] + $timings[5] + $timings[6]) - ($ltimings[2] + $ltimings[5] + $ltimings[6]);
|
||||
my $idle = $timings[3] - $ltimings[3];
|
||||
my $iowait = $timings[4] - $ltimings[4];
|
||||
my $sum = $user + $system + $idle + $iowait;
|
||||
my %sample;
|
||||
$sample{time} = $time;
|
||||
$sample{user} = $user / $sum;
|
||||
$sample{system} = $system / $sum;
|
||||
$sample{iowait} = $iowait / $sum;
|
||||
push @cpu_samples, \%sample;
|
||||
}
|
||||
|
||||
$ltime = $time;
|
||||
@ltimings = @timings;
|
||||
next;
|
||||
}
|
||||
|
||||
@timings = split /\s+/ if s/^cpu\s+//;
|
||||
}
|
||||
close(PROC_STAT);
|
||||
}
|
||||
|
||||
sub parse_log_disk {
|
||||
my $tmp = shift;
|
||||
|
||||
# Reads in: time, read, write, use
|
||||
my ($time, $ltime);
|
||||
my ($read, $write, $util) = (0, 0, 0);
|
||||
my ($lread, $lwrite, $lutil);
|
||||
|
||||
open(DISK_STAT, "<$tmp/proc_diskstats.log");
|
||||
while (<DISK_STAT>) {
|
||||
chomp;
|
||||
$time = $1, next if /^(\d+)$/;
|
||||
|
||||
if (/^$/) {
|
||||
if (defined $ltime) {
|
||||
my $dtime = ($time - $ltime) / $HZ; # in seconds
|
||||
my $dutil = ($util - $lutil) / (1000 * $dtime);
|
||||
|
||||
my %sample;
|
||||
$sample{time} = $time;
|
||||
$sample{read} = ($read - $lread) / 2 / $dtime; # in KB/s
|
||||
$sample{write} = ($write - $lwrite) / 2 / $dtime; # in KB/s
|
||||
$sample{util} = ($dutil > 1 ? 1 : $dutil);
|
||||
push @disk_samples, \%sample;
|
||||
}
|
||||
|
||||
$ltime = $time;
|
||||
$lread = $read, $read = 0;
|
||||
$lwrite = $write, $write = 0;
|
||||
$lutil = $util, $util = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
s/\s+//;
|
||||
my @tokens = split /\s+/;
|
||||
next if scalar(@tokens) != 14 || not $tokens[2] =~ /hd|sd/;
|
||||
|
||||
$read += $tokens[5];
|
||||
$write += $tokens[9];
|
||||
$util += $tokens[12];
|
||||
}
|
||||
close(DISK_STAT);
|
||||
}
|
||||
|
||||
sub parse_log_ps {
|
||||
my $tmp = shift;
|
||||
|
||||
my $time;
|
||||
|
||||
open(PS_STAT, "<$tmp/proc_ps.log");
|
||||
while (<PS_STAT>) {
|
||||
chomp;
|
||||
next if /^$/;
|
||||
$time = $1, next if /^(\d+)$/;
|
||||
|
||||
my @tokens = split /\s+/;
|
||||
my $pid = $tokens[0];
|
||||
|
||||
if (!defined $ps_info{$pid}) {
|
||||
my %info;
|
||||
my @empty;
|
||||
my $ppid = $tokens[3];
|
||||
my $start = $tokens[21];
|
||||
$t_begin = $start if !defined $t_begin || $t_begin > $start;
|
||||
|
||||
$info{ppid} = $ppid;
|
||||
$info{start} = $start;
|
||||
$info{samples} = \@empty;
|
||||
$ps_info{$pid} = \%info;
|
||||
|
||||
if (!defined $ps_by_parent{$ppid}) {
|
||||
my @pidlist = ($pid);
|
||||
$ps_by_parent{$ppid} = \@pidlist;
|
||||
} else {
|
||||
push @{$ps_by_parent{$ppid}}, $pid;
|
||||
}
|
||||
}
|
||||
|
||||
# argv may change, we'll store here the last sampled value
|
||||
my $comm = $tokens[1];
|
||||
$comm =~ s/[()]//g;
|
||||
$ps_info{$pid}->{comm} = $comm;
|
||||
|
||||
my %sample;
|
||||
$sample{time} = $time;
|
||||
$sample{state} = $tokens[2];
|
||||
$sample{sys} = $tokens[13];
|
||||
$sample{user} = $tokens[14];
|
||||
push @{$ps_info{$pid}->{samples}}, \%sample;
|
||||
}
|
||||
close PS_STAT;
|
||||
}
|
||||
|
||||
sub unxml {
|
||||
my $x = shift;
|
||||
$x =~ s/</</g;
|
||||
$x =~ s/>/>/g;
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
sub render_svg {
|
||||
my $t_init = $cpu_samples[0]->{time};
|
||||
$t_end = $cpu_samples[-1]->{time};
|
||||
$t_dur = $t_end - $t_begin;
|
||||
$img_w = $t_dur / $HZ * $sec_w;
|
||||
|
||||
my @subst;
|
||||
$subst[1] = $svg_css_file;
|
||||
|
||||
#
|
||||
# Headers
|
||||
#
|
||||
|
||||
my $cpu = $headers{'system.cpu'};
|
||||
$cpu =~ s/model name\s*:\s*//;
|
||||
$subst[2] = unxml($headers{title});
|
||||
$subst[3] = "uname: ".unxml($headers{'system.uname'});
|
||||
$subst[4] = "release: ".unxml($headers{'system.release'});
|
||||
$subst[5] = "CPU: ".unxml($cpu);
|
||||
$subst[6] = "kernel options: ".unxml($headers{'system.kernel.options'});
|
||||
$subst[7] = "boot time: ".int($t_end / $HZ)." seconds";
|
||||
|
||||
#
|
||||
# CPU I/O chart
|
||||
#
|
||||
|
||||
my $bar_h = 50;
|
||||
my $cpu_ticks = '';
|
||||
for (my $i = 0; $i < $t_dur / $HZ; $i++) {
|
||||
my $x = $i * $sec_w;
|
||||
$cpu_ticks .= "<line ".($i % 5 ? "" : "class=\"Bold\" ")."x1=\"$x\" y1=\"0\" x2=\"$x\" y2=\"$bar_h\"/>\n";
|
||||
}
|
||||
$cpu_ticks =~ s/^/\t\t\t/mg; $cpu_ticks =~ s/^\s+//g;
|
||||
|
||||
my $io_points = '';
|
||||
my $cpu_points = '';
|
||||
|
||||
if (@cpu_samples) {
|
||||
my $last_x = 0;
|
||||
|
||||
for (@cpu_samples) {
|
||||
my $time = $_->{time};
|
||||
my $iowait = $_->{iowait};
|
||||
my $usersys = $_->{user} + $_->{system};
|
||||
|
||||
my $pos_x = int(($time - $t_begin) * $img_w / $t_dur);
|
||||
my $pos_y = int($bar_h - ($usersys + $iowait) * $bar_h);
|
||||
$io_points .= "$pos_x,$bar_h" if $io_points eq '';
|
||||
$io_points .= " $pos_x,$pos_y";
|
||||
|
||||
$pos_y = int($bar_h - $usersys * $bar_h);
|
||||
$cpu_points .= "$pos_x,$bar_h" if $cpu_points eq '';
|
||||
$cpu_points .= " $pos_x,$pos_y";
|
||||
|
||||
$last_x = $pos_x;
|
||||
}
|
||||
$io_points .= " $last_x,$bar_h";
|
||||
$cpu_points .= " $last_x,$bar_h";
|
||||
}
|
||||
|
||||
$subst[8] = $cpu_ticks;
|
||||
$subst[9] = $io_points;
|
||||
$subst[10] = $cpu_points;
|
||||
|
||||
#
|
||||
# Disk usage chart
|
||||
#
|
||||
|
||||
my $util_points = '';
|
||||
my $read_points = '';
|
||||
|
||||
if (@disk_samples) {
|
||||
my $max_tput = 0;
|
||||
my $max_tput_label = '';
|
||||
for (@disk_samples) {
|
||||
my $put = $_->{read} + $_->{write};
|
||||
$max_tput = $put if $put > $max_tput;
|
||||
}
|
||||
|
||||
my $last_x = 0;
|
||||
my $last_y = 0;
|
||||
|
||||
for (@disk_samples) {
|
||||
my $time = $_->{time};
|
||||
my $read = $_->{read};
|
||||
my $write = $_->{write};
|
||||
my $util = $_->{util};
|
||||
|
||||
my $pos_x = int(($time - $t_begin) * $img_w / $t_dur);
|
||||
my $pos_y = int($bar_h - $util * $bar_h);
|
||||
$util_points .= "$pos_x,$bar_h" if $util_points eq '';
|
||||
$util_points .= " $pos_x,$pos_y";
|
||||
|
||||
$pos_y = int($bar_h - ($read + $write) / $max_tput * $bar_h);
|
||||
if ($read_points ne '') {
|
||||
$read_points .= "\t\t\t<line x1=\"$last_x\" y1=\"$last_y\" x2=\"$pos_x\" y2=\"$pos_y\"/>";
|
||||
}
|
||||
$read_points .= "\n";
|
||||
|
||||
if ($max_tput_label eq '' && $read + $write == $max_tput) {
|
||||
my $label = int($max_tput / 1024)." MB/s";
|
||||
$max_tput_label = "\t\t\t<text class=\"DiskLabel\" x=\"$pos_x\" y=\"0\" dx=\"-".(length($label) / 3)."em\" dy=\"-2px\">$label</text>\n";
|
||||
}
|
||||
|
||||
$last_x = $pos_x;
|
||||
$last_y = $pos_y;
|
||||
}
|
||||
$util_points .= " $last_x,$bar_h";
|
||||
$read_points .= $max_tput_label;
|
||||
}
|
||||
|
||||
$subst[11] = $cpu_ticks;
|
||||
$subst[12] = $util_points;
|
||||
$subst[13] = $read_points;
|
||||
$subst[14] = ''; # open_points, no openfile parser implemented
|
||||
|
||||
#
|
||||
# Process tree
|
||||
#
|
||||
|
||||
my $tree_h = scalar(@cpu_samples) * $proc_h;
|
||||
my $axis = '';
|
||||
my $proc_ticks = '';
|
||||
for (my $i = 0; $i < $t_dur / $HZ; $i++) {
|
||||
my $x = $i * $sec_w;
|
||||
$proc_ticks .= "<line ".($i % 5 ? "" : "class=\"Bold\" ")."x1=\"$x\" y1=\"0\" x2=\"$x\" y2=\"$tree_h\"/>\n";
|
||||
if ($i > 0 && $i % 5 == 0) {
|
||||
my $label = $i.'s';
|
||||
$axis .= "<text class=\"AxisLabel\" x=\"$x\" y=\"0\" dx=\"-".(length($label) / 4)."\" dy=\"-3\">$label</text>\n";
|
||||
}
|
||||
}
|
||||
$proc_ticks =~ s/^/\t\t\t/mg; $proc_ticks =~ s/^\s+//g;
|
||||
$axis =~ s/^/\t\t\t/mg; $axis =~ s/^\s+//g;
|
||||
|
||||
my $proc_tree = '';
|
||||
my @init = (1);
|
||||
my $ps_count = 0;
|
||||
$proc_tree = render_proc_tree(\@init, \$ps_count);
|
||||
|
||||
$subst[15] = $axis;
|
||||
$subst[16] = $proc_ticks;
|
||||
$subst[17] = $proc_tree;
|
||||
|
||||
$img_h = $proc_h * $ps_count + $header_h;
|
||||
$subst[0] = 'width="'.($img_w > $min_img_w ? $img_w : $min_img_w).'px" height="'.($img_h + 1).'px"';
|
||||
|
||||
print template_subst($chart_svg_template, @subst);
|
||||
}
|
||||
|
||||
sub render_proc_tree {
|
||||
my $ps_list = shift;
|
||||
my $ps_count = shift;
|
||||
my $level = shift || 0;
|
||||
|
||||
my $proc_tree = '';
|
||||
for (sort {$a <=> $b} @{$ps_list}) {
|
||||
# Hide bootchartd and its children processes
|
||||
next if $ps_info{$_}->{comm} eq 'bootchartd';
|
||||
|
||||
my $children = $ps_by_parent{$_};
|
||||
$proc_tree .= render_proc($_, $ps_count, $level);
|
||||
$proc_tree .= render_proc_tree($children, $ps_count, $level + 1) if defined $children;
|
||||
}
|
||||
return $proc_tree;
|
||||
}
|
||||
|
||||
sub render_proc {
|
||||
my $pid = shift;
|
||||
my $ps_count = shift;
|
||||
my $level = shift;
|
||||
|
||||
my $info = $ps_info{$pid};
|
||||
return '' if defined $info->{done}; # Draw once
|
||||
|
||||
my @samples = @{$info->{samples}};
|
||||
return '' if scalar(@samples) < 2; # Skip processes with only 1 sample
|
||||
|
||||
my $p_begin = ($pid == 1) ? $samples[0]->{time} : $info->{start};
|
||||
my $p_period = $samples[1]->{time} - $p_begin;
|
||||
my $p_end = $samples[-1]->{time};
|
||||
my $p_dur = $p_end - $p_begin + $p_period;
|
||||
|
||||
my $x = ($p_begin - $t_begin) * $sec_w / $HZ;
|
||||
my $y = ${$ps_count} * $proc_h;
|
||||
my $w = $p_dur * $sec_w / $HZ;
|
||||
|
||||
my $position = "$x,$y";
|
||||
my $border = "width=\"$w\" height=\"$proc_h\"";
|
||||
my $timeline = "<rect class=\"Sleeping\" x=\"0\" y=\"0\" $border/>\n";
|
||||
|
||||
my ($last_tx, $last_sample);
|
||||
for my $sample (@samples) {
|
||||
my $time = $sample->{time};
|
||||
my $state = $sample->{state};
|
||||
my $tx = ($time - $p_begin) * $sec_w / $HZ;
|
||||
$tx = 0 if $tx < 0;
|
||||
|
||||
if (defined $last_sample) {
|
||||
my $tw = $tx - $last_tx;
|
||||
|
||||
if ($state ne 'S') {
|
||||
my $sys = ($sample->{sys} - $last_sample->{sys}) / $HZ;
|
||||
my $user = ($sample->{user} - $last_sample->{user}) / $HZ;
|
||||
|
||||
my %class = ('D' => 'UnintSleep', 'R' => 'Running', 'T' => 'Traced', 'Z' => 'Zombie');
|
||||
my $opacity = ($state eq 'R') ? ' fill-opacity="'.($sys + $user).'"' : '';
|
||||
$timeline .= "<rect class=\"$class{$state}\"$opacity x=\"$last_tx\" y=\"0\" width=\"$tw\" height=\"$proc_h\"/>\n";
|
||||
}
|
||||
}
|
||||
|
||||
$last_tx = $tx;
|
||||
$last_sample = $sample;
|
||||
}
|
||||
$timeline =~ s/^/\t\t/mg; $timeline =~ s/^\s+//g;
|
||||
|
||||
my $label = $info->{comm};
|
||||
my $label_pos = ($w < 200 && ($x + $w + 200) < $img_w) ?
|
||||
"dx=\"2\" dy=\"".($proc_h - 1)."\" x=\"".($w + 1)."\" y=\"0\"" :
|
||||
"dx=\"".($w / 2)."\" dy=\"".($proc_h - 1)."\" x=\"0\" y=\"0\"";
|
||||
|
||||
my @subst = ($position, $timeline, $border, '', $label_pos, $label, '');
|
||||
|
||||
$info->{done} = 1;
|
||||
${$ps_count}++;
|
||||
return template_subst($process_svg_template, @subst);
|
||||
}
|
||||
|
||||
sub template_subst {
|
||||
my $template = shift;
|
||||
|
||||
my $i = 0;
|
||||
for(@_) {
|
||||
$template =~ s/\Q{$i}\E/$_[$i]/g;
|
||||
$i++;
|
||||
}
|
||||
return $template;
|
||||
}
|
||||
|
||||
|
||||
parse_logs('/var/log/bootchart.tgz');
|
||||
render_svg();
|
78
kbootchart
Normal file
78
kbootchart
Normal file
@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# kbootchart - kde frontend for bootchart
|
||||
#
|
||||
# Copyright (c) 2006 by Stefano Cotta Ramusino <stefano.cotta@qilinux.it>
|
||||
|
||||
lang="java"
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
JRE_HOME="/usr/java/jre"
|
||||
JDK_HOME="/usr/java/jdk"
|
||||
if [ -x "$JRE_HOME/bin/java" ]; then
|
||||
JAVA_HOME=$JRE_HOME
|
||||
elif [ -x "$JDK_HOME/bin/java" ]; then
|
||||
JAVA_HOME=$JDK_HOME
|
||||
elif [[ $(host www.qilinux.org &> /dev/null; echo $?) -eq 0 ]]; then
|
||||
lang="bash"
|
||||
elif [ -x "$(which perl 2> /dev/null)" ]; then
|
||||
lang="perl"
|
||||
else
|
||||
kdialog --title "KBootchart" \
|
||||
--icon $(basename $0) \
|
||||
--error "Perl is missing in your system.\nTo create the bootchart image you need to install perl."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$lang" == "java" || "$lang" == "bash" ]]; then
|
||||
format="$(kdialog --title "KBootchart" \
|
||||
--icon $(basename $0) \
|
||||
--radiolist "Select the output image format:" \
|
||||
png "PNG" on svg "SVG" off eps "EPS" off)"
|
||||
|
||||
if [ -z "$format" ]; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
format="svg"
|
||||
fi
|
||||
|
||||
output_dir="$(kdialog --title "Select the directory where the image will be created" \
|
||||
--icon $(basename $0) \
|
||||
--getexistingdirectory ~)"
|
||||
|
||||
if [ -z "$output_dir" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $format == "svg" && $lang != "perl" ]]; then
|
||||
output_ext_file="svgz"
|
||||
else
|
||||
if [ $format == "eps" ]; then
|
||||
output_ext_file="eps.gz"
|
||||
else
|
||||
output_ext_file=$format
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$lang" == "java" ]; then
|
||||
PATH=$JAVA_HOME/bin:$PATH bootchart -f $format -o $output_dir &> /dev/null
|
||||
elif [ "$lang" == "bash" ]; then
|
||||
bootchart.sh $format $output_dir &> /dev/null
|
||||
else
|
||||
bootchart.pl > $output_dir/bootchart.$output_ext_file 2> /dev/null
|
||||
fi
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
kdialog --title "KBootchart" \
|
||||
--icon $(basename $0) \
|
||||
--error "Error during creation of image file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
kdialog --title "KBootchart" \
|
||||
--icon $(basename $0) \
|
||||
--msgbox "File bootchart.$output_ext_file successfully created"
|
||||
|
||||
exit $?
|
BIN
kbootchart.png
Normal file
BIN
kbootchart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
Loading…
Reference in New Issue
Block a user