2 bootchart.c - This file is part of systemd-bootchart
4 Copyright (C) 2009-2013 Intel Coproration
7 Auke Kok <auke-jan.h.kok@intel.com>
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/types.h>
25 #include <sys/resource.h>
37 #include "bootchart.h"
42 double sampletime
[MAXSAMPLES
];
43 struct ps_struct
*ps_first
;
44 struct block_stat_struct blockstat
[MAXSAMPLES
];
45 int entropy_avail
[MAXSAMPLES
];
46 struct cpu_stat_struct cpustat
[MAXCPUS
];
52 static int exiting
= 0;
61 int len
= 500; /* we record len+1 (1 start sample) */
62 double hz
= 25.0; /* 20 seconds log time */
63 double scale_x
= 100.0; /* 100px = 1sec */
64 double scale_y
= 20.0; /* 16px = 1 process bar */
66 char init_path
[PATH_MAX
] = "/sbin/init";
67 char output_path
[PATH_MAX
] = "/var/log";
69 static struct rlimit rlim
;
71 static void signal_handler(int sig
)
79 int main(int argc
, char *argv
[])
83 char output_file
[PATH_MAX
];
92 (void) setrlimit(RLIMIT_NOFILE
, &rlim
);
94 f
= fopen("/etc/systemd/bootchart.conf", "r");
100 while (fgets(buf
, 80, f
) != NULL
) {
103 c
= strchr(buf
, '\n');
104 if (c
) *c
= 0; /* remove trailing \n */
107 continue; /* comment line */
109 key
= strtok(buf
, "=");
112 val
= strtok(NULL
, "=");
116 // todo: filter leading/trailing whitespace
118 if (streq(key
, "samples"))
120 if (streq(key
, "freq"))
122 if (streq(key
, "rel"))
123 relative
= atoi(val
);
124 if (streq(key
, "filter"))
126 if (streq(key
, "pss"))
128 if (streq(key
, "output"))
129 strncpy(output_path
, val
, PATH_MAX
- 1);
130 if (streq(key
, "init"))
131 strncpy(init_path
, val
, PATH_MAX
- 1);
132 if (streq(key
, "scale_x"))
134 if (streq(key
, "scale_y"))
136 if (streq(key
, "entropy"))
143 static struct option opts
[] = {
144 {"rel", 0, NULL
, 'r'},
145 {"freq", 1, NULL
, 'f'},
146 {"samples", 1, NULL
, 'n'},
147 {"pss", 0, NULL
, 'p'},
148 {"output", 1, NULL
, 'o'},
149 {"init", 1, NULL
, 'i'},
150 {"filter", 0, NULL
, 'F'},
151 {"help", 0, NULL
, 'h'},
152 {"scale-x", 1, NULL
, 'x'},
153 {"scale-y", 1, NULL
, 'y'},
154 {"entropy", 0, NULL
, 'e'},
160 i
= getopt_long(argc
, argv
, "erpf:n:o:i:Fhx:y:", opts
, &gind
);
177 strncpy(output_path
, optarg
, PATH_MAX
- 1);
180 strncpy(init_path
, optarg
, PATH_MAX
- 1);
186 scale_x
= atof(optarg
);
189 scale_y
= atof(optarg
);
195 fprintf(stderr
, "Usage: %s [OPTIONS]\n", argv
[0]);
196 fprintf(stderr
, " --rel, -r Record time relative to recording\n");
197 fprintf(stderr
, " --freq, -f N Sample frequency [%f]\n", hz
);
198 fprintf(stderr
, " --samples, -n N Stop sampling at [%d] samples\n", len
);
199 fprintf(stderr
, " --scale-x, -x N Scale the graph horizontally [%f] \n", scale_x
);
200 fprintf(stderr
, " --scale-y, -y N Scale the graph vertically [%f] \n", scale_y
);
201 fprintf(stderr
, " --pss, -p Enable PSS graph (CPU intensive)\n");
202 fprintf(stderr
, " --entropy, -e Enable the entropy_avail graph\n");
203 fprintf(stderr
, " --output, -o [PATH] Path to output files [%s]\n", output_path
);
204 fprintf(stderr
, " --init, -i [PATH] Path to init executable [%s]\n", init_path
);
205 fprintf(stderr
, " --filter, -F Disable filtering of processes from the graph\n");
206 fprintf(stderr
, " that are of less importance or short-lived\n");
207 fprintf(stderr
, " --help, -h Display this message\n");
208 fprintf(stderr
, "See the installed README and bootchartd.conf.example for more information.\n");
216 if (len
> MAXSAMPLES
) {
217 fprintf(stderr
, "Error: samples exceeds maximum\n");
222 fprintf(stderr
, "Error: Frequency needs to be > 0\n");
227 * If the kernel executed us through init=/sbin/bootchartd, then
229 * - parent execs executable specified via init_path[] (/sbin/init by default) as pid=1
235 execl(init_path
, init_path
, NULL
);
239 /* start with empty ps LL */
240 ps_first
= calloc(1, sizeof(struct ps_struct
));
242 perror("calloc(ps_struct)");
246 /* handle TERM/INT nicely */
247 memset(&sig
, 0, sizeof(struct sigaction
));
248 sig
.sa_handler
= signal_handler
;
249 sigaction(SIGHUP
, &sig
, NULL
);
251 interval
= (1.0 / hz
) * 1000000000.0;
255 /* main program loop */
265 sampletime
[samples
] = gettime_ns();
267 /* wait for /proc to become available, discarding samples */
268 if (!(graph_start
> 0.0))
273 sample_stop
= gettime_ns();
275 elapsed
= (sample_stop
- sampletime
[samples
]) * 1000000000.0;
276 timeleft
= interval
- elapsed
;
278 newint_s
= (time_t)(timeleft
/ 1000000000.0);
279 newint_ns
= (long)(timeleft
- (newint_s
* 1000000000.0));
282 * check if we have not consumed our entire timeslice. If we
283 * do, don't sleep and take a new sample right away.
284 * we'll lose all the missed samples and overrun our total
287 if ((newint_ns
> 0) || (newint_s
> 0)) {
288 req
.tv_sec
= newint_s
;
289 req
.tv_nsec
= newint_ns
;
291 res
= nanosleep(&req
, NULL
);
293 if (errno
== EINTR
) {
294 /* caught signal, probably HUP! */
297 perror("nanosleep()");
302 /* calculate how many samples we lost and scrap them */
303 len
= len
+ ((int)(newint_ns
/ interval
));
313 /* do some cleanup, close fd's */
315 while (ps
->next_ps
) {
318 close(ps
->schedstat
);
327 strftime(datestr
, sizeof(datestr
), "%Y%m%d-%H%M", localtime(&t
));
328 snprintf(output_file
, PATH_MAX
, "%s/bootchart-%s.svg", output_path
, datestr
);
330 of
= fopen(output_file
, "w");
332 perror("open output_file");
338 fprintf(stderr
, "bootchartd: Wrote %s\n", output_file
);
341 /* nitpic cleanups */
343 while (ps
->next_ps
) {
344 struct ps_struct
*old
= ps
;
352 /* don't complain when overrun once, happens most commonly on 1st sample */
354 fprintf(stderr
, "bootchartd: Warning: sample time overrun %i times\n", overrun
);