X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fbootchart%2Fstore.c;h=fb3dc9ad6e6cb138a2b614f4f41055cc63c46cce;hb=c87664fef45fc1dadc2303675ed357e0dde61db9;hp=b2afb8d13b65b99dd3ccdf9dad245149848bca60;hpb=8dfb6e718d621a5115bd3b8e7e826195dc6bfe14;p=elogind.git diff --git a/src/bootchart/store.c b/src/bootchart/store.c old mode 100755 new mode 100644 index b2afb8d13..fb3dc9ad6 --- 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 @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include #include #include @@ -34,9 +32,11 @@ #include #include "util.h" +#include "time-util.h" #include "strxcpyx.h" #include "store.h" #include "bootchart.h" +#include "cgroup-util.h" /* * Alloc a static 4k buffer for stdio - primarily used to increase @@ -53,30 +53,25 @@ double gettime_ns(void) { clock_gettime(CLOCK_MONOTONIC, &n); - return (n.tv_sec + (n.tv_nsec / 1000000000.0)); + return (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC)); } -void log_uptime(void) { - _cleanup_fclose_ FILE *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 / (double) NSEC_PER_SEC)); +} - /* 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) { @@ -113,8 +108,8 @@ static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) { } void log_sample(int sample, struct list_sample_data **ptr) { - static int vmstat; - static int schedstat; + static int vmstat = -1; + static int schedstat = -1; char buf[4096]; char key[256]; char val[256]; @@ -124,7 +119,7 @@ void log_sample(int sample, struct list_sample_data **ptr) { int c; int p; int mod; - static int e_fd; + static int e_fd = -1; ssize_t s; ssize_t n; struct dirent *ent; @@ -132,8 +127,6 @@ void log_sample(int sample, struct list_sample_data **ptr) { struct list_sample_data *sampledata; struct ps_sched_struct *ps_prev = NULL; - - sampledata = *ptr; /* all the per-process stuff goes here */ @@ -147,18 +140,19 @@ void log_sample(int sample, struct list_sample_data **ptr) { rewinddir(proc); } - if (!vmstat) { + if (vmstat < 0) { /* block stuff */ vmstat = openat(procfd, "vmstat", O_RDONLY); if (vmstat == -1) { - perror("open /proc/vmstat"); - exit (EXIT_FAILURE); + log_error_errno(errno, "Failed to open /proc/vmstat: %m"); + exit(EXIT_FAILURE); } } n = pread(vmstat, buf, sizeof(buf) - 1, 0); if (n <= 0) { close(vmstat); + vmstat = -1; return; } buf[n] = '\0'; @@ -179,30 +173,33 @@ vmstat_next: break; } - if (!schedstat) { + if (schedstat < 0) { /* overall CPU utilization */ schedstat = openat(procfd, "schedstat", O_RDONLY); if (schedstat == -1) { - perror("open /proc/schedstat"); - exit (EXIT_FAILURE); + log_error_errno(errno, "Failed to open /proc/schedstat (requires CONFIG_SCHEDSTATS=y in kernel config): %m"); + exit(EXIT_FAILURE); } } n = pread(schedstat, buf, sizeof(buf) - 1, 0); if (n <= 0) { close(schedstat); + schedstat = -1; return; } buf[n] = '\0'; m = buf; while (m) { + int r; + if (sscanf(m, "%s %*s %*s %*s %*s %*s %*s %s %s", key, rt, wt) < 3) goto schedstat_next; if (strstr(key, "cpu")) { - c = atoi((const char*)(key+3)); - if (c > MAXCPUS) + r = safe_atoi((const char*)(key+3), &c); + if (r < 0 || c > MAXCPUS -1) /* Oops, we only have room for MAXCPUS data */ break; sampledata->runtime[c] = atoll(rt); @@ -218,16 +215,21 @@ schedstat_next: } if (arg_entropy) { - if (!e_fd) { + if (e_fd < 0) { e_fd = openat(procfd, "sys/kernel/random/entropy_avail", O_RDONLY); + if (e_fd == -1) { + log_error_errno(errno, "Failed to open /proc/sys/kernel/random/entropy_avail: %m"); + exit(EXIT_FAILURE); + } } - if (e_fd) { - n = pread(e_fd, buf, sizeof(buf) - 1, 0); - if (n > 0) { - buf[n] = '\0'; - sampledata->entropy_avail = atoi(buf); - } + n = pread(e_fd, buf, sizeof(buf) - 1, 0); + if (n <= 0) { + close(e_fd); + e_fd = -1; + } else { + buf[n] = '\0'; + sampledata->entropy_avail = atoi(buf); } } @@ -256,18 +258,21 @@ schedstat_next: _cleanup_fclose_ FILE *st = NULL; char t[32]; struct ps_struct *parent; + int r; - 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->sched = -1; + ps->schedstat = -1; - ps->sample = calloc(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; @@ -275,12 +280,12 @@ schedstat_next: pscount++; /* mark our first sample */ - ps->first = ps->sample; + ps->first = ps->last = ps->sample; ps->sample->runtime = atoll(rt); ps->sample->waittime = atoll(wt); /* get name, start time */ - if (!ps->sched) { + if (ps->sched < 0) { sprintf(filename, "%d/sched", pid); ps->sched = openat(procfd, filename, O_RDONLY); if (ps->sched == -1) @@ -290,6 +295,7 @@ schedstat_next: s = pread(ps->sched, buf, sizeof(buf) - 1, 0); if (s <= 0) { close(ps->sched); + ps->sched = -1; continue; } buf[s] = '\0'; @@ -315,14 +321,27 @@ schedstat_next: if (!sscanf(m, "%*s %*s %s", t)) continue; - ps->starttime = strtod(t, NULL) / 1000.0; + r = safe_atod(t, &ps->starttime); + if (r < 0) + continue; + + ps->starttime /= 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); + if (fd == -1) + continue; st = fdopen(fd, "r"); - if (!st) + if (!st) { + close(fd); continue; + } if (!fscanf(st, "%*s %*s %*s %i", &p)) { continue; } @@ -345,7 +364,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; @@ -372,7 +391,7 @@ schedstat_next: * iteration */ /* rt, wt */ - if (!ps->schedstat) { + if (ps->schedstat < 0) { sprintf(filename, "%d/schedstat", pid); ps->schedstat = openat(procfd, filename, O_RDONLY); if (ps->schedstat == -1) @@ -382,8 +401,11 @@ schedstat_next: if (s <= 0) { /* clean up our file descriptors - assume that the process exited */ close(ps->schedstat); - if (ps->sched) + ps->schedstat = -1; + if (ps->sched) { close(ps->sched); + ps->sched = -1; + } //if (ps->smaps) // fclose(ps->smaps); continue; @@ -393,10 +415,10 @@ schedstat_next: if (!sscanf(buf, "%s %s %*s", rt, wt)) continue; - ps->sample->next = calloc(1, sizeof(struct ps_sched_struct)); - if (!ps->sample) { - perror("calloc(ps_struct)"); - exit (EXIT_FAILURE); + ps->sample->next = new0(struct ps_sched_struct, 1); + if (!ps->sample->next) { + log_oom(); + exit(EXIT_FAILURE); } ps->sample->next->prev = ps->sample; ps->sample = ps->sample->next; @@ -419,9 +441,13 @@ schedstat_next: if (!ps->smaps) { sprintf(filename, "%d/smaps", pid); fd = openat(procfd, filename, O_RDONLY); + if (fd == -1) + continue; ps->smaps = fdopen(fd, "r"); - if (!ps->smaps) + if (!ps->smaps) { + close(fd); continue; + } setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf)); } else { @@ -483,8 +509,11 @@ catch_rename: if (s <= 0) { /* clean up file descriptors */ close(ps->sched); - if (ps->schedstat) + ps->sched = -1; + if (ps->schedstat) { close(ps->schedstat); + ps->schedstat = -1; + } //if (ps->smaps) // fclose(ps->smaps); continue;