File: bootchartd

package info (click to toggle)
bootchart 0.10~svn407-3
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 1,032 kB
  • ctags: 875
  • sloc: java: 7,236; sh: 417; xml: 73; makefile: 48
file content (261 lines) | stat: -rwxr-xr-x 6,773 bytes parent folder | download | duplicates (2)
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
#!/bin/sh
#
# Bootchart logger script
# Ziga Mahkovec  <ziga.mahkovec@klika.si>
#
# This script is used for data collection for the bootchart
# boot performance visualization tool (http://www.bootchart.org).
#
# To profile the boot process, bootchartd should be called instead of
# /sbin/init.  Modify the kernel command line to include:
# init=/sbin/bootchartd
#
# 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
#

PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH"
VERSION="0.8"

# Lock file
BOOTLOG_LOCK=".lock"

# 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


# Start the boot logger.
start()
{
	# Mount the temporary file system for log file storage.  If possible,
	# a temporary directory is created.  In most cases though (i.e. during
	# boot), a tmpfs is mounted in /mnt.  The mount point is immediately
	# released using a lazy umount, so the script must never leave that
	# directory.
	LOG_DIR="$( mktemp -d /tmp/bootchart.XXXXXX 2>/dev/null )"
	if [ -z "$LOG_DIR" ]; then
		LOG_DIR="/mnt"
		LAZY_UMOUNT="yes"
		mount -n -t tmpfs -o size=$TMPFS_SIZE none "$LOG_DIR" >/dev/null 2>&1
	fi
	cd "$LOG_DIR"
	> "$BOOTLOG_LOCK"
	[ -n "$LAZY_UMOUNT" ] && umount -nfl "$LOG_DIR"

	# Enable process accounting if configured
	if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
		> kernel_pacct
		accton kernel_pacct
	fi
	
	#
	# Run loggers in background
	#
	log_output "cat /proc/stat" proc_stat.log &

	# /proc/diskstats is available in 2.6 kernels
	log_output "cat /proc/diskstats" proc_diskstats.log &

	log_output "cat /proc/*/stat" proc_ps.log &
	#log_output "ps -eww -o pid,ppid,s,pcpu,comm,cmd" ps.log &

	# Uncomment this line for diskless stations
	#log_output "cat /proc/net/dev" proc_netdev.log &

	if [ -n "$IN_INIT" ]; then
		if [ "$AUTO_STOP_LOGGER" = "yes" ]; then
			# If we were called during init, wait for the boot process to end
			wait_boot &
		fi
	elif [ "$#" -gt 0 ]; then
		# If a command was passed, run it
		# (used for profiling specific applications)
		echo "profile.process = $( basename $1 )" >> header
		$@
		stop
	else
		echo "profile.process = (all)" >> header
	fi
}


# Run the command ($1) every $SAMPLE_PERIOD seconds and append output to
# file ($2).  Mostly pure bash, so we avoid creating an excessive number of
# processes (thus polluting the process tree).
log_output()
{
	# Set the stop() trap.
	trap trapstop USR1

	local cmd="$1"
	local logfile="$2"
	while [ -f "$BOOTLOG_LOCK" ]; do
		# Write the time (in jiffies).
		read uptime < /proc/uptime
		uptime=${uptime%% [0-9]*}
		uptime=${uptime%.*}${uptime#*.}
		echo $uptime

		# Log the command output
		eval $cmd 2>/dev/null
		echo
		sleep $SAMPLE_PERIOD
	done  >> "$logfile" || stop
}

# 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="gdmgreeter gdm-binary kdm_greet kdm"
	# 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 [ "$runlevel" -eq "2" -o "$runlevel" -eq "3" -o "$early_login" = "yes" ]; then
		exit_proc="mingetty agetty rungetty getty fgetty"
	fi
	while [ -f "$BOOTLOG_LOCK" ]; do
		if [ -n "$( pidof $exit_proc )" ]; then
			# Give the exit process some time to start
			sleep 5
			# Flush the log files
			stop
			return
		fi
		sleep 2
	done;
}

trapstop()
{
  stop
}

# Stop the boot logger.  The lock file is removed to force the loggers in
# background to exit.  Some final log files are created and then all log files
# from the tmpfs are packaged and stored in $BOOTLOG_DEST.
stop()
{
	if [ ! -f "$BOOTLOG_LOCK" ]; then
		echo "${0##*/} not running"
		return
	fi
	# Prevent concurrent stop() calls
	rm -f "$BOOTLOG_LOCK" || return
	sleep $SAMPLE_PERIOD
	sleep $SAMPLE_PERIOD

	# Stop process accounting if configured
	local pacct=
	if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
		accton
		pacct=kernel_pacct
	fi

	# Write system information
	log_header

	# Package log files
	tar -zcf "$BOOTLOG_DEST" header $pacct *.log
	if [ -z "$LAZY_UMOUNT" ]; then
		rm "$LOG_DIR"/*
		rmdir "$LOG_DIR"
	fi

	# Render the chart if configured (and the renderer is installed)
	[ "$AUTO_RENDER" = "yes" -a -x /usr/bin/bootchart ] && \
		/usr/bin/bootchart -o "$AUTO_RENDER_DIR" -f $AUTO_RENDER_FORMAT "$BOOTLOG_DEST"
}


# Log some basic information about the system.
log_header()
{
	(
		echo "version = $VERSION"
		echo "title = Boot chart for $( hostname | sed q ) ($( date ))"
		echo "system.uname = $( uname -srvm | sed q )"
		if [ -f /etc/gentoo-release ]; then
			echo "system.release = $( sed q /etc/gentoo-release )"
		elif [ -f /etc/SuSE-release ]; then
			echo "system.release = $( sed q /etc/SuSE-release )"
		elif [ -f /etc/debian_version ]; then
			echo "system.release = Debian GNU/$( uname -s ) $( cat /etc/debian_version )"
		elif [ -f /etc/frugalware-release ]; then
			echo "system.release = $( sed q /etc/frugalware-release )"
		elif [ -f /etc/pardus-release ]; then
			echo "system.release = $( sed q /etc/pardus-release )"
		else
			echo "system.release = $( sed 's/\\.//g;q' /etc/issue )"
		fi

		# Get CPU count
		local cpucount=$(grep -c '^processor' /proc/cpuinfo)
		if [ $cpucount -gt 1 -a -n "$(grep 'sibling.*2' /proc/cpuinfo)" ]; then
			# Hyper-Threading enabled
			cpucount=$(( $cpucount / 2 ))
		fi
		if grep -q '^model name' /proc/cpuinfo; then
			echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q )"\
			     "($cpucount)"
		else
			echo "system.cpu = $( grep '^cpu' /proc/cpuinfo | sed q )"\
			     "($cpucount)"
		fi

		echo "system.kernel.options = $( sed q /proc/cmdline )"
	) >> header
}

if [ $$ -eq 1 ]; then
	# Started by the kernel.  Start the logger in background and exec
	# init(1).
	IN_INIT="yes"
	echo "Starting bootchart logging"
	start
	
	# Optionally, an alternative init(1) process may be specified using
	# the kernel command line (e.g. "bootchart_init=/sbin/initng")
	init="${bootchart_init}"
	if [ -z "$init" ]; then
		init="/sbin/init"
	fi
	exec $init $*
fi

case "$1" in
	"init")
		# Started by the init script
		IN_INIT="yes"
		echo "Starting bootchart logging"
		start &
		;;
	"start")
		# Started by the user
		shift
		start $@
		;;
	"stop")
		# We get the signal, too. But we ignore it.
		trap : USR1
		# Signal all background processes to stop logging
		killall --exact -USR1 bootchartd
		;;
	*)
		echo "Usage: $0 {init|start|stop}"
		;;
esac