forked from xrmx/bootchart
-
Notifications
You must be signed in to change notification settings - Fork 1
/
bootchartd
executable file
·336 lines (297 loc) · 8.49 KB
/
bootchartd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#!/bin/bash
#
# Bootchart logger script
# Ziga Mahkovec <ziga.mahkovec@klika.si>
# Michael Meeks <michael.meeks@novell.com>
#
# This script is used for data collection for the bootchart2
# boot performance visualization tool.
#
# To profile the boot process, bootchartd should be called instead of
# /sbin/init. Modify the kernel command line to include:
#
# init=/sbin/bootchartd initcall_debug printk.time=y quiet
#
# bootchartd will then start itself in background and exec /sbin/init
# (or an alternative init process if specified using bootchart_init=)
#
# To profile a running system, run:
# $ /sbin/bootchartd start; sleep 30; /sbin/bootchartd stop
#
# Whack everything in a handy tmpfs: /dev ...
JAIL_INITRD="/dev/.bootchart"
JAIL_MAIN="/tmp/.bootchart"
# we need to find our tools
PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH"
# Read configuration.
CONF="/etc/bootchartd.conf"
if [ -f $PWD/bootchartd.conf ]; then
. $PWD/bootchartd.conf
elif [ -f $CONF ]; then
. $CONF
else
echo "$CONF missing"
exit 1
fi
# 'which' rather fails to work, with no PATH set
if [ -x "/sbin/accton" ]; then
ACCTON=/sbin/accton
elif [ -x "/usr/sbin/accton" ]; then
ACCTON=/usr/sbin/accton
else
echo "No accton - though it is configured";
PROCESS_ACCOUNTING="no"
fi
# Start the boot logger.
start()
{
# we have no control over the (usually rather mindless) scripts
# that will mount, and populate /dev - however we have to wait
# for them; otherwise we can't share the /dev tmpfs for our logs
# and have to modify each system to mount --move our file-system.
while [ ! -e /dev/console ] || [ ! -e /dev/random ]; do
usleep 5000
done
if [ ! -d $JAIL ]; then
mkdir -p $JAIL
fi
cd $JAIL
# use dmsg for debugging
if [ ! -c kmsg ]; then
mknod kmsg c 1 11
fi
echo "bootchartd started" >> kmsg
# Mount a copy of /proc just for us ...
if [ ! -d "proc" ]; then
mkdir proc
fi
if [ ! -f "proc/stat" ]; then
mount -n -t proc none proc
fi
# If we were started during the initrd, -but- we have no
# init=/sbin/bootchart, then there will be no-one to stop
# the collector will just keep
# running with no-one to stop it, so bail here.
if [ "$JAIL" == "$JAIL_INITRD" ]; then
if ! grep -q init=/sbin/bootchartd proc/cmdline; then
echo "aborting initrd bootchart setup - init not set."
umount proc
return
fi
fi
# setup the jail so we can run the collector inside it [ why bother !? ]
if [ -n "$IN_INIT" ]; then
echo "bootchartd init" >> kmsg
if [ "`uname -m`" = "x86_64" ]
then
mkdir $JAIL/lib64
cp /lib64/ld-linux-x86-64.so.* $JAIL/lib64
else
mkdir -p $JAIL/lib
cp /lib/ld-linux.so.* $JAIL/lib
fi
cp /lib/libc.so.* $JAIL/lib
mkdir $JAIL/lib/bootchart
cp /lib/bootchart/bootchart-collector $JAIL/lib/bootchart
fi
# Enable process accounting if configured
if [ ! -f kernel_pacct ]; then
if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
> kernel_pacct
$ACCTON kernel_pacct
echo "bootchartd pacct started" >> kmsg
fi
fi
# Ensure we don't start ourselves a second time during init
if [ -e proc_stat.log ]; then
echo "bootchart collector already running" >> kmsg
# Otherwise start in a chroot jail
elif [ -n "$IN_INIT" ]; then
chroot $JAIL /lib/bootchart/bootchart-collector -p proc $SAMPLE_HZ # 2>/dev/null &
# Otherwise, manually launched to profile something
else
/lib/bootchart/bootchart-collector -p proc $SAMPLE_HZ &
if [ "$#" -gt 0 ]; then
# If a command was passed, run it
# (used for profiling specific applications)
echo "profile.process = $( basename $1 )" >> header
$@
stop
# else
# manual start/stop - wait for a 'stop'
fi
fi
}
# Wait for the boot process to end.
wait_boot()
{
local runlevel=$( sed -n 's/.*:\(.*\):initdefault:.*/\1/gp' /etc/inittab )
# The processes we have to wait for
local exit_proc="kdm_greet xterm konsole metacity mutter compiz"
# Don't exit until *all* the mandatory procs are running. Only used if exit_proc
# is unset.
local mandatory_procs="nautilus mutter"
# Wait for /proc first - without it we have issues
while [ ! -e /proc/cmdline ]; do
usleep 5000
done
# early_login in FC4 starts gdm early, so fall back to mingetty
local early_login="no"
grep -q early_login proc/cmdline && early_login="yes"
if [ "x$runlevel" = "x2" -o "x$runlevel" = "x3" -o "$early_login" = "yes" ]; then
exit_proc="mingetty agetty rungetty getty"
fi
while true; do
if [ -n "$exit_proc" -a -n "$( pidof $exit_proc )" ]; then
# give an unambiguous settle afterwards - so we get
# more post-login data for slow systems
sleep 20
# Write / flush the log files
stop
return
fi
usleep 200000
done;
}
#
# This is all madness; the collector should store it's sample data
# in memory, and write it out only when triggered: after the
# system is up. Then having another mount over the top of it's
# root is no issue.
#
find_jail()
{
if [ -d $JAIL_INITRD ]; then
if [ ! -d $JAIL_MAIN ] || [ $JAIL_INITRD -nt $JAIL_MAIN ]; then
JAIL=$JAIL_INITRD;
return
fi
fi
JAIL=$JAIL_MAIN;
}
# Stop the boot logger.
# Some final log files are created and then all log files
# from the tmpfs are packaged and stored in $BOOTLOG_DEST.
stop()
{
pkill -f /lib/bootchart/bootchart-collector
sleep 2
# try harder in case it hung
pkill -9 -f /lib/bootchart/bootchart-collector
# Stop process accounting if configured
local pacct=
if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
accton
pacct=kernel_pacct
fi
find_jail
if [ ! -d $JAIL ]; then
echo "Can't find bootchart output in $JAIL - aborting"
exit 1
fi
cd $JAIL
# Write system information
log_header
# get kernel messages for kernel init logging
dmesg > dmesg
# cleanup
rm -f kmsg
umount proc
rmdir proc
tar -zcf "$BOOTLOG_DEST" header dmesg $pacct *.log
rm -f header dmesg $pacct *.log
rm -Rf $JAIL/lib
cd ..
rmdir $JAIL
# Render the chart if configured (and the renderer is installed)
if [ "$AUTO_RENDER" = "yes" -a -x /usr/bin/pybootchartgui ]; then
cd $AUTO_RENDER_DIR
/usr/bin/pybootchartgui -o "$AUTO_RENDER_DIR"/bootchart.$AUTO_RENDER_FORMAT -f $AUTO_RENDER_FORMAT "$BOOTLOG_DEST"
fi
}
# Log some basic information about the system.
log_header()
{
if [ -x "/usr/bin/dpkg-query" ]; then
version="$(dpkg-query -f'${Version}' -W bootchart)"
else
version="$(rpm -q bootchart --queryformat '%{VERSION}')"
fi
( echo "version = $version"
echo "title = Boot chart for $(hostname) ($(date))"
echo "system.uname = $(uname -srvm)"
echo "system.release = $(lsb_release -sd)"
echo "system.cpu = $(grep '^model name' proc/cpuinfo)"\
"($(grep -c '^model name' proc/cpuinfo))"
echo "system.kernel.options = $(sed q proc/cmdline)"
) > header
}
if [ $$ -eq 1 ]; then
# Either started by the kernel - in which case, we start the
# logger in background and exec init [ re-using this pid (1) ]
# Or - started after the initrd has completed, in which case
# we try to do nothing much.
IN_INIT="yes"
echo "Starting bootchart logging"
JAIL=$JAIL_INITRD
# Are we running in the initrd ?
if [ ! -e /dev/random ]; then
start &
else # running inside the main system
echo "acute oddness - why can't we detect this !?" >> /dev/kmsg
ls -al /dev >> /dev/kmsg
if [ -c /dev/.bootchart/kmsg ]; then
echo "bootchart - has kmsg" >> /dev/kmsg
fi
if [ -d /dev/.bootchart ]; then
echo "bootchart: start wait for completion" >> /dev/kmsg
wait_boot &
else # perhaps we had no initrd
JAIL=$JAIL_MAIN
echo "bootchart: no initrd used; starting" >> /dev/kmsg
start &
# wait a little, until the collector is going, before allowing
# the rest of the system to charge ahead, so we catch it
usleep 500000
echo "bootchart continuing boot" >> /dev/kmsg
wait_boot &
fi
fi
# Optionally, an alternative init(1) process may be specified using
# the kernel command line (e.g. "bootchart_init=/sbin/initng")
init="/sbin/init"
for i in $@; do
if [ "${i%%=*}" = "bootchart_init" ]; then
init="${i#*=}"
break
fi
if [ "${i%%=*}" = "init" ]; then
_init=${i#*=}
if test "$_init" != "/sbin/bootchartd"; then
init="$_init"
fi
break
fi
done
export PATH=$OLDPATH
# switch to - either the initrd's init, or the main system's
exec $init $*
fi
find_jail
case "$1" in
"start")
# Started by the user
shift
start $@
;;
"wait")
# Wait for boot
wait_boot
;;
"stop")
stop
;;
*)
echo $"Usage: $0 {init|start|stop}"
;;
esac