summaryrefslogtreecommitdiff
path: root/init/bootchartd.c
diff options
context:
space:
mode:
Diffstat (limited to 'init/bootchartd.c')
-rw-r--r--init/bootchartd.c154
1 files changed, 125 insertions, 29 deletions
diff --git a/init/bootchartd.c b/init/bootchartd.c
index d1f9ed30e..1ed4f99fc 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -2,7 +2,58 @@
2/* 2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
4 */ 4 */
5
6//config:config BOOTCHARTD
7//config: bool "bootchartd"
8//config: default y
9//config: help
10//config: bootchartd is commonly used to profile the boot process
11//config: for the purpose of speeding it up. In this case, it is started
12//config: by the kernel as the init process. This is configured by adding
13//config: the init=/sbin/bootchartd option to the kernel command line.
14//config:
15//config: It can also be used to monitor the resource usage of a specific
16//config: application or the running system in general. In this case,
17//config: bootchartd is started interactively by running bootchartd start
18//config: and stopped using bootchartd stop.
19//config:
20//config:config FEATURE_BOOTCHARTD_BLOATED_HEADER
21//config: bool "bootchartd"
22//config: default y
23//config: depends on BOOTCHARTD
24//config: help
25//config: Create extended header file compatible with "big" bootchartd.
26//config: "Big" bootchartd is a shell script and it dumps some
27//config: "convenient" info int the header, such as:
28//config: title = Boot chart for `hostname` (`date`)
29//config: system.uname = `uname -srvm`
30//config: system.release = `cat /etc/DISTRO-release`
31//config: system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
32//config: system.kernel.options = `cat /proc/cmdline`
33//config: This data is not mandatory for bootchart graph generation,
34//config: and is considered bloat. Nevertheless, this option
35//config: makes bootchartd applet to dump a subset of it.
36//config:
37//config:config FEATURE_BOOTCHARTD_CONFIG_FILE
38//config: bool "bootchartd"
39//config: default y
40//config: depends on BOOTCHARTD
41//config: help
42//config: Create extended header file compatible with "big" bootchartd.
43//config: "Big" bootchartd is a shell script and it dumps some
44//config: "convenient" info int the header, such as:
45//config: title = Boot chart for `hostname` (`date`)
46//config: system.uname = `uname -srvm`
47//config: system.release = `cat /etc/DISTRO-release`
48//config: system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
49//config: system.kernel.options = `cat /proc/cmdline`
50//config: This data is not mandatory for bootchart graph generation,
51//config: and is considered bloat. Nevertheless, this option
52//config: makes bootchartd applet to dump a subset of it.
53
5#include "libbb.h" 54#include "libbb.h"
55/* After libbb.h, since it needs sys/types.h on some systems */
56#include <sys/utsname.h>
6#include <sys/mount.h> 57#include <sys/mount.h>
7#ifndef MS_SILENT 58#ifndef MS_SILENT
8# define MS_SILENT (1 << 15) 59# define MS_SILENT (1 << 15)
@@ -19,15 +70,16 @@
19#define DO_SIGNAL_SYNC 1 70#define DO_SIGNAL_SYNC 1
20 71
21 72
22//Not supported: $PWD/bootchartd.conf and /etc/bootchartd.conf 73//$PWD/bootchartd.conf and /etc/bootchartd.conf:
23 74//supported options:
75//# Sampling period (in seconds)
76//SAMPLE_PERIOD=0.2
77//
78//not yet supported:
24//# tmpfs size 79//# tmpfs size
25//# (32 MB should suffice for ~20 minutes worth of log data, but YMMV) 80//# (32 MB should suffice for ~20 minutes worth of log data, but YMMV)
26//TMPFS_SIZE=32m 81//TMPFS_SIZE=32m
27// 82//
28//# Sampling period (in seconds)
29//SAMPLE_PERIOD=0.2
30//
31//# Whether to enable and store BSD process accounting information. The 83//# Whether to enable and store BSD process accounting information. The
32//# kernel needs to be configured to enable v3 accounting 84//# kernel needs to be configured to enable v3 accounting
33//# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities 85//# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities
@@ -126,7 +178,7 @@ static int dump_procs(FILE *fp, int look_for_login_process)
126 return found_login_process; 178 return found_login_process;
127} 179}
128 180
129static char *make_tempdir(const char *prog) 181static char *make_tempdir(void)
130{ 182{
131 char template[] = "/tmp/bootchart.XXXXXX"; 183 char template[] = "/tmp/bootchart.XXXXXX";
132 char *tempdir = xstrdup(mkdtemp(template)); 184 char *tempdir = xstrdup(mkdtemp(template));
@@ -151,18 +203,10 @@ static char *make_tempdir(const char *prog)
151 } else { 203 } else {
152 xchdir(tempdir); 204 xchdir(tempdir);
153 } 205 }
154 {
155 FILE *header_fp = xfopen("header", "w");
156 if (prog)
157 fprintf(header_fp, "profile.process = %s\n", prog);
158 fputs("version = "BC_VERSION_STR"\n", header_fp);
159 fclose(header_fp);
160 }
161
162 return tempdir; 206 return tempdir;
163} 207}
164 208
165static void do_logging(void) 209static void do_logging(int sample_pariod_us)
166{ 210{
167 //# Enable process accounting if configured 211 //# Enable process accounting if configured
168 //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then 212 //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
@@ -205,26 +249,61 @@ static void do_logging(void)
205 } 249 }
206 fflush_all(); 250 fflush_all();
207 wait_more: 251 wait_more:
208 usleep(200*1000); 252 usleep(sample_pariod_us);
209 } 253 }
210 254
211 // [ -e kernel_pacct ] && accton off 255 // [ -e kernel_pacct ] && accton off
212} 256}
213 257
214static void finalize(char *tempdir) 258static void finalize(char *tempdir, const char *prog)
215{ 259{
216 //# Stop process accounting if configured 260 //# Stop process accounting if configured
217 //local pacct= 261 //local pacct=
218 //[ -e kernel_pacct ] && pacct=kernel_pacct 262 //[ -e kernel_pacct ] && pacct=kernel_pacct
219 263
220 //( 264 FILE *header_fp = xfopen("header", "w");
221 // echo "version = $VERSION" 265
222 // echo "title = Boot chart for $( hostname | sed q ) ($( date ))" 266 if (prog)
223 // echo "system.uname = $( uname -srvm | sed q )" 267 fprintf(header_fp, "profile.process = %s\n", prog);
224 // echo "system.release = $( sed q /etc/SuSE-release )" 268
225 // echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q ) ($cpucount)" 269 fputs("version = "BC_VERSION_STR"\n", header_fp);
226 // echo "system.kernel.options = $( sed q /proc/cmdline )" 270
227 //) >> header 271 if (ENABLE_FEATURE_BOOTCHARTD_BLOATED_HEADER) {
272 char *hostname;
273 char *kcmdline;
274 time_t t;
275 struct tm tm_time;
276 /* x2 for possible localized data */
277 char date_buf[sizeof("Mon Jun 21 05:29:03 CEST 2010") * 2];
278 struct utsname unamebuf;
279
280 hostname = safe_gethostname();
281 time(&t);
282 localtime_r(&t, &tm_time);
283 strftime(date_buf, sizeof(date_buf), "%a %b %e %H:%M:%S %Z %Y", &tm_time);
284 fprintf(header_fp, "title = Boot chart for %s (%s)\n", hostname, date_buf);
285 if (ENABLE_FEATURE_CLEAN_UP)
286 free(hostname);
287
288 uname(&unamebuf); /* never fails */
289 /* same as uname -srvm */
290 fprintf(header_fp, "system.uname = %s %s %s %s\n",
291 unamebuf.sysname,
292 unamebuf.release,
293 unamebuf.version,
294 unamebuf.machine
295 );
296
297 //system.release = `cat /etc/DISTRO-release`
298 //system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
299
300 kcmdline = xmalloc_open_read_close("/proc/cmdline", NULL);
301 /* kcmdline includes trailing "\n" */
302 fprintf(header_fp, "system.kernel.options = %s", kcmdline);
303 if (ENABLE_FEATURE_CLEAN_UP)
304 free(kcmdline);
305 }
306 fclose(header_fp);
228 307
229 /* Package log files */ 308 /* Package log files */
230 system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct 309 system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct
@@ -256,6 +335,7 @@ static void finalize(char *tempdir)
256int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 335int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
257int bootchartd_main(int argc UNUSED_PARAM, char **argv) 336int bootchartd_main(int argc UNUSED_PARAM, char **argv)
258{ 337{
338 int sample_pariod_us;
259 pid_t parent_pid, logger_pid; 339 pid_t parent_pid, logger_pid;
260 smallint cmd; 340 smallint cmd;
261 enum { 341 enum {
@@ -287,7 +367,23 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
287 cmd = CMD_PID1; 367 cmd = CMD_PID1;
288 } 368 }
289 369
290 /* Here we are in START or INIT state. Create logger child: */ 370 /* Here we are in START or INIT state */
371
372 /* Read config file: */
373 sample_pariod_us = 200 * 1000;
374 if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) {
375 char* token[2];
376 parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read);
377 if (!parser)
378 parser = config_open2("/etc/bootchartd.conf", fopen_for_read);
379 while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) {
380 if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1])
381 sample_pariod_us = atof(token[1]) * 1000000;
382 }
383 config_close(parser);
384 }
385
386 /* Create logger child: */
291 logger_pid = fork_or_rexec(argv); 387 logger_pid = fork_or_rexec(argv);
292 388
293 if (logger_pid == 0) { /* child */ 389 if (logger_pid == 0) { /* child */
@@ -312,9 +408,9 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
312 if (cmd == CMD_PID1 && !getenv("PATH")) 408 if (cmd == CMD_PID1 && !getenv("PATH"))
313 putenv((char*)bb_PATH_root_path); 409 putenv((char*)bb_PATH_root_path);
314 410
315 tempdir = make_tempdir(cmd == CMD_START ? argv[2] : NULL); 411 tempdir = make_tempdir();
316 do_logging(); 412 do_logging(sample_pariod_us);
317 finalize(tempdir); 413 finalize(tempdir, cmd == CMD_START ? argv[2] : NULL);
318 return EXIT_SUCCESS; 414 return EXIT_SUCCESS;
319 } 415 }
320 416