Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 99 additions & 1 deletion src/bootchart.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ static int exiting = 0;
bool arg_entropy = false;
bool arg_initcall = true;
bool arg_relative = false;
bool arg_raw_dumps = false;
bool arg_filter = true;
bool arg_show_cmdline = false;
bool arg_show_cgroup = false;
Expand All @@ -105,6 +106,7 @@ static void parse_conf(void) {
{ "Bootchart", "Samples", config_parse_int, 0, &arg_samples_len },
{ "Bootchart", "Frequency", config_parse_double, 0, &arg_hz },
{ "Bootchart", "Relative", config_parse_bool, 0, &arg_relative },
{ "Bootchart", "RawDumps", config_parse_bool, 0, &arg_raw_dumps },
{ "Bootchart", "Filter", config_parse_bool, 0, &arg_filter },
{ "Bootchart", "Output", config_parse_path, 0, &output },
{ "Bootchart", "Init", config_parse_path, 0, &init },
Expand Down Expand Up @@ -132,6 +134,7 @@ static void help(void) {
printf("Usage: %s [OPTIONS]\n\n"
"Options:\n"
" -r --rel Record time relative to recording\n"
" -R --keep-raw Save raw data files alongside the SVG\n"
" -f --freq=FREQ Sample frequency [%g]\n"
" -n --samples=N Stop sampling at [%d] samples\n"
" -x --scale-x=N Scale the graph horizontally [%g] \n"
Expand Down Expand Up @@ -163,6 +166,7 @@ static int parse_argv(int argc, char *argv[]) {

static const struct option options[] = {
{"rel", no_argument, NULL, 'r' },
{"keep-raw", no_argument, NULL, 'R' },
{"freq", required_argument, NULL, 'f' },
{"samples", required_argument, NULL, 'n' },
{"pss", no_argument, NULL, 'p' },
Expand All @@ -183,12 +187,15 @@ static int parse_argv(int argc, char *argv[]) {
if (getpid() == 1)
opterr = 0;

while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0)
while ((c = getopt_long(argc, argv, "erRpf:n:o:i:FCchx:y:", options, NULL)) >= 0)
switch (c) {

case 'r':
arg_relative = true;
break;
case 'R':
arg_raw_dumps = true;
break;
case 'f':
r = safe_atod(optarg, &arg_hz);
if (r < 0)
Expand Down Expand Up @@ -259,6 +266,91 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}

static int write_raw_data(const char *output_file,
struct list_sample_data *head,
struct ps_struct *ps_first,
int n_cpus,
double graph_start,
double log_start) {
FILE *f;
char raw_file[PATH_MAX];
struct list_sample_data *sampledata;
struct ps_struct *ps;
int i;

snprintf(raw_file, PATH_MAX, "%.*s.dat",
(int)(strlen(output_file) - (strrchr(output_file, '.') ?
strlen(strrchr(output_file, '.')) : 0)),
output_file);

f = fopen(raw_file, "we");
if (!f)
return log_error_errno(errno, "Failed to open raw data file '%s': %m", raw_file);

fprintf(f, "# bootchart raw data\n");
fprintf(f, "# graph_start=%.9f log_start=%.9f\n", graph_start, log_start);
fprintf(f, "# Samples=%d Frequency=%f Relative=%d\n",
arg_samples_len, arg_hz, arg_relative);

fprintf(f, "\n[samples]\n");
fprintf(f, "# counter sampletime bi bo entropy_avail");
for (i = 0; i < n_cpus; i++)
fprintf(f, " runtime[%d] waittime[%d]", i, i);
fprintf(f, "\n");

LIST_FIND_TAIL(link, sampledata, head);
while (sampledata) {
fprintf(f, "%d %.9f %d %d %d",
sampledata->counter,
sampledata->sampletime,
sampledata->blockstat.bi,
sampledata->blockstat.bo,
sampledata->entropy_avail);
for (i = 0; i < n_cpus; i++)
fprintf(f, " %.0f %.0f",
sampledata->runtime[i],
sampledata->waittime[i]);
fprintf(f, "\n");
sampledata = sampledata->link_prev;
}

fprintf(f, "\n[processes]\n");
fprintf(f, "# pid ppid name starttime total_cpu_s pss_max_kb\n");

ps = ps_first;
while (ps->next_ps) {
struct ps_sched_struct *sample;
ps = ps->next_ps;

fprintf(f, "%d %d %s %.9f %.9f %d\n",
ps->pid, ps->ppid, ps->name,
ps->starttime, ps->total, ps->pss_max);

fprintf(f, " # sample runtime_ns waittime_ns pss_kb\n");
sample = ps->first;
while (sample) {
fprintf(f, " %.9f %.0f %.0f %d\n",
sample->sampledata ? sample->sampledata->sampletime : 0.0,
sample->runtime,
sample->waittime,
sample->pss);
sample = sample->next;
}
}

fclose(f);

{
char cmd[PATH_MAX + 16];
snprintf(cmd, sizeof(cmd), "gzip -f %s", raw_file);
if (system(cmd) != 0)
log_warning("Failed to compress raw data file '%s'", raw_file);
}

log_info("systemd-bootchart wrote raw data to %s.gz\n", raw_file);
return 0;
}

static int do_journal_append(char *file) {
#ifdef HAVE_LIBSYSTEMD
_cleanup_free_ char *bootchart_message = NULL;
Expand Down Expand Up @@ -501,6 +593,12 @@ int main(int argc, char *argv[]) {

log_info("systemd-bootchart wrote %s\n", output_file);

if (arg_raw_dumps) {
r = write_raw_data(output_file, head, ps_first, n_cpus, graph_start, log_start);
if (r < 0)
return EXIT_FAILURE;
}

r = do_journal_append(output_file);
if (r < 0)
return EXIT_FAILURE;
Expand Down
1 change: 1 addition & 0 deletions src/bootchart.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ struct ps_struct {
};

extern bool arg_relative;
extern bool arg_raw_dumps;
extern bool arg_filter;
extern bool arg_show_cmdline;
extern bool arg_show_cgroup;
Expand Down