X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbootchart%2Fstore.c;h=cedcba88ed1b8059c03281c75cd2a8fc1c52f992;hp=343365e6126e1d948489c30bc478b1bbddfbda19;hb=4d8ddba9d71e51356cc9488f906b8fef89c60c23;hpb=c309a7137b06516eafc055eaab31df964599a8b3 diff --git a/src/bootchart/store.c b/src/bootchart/store.c index 343365e61..cedcba88e 100644 --- a/src/bootchart/store.c +++ b/src/bootchart/store.c @@ -3,7 +3,7 @@ /*** This file is part of systemd. - Copyright (C) 2009-2013 Intel Coproration + Copyright (C) 2009-2013 Intel Corporation Authors: Auke Kok @@ -37,6 +37,7 @@ #include "strxcpyx.h" #include "store.h" #include "bootchart.h" +#include "cgroup-util.h" /* * Alloc a static 4k buffer for stdio - primarily used to increase @@ -44,6 +45,7 @@ * read() overhead. */ static char smaps_buf[4096]; +static int skip = 0; DIR *proc; int procfd = -1; @@ -55,27 +57,22 @@ double gettime_ns(void) { return (n.tv_sec + (n.tv_nsec / 1000000000.0)); } -void log_uptime(void) { - FILE _cleanup_fclose_ *f = NULL; - char str[32]; - double uptime; - - f = fopen("/proc/uptime", "r"); - - if (!f) - return; - if (!fscanf(f, "%s %*s", str)) - return; - - uptime = strtod(str, NULL); +static double gettime_up(void) { + struct timespec n; - log_start = gettime_ns(); + clock_gettime(CLOCK_BOOTTIME, &n); + return (n.tv_sec + (n.tv_nsec / 1000000000.0)); +} - /* start graph at kernel boot time */ +void log_uptime(void) { if (arg_relative) - graph_start = log_start; - else + graph_start = log_start = gettime_ns(); + else { + double uptime = gettime_up(); + + log_start = gettime_ns(); graph_start = log_start - uptime; + } } static char *bufgetline(char *buf) { @@ -92,7 +89,7 @@ static char *bufgetline(char *buf) { static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) { char filename[PATH_MAX]; - int _cleanup_close_ fd=-1; + _cleanup_close_ int fd=-1; ssize_t n; sprintf(filename, "%d/cmdline", pid); @@ -111,10 +108,10 @@ static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) { return 0; } -void log_sample(int sample) { +void log_sample(int sample, struct list_sample_data **ptr) { static int vmstat; static int schedstat; - char buf[4095]; + char buf[4096]; char key[256]; char val[256]; char rt[256]; @@ -128,6 +125,10 @@ void log_sample(int sample) { ssize_t n; struct dirent *ent; int fd; + struct list_sample_data *sampledata; + struct ps_sched_struct *ps_prev = NULL; + + sampledata = *ptr; /* all the per-process stuff goes here */ if (!proc) { @@ -144,8 +145,8 @@ void log_sample(int sample) { /* block stuff */ vmstat = openat(procfd, "vmstat", O_RDONLY); if (vmstat == -1) { - perror("open /proc/vmstat"); - exit (EXIT_FAILURE); + log_error("Failed to open /proc/vmstat: %m"); + exit(EXIT_FAILURE); } } @@ -161,9 +162,9 @@ void log_sample(int sample) { if (sscanf(m, "%s %s", key, val) < 2) goto vmstat_next; if (streq(key, "pgpgin")) - blockstat[sample].bi = atoi(val); + sampledata->blockstat.bi = atoi(val); if (streq(key, "pgpgout")) { - blockstat[sample].bo = atoi(val); + sampledata->blockstat.bo = atoi(val); break; } vmstat_next: @@ -176,8 +177,8 @@ vmstat_next: /* overall CPU utilization */ schedstat = openat(procfd, "schedstat", O_RDONLY); if (schedstat == -1) { - perror("open /proc/schedstat"); - exit (EXIT_FAILURE); + log_error("Failed to open /proc/schedstat: %m"); + exit(EXIT_FAILURE); } } @@ -198,8 +199,8 @@ vmstat_next: if (c > MAXCPUS) /* Oops, we only have room for MAXCPUS data */ break; - cpustat[c].sample[sample].runtime = atoll(rt); - cpustat[c].sample[sample].waittime = atoll(wt); + sampledata->runtime[c] = atoll(rt); + sampledata->waittime[c] = atoll(wt); if (c == cpus) cpus = c + 1; @@ -219,7 +220,7 @@ schedstat_next: n = pread(e_fd, buf, sizeof(buf) - 1, 0); if (n > 0) { buf[n] = '\0'; - entropy_avail[sample] = atoi(buf); + sampledata->entropy_avail = atoi(buf); } } } @@ -246,28 +247,31 @@ schedstat_next: /* end of our LL? then append a new record */ if (ps->pid != pid) { - FILE _cleanup_fclose_ *st = NULL; + _cleanup_fclose_ FILE *st = NULL; char t[32]; struct ps_struct *parent; - ps->next_ps = calloc(1, sizeof(struct ps_struct)); + ps->next_ps = new0(struct ps_struct, 1); if (!ps->next_ps) { - perror("calloc(ps_struct)"); + log_oom(); exit (EXIT_FAILURE); } ps = ps->next_ps; ps->pid = pid; - ps->sample = calloc(arg_samples_len + 1, sizeof(struct ps_sched_struct)); + ps->sample = new0(struct ps_sched_struct, 1); if (!ps->sample) { - perror("calloc(ps_struct)"); + log_oom(); exit (EXIT_FAILURE); } + ps->sample->sampledata = sampledata; pscount++; /* mark our first sample */ - ps->first = sample; + ps->first = ps->last = ps->sample; + ps->sample->runtime = atoll(rt); + ps->sample->waittime = atoll(wt); /* get name, start time */ if (!ps->sched) { @@ -307,6 +311,11 @@ schedstat_next: ps->starttime = strtod(t, NULL) / 1000.0; + if (arg_show_cgroup) + /* if this fails, that's OK */ + cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, + ps->pid, &ps->cgroup); + /* ppid */ sprintf(filename, "%d/stat", pid); fd = openat(procfd, filename, O_RDONLY); @@ -335,7 +344,7 @@ schedstat_next: while ((parent->next_ps && parent->pid != ps->ppid)) parent = parent->next_ps; - if ((!parent) || (parent->pid != ps->ppid)) { + if (parent->pid != ps->ppid) { /* orphan */ ps->ppid = 1; parent = ps_first->next_ps; @@ -383,16 +392,28 @@ schedstat_next: if (!sscanf(buf, "%s %s %*s", rt, wt)) continue; - ps->last = sample; - ps->sample[sample].runtime = atoll(rt); - ps->sample[sample].waittime = atoll(wt); - - ps->total = (ps->sample[ps->last].runtime - - ps->sample[ps->first].runtime) - / 1000000000.0; + ps->sample->next = new0(struct ps_sched_struct, 1); + if (!ps->sample) { + log_oom(); + exit(EXIT_FAILURE); + } + ps->sample->next->prev = ps->sample; + ps->sample = ps->sample->next; + ps->last = ps->sample; + ps->sample->runtime = atoll(rt); + ps->sample->waittime = atoll(wt); + ps->sample->sampledata = sampledata; + ps->sample->ps_new = ps; + if (ps_prev) { + ps_prev->cross = ps->sample; + } + ps_prev = ps->sample; + ps->total = (ps->last->runtime - ps->first->runtime) + / 1000000000.0; if (!arg_pss) goto catch_rename; + /* Pss */ if (!ps->smaps) { sprintf(filename, "%d/smaps", pid); @@ -401,31 +422,53 @@ schedstat_next: if (!ps->smaps) continue; setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf)); - } else { + } + else { + rewind(ps->smaps); + } + /* test to see if we need to skip another field */ + if (skip == 0) { + if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { + continue; + } + if (fread(buf, 1, 28 * 15, ps->smaps) != (28 * 15)) { + continue; + } + if (buf[392] == 'V') { + skip = 2; + } + else { + skip = 1; + } rewind(ps->smaps); } - while (1) { int pss_kb; - /* skip one line, this contains the object mapped */ - if (fgets(buf, sizeof(buf), ps->smaps) == NULL) + /* skip one line, this contains the object mapped. */ + if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { break; + } /* then there's a 28 char 14 line block */ - if (fread(buf, 1, 28 * 14, ps->smaps) != 28 * 14) + if (fread(buf, 1, 28 * 14, ps->smaps) != 28 * 14) { break; - + } pss_kb = atoi(&buf[61]); - ps->sample[sample].pss += pss_kb; - } + ps->sample->pss += pss_kb; - if (ps->sample[sample].pss > ps->pss_max) - ps->pss_max = ps->sample[sample].pss; + /* skip one more line if this is a newer kernel */ + if (skip == 2) { + if (fgets(buf, sizeof(buf), ps->smaps) == NULL) + break; + } + } + if (ps->sample->pss > ps->pss_max) + ps->pss_max = ps->sample->pss; catch_rename: /* catch process rename, try to randomize time */ mod = (arg_hz < 4.0) ? 4.0 : (arg_hz / 4.0); - if (((samples - ps->first) + pid) % (int)(mod) == 0) { + if (((samples - ps->pid) + pid) % (int)(mod) == 0) { /* re-fetch name */ /* get name, start time */