X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbootchart%2Flog.c;h=78f0cab17833c4015f9117bbb67a6caf9fc9c1a6;hp=89c7b3523c86908dedd82287c06551173bc06fe3;hb=ef2648c12793ded136eb81b2482f84027cade614;hpb=83fdc450aa8f79941bec84488ffd5bf8eadab18e diff --git a/src/bootchart/log.c b/src/bootchart/log.c index 89c7b3523..78f0cab17 100644 --- a/src/bootchart/log.c +++ b/src/bootchart/log.c @@ -38,383 +38,390 @@ DIR *proc; double gettime_ns(void) { - struct timespec now; + struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); + clock_gettime(CLOCK_MONOTONIC, &now); - return (now.tv_sec + (now.tv_nsec / 1000000000.0)); + return (now.tv_sec + (now.tv_nsec / 1000000000.0)); } void log_uptime(void) { - FILE *f; - char str[32]; - double uptime; - - f = fopen("/proc/uptime", "r"); - if (!f) - return; - if (!fscanf(f, "%s %*s", str)) { - fclose(f); - return; - } - fclose(f); - uptime = strtod(str, NULL); - - log_start = gettime_ns(); - - /* start graph at kernel boot time */ - if (relative) - graph_start = log_start; - else - graph_start = log_start - uptime; + FILE *f; + char str[32]; + double uptime; + + f = fopen("/proc/uptime", "r"); + if (!f) + return; + if (!fscanf(f, "%s %*s", str)) { + fclose(f); + return; + } + fclose(f); + uptime = strtod(str, NULL); + + log_start = gettime_ns(); + + /* start graph at kernel boot time */ + if (relative) + graph_start = log_start; + else + graph_start = log_start - uptime; } static char *bufgetline(char *buf) { - char *c; + char *c; - if (!buf) - return NULL; + if (!buf) + return NULL; - c = strchr(buf, '\n'); - if (c) - c++; - return c; + c = strchr(buf, '\n'); + if (c) + c++; + return c; } void log_sample(int sample) { - static int vmstat; - static int schedstat; - FILE *st; - char buf[4095]; - char key[256]; - char val[256]; - char rt[256]; - char wt[256]; - char *m; - int c; - int p; - int mod; - static int e_fd; - ssize_t s; - ssize_t n; - struct dirent *ent; - - if (!vmstat) { - /* block stuff */ - vmstat = open("/proc/vmstat", O_RDONLY); - if (vmstat == -1) { - perror("open /proc/vmstat"); - exit (EXIT_FAILURE); - } - } - - n = pread(vmstat, buf, sizeof(buf) - 1, 0); - if (n <= 0) { - close(vmstat); - return; - } - buf[n] = '\0'; - - m = buf; - while (m) { - if (sscanf(m, "%s %s", key, val) < 2) - goto vmstat_next; - if (!strcmp(key, "pgpgin")) - blockstat[sample].bi = atoi(val); - if (!strcmp(key, "pgpgout")) { - blockstat[sample].bo = atoi(val); - break; - } + static int vmstat; + static int schedstat; + FILE *st; + char buf[4095]; + char key[256]; + char val[256]; + char rt[256]; + char wt[256]; + char *m; + int c; + int p; + int mod; + static int e_fd; + ssize_t s; + ssize_t n; + struct dirent *ent; + + if (!vmstat) { + /* block stuff */ + vmstat = open("/proc/vmstat", O_RDONLY); + if (vmstat == -1) { + perror("open /proc/vmstat"); + exit (EXIT_FAILURE); + } + } + + n = pread(vmstat, buf, sizeof(buf) - 1, 0); + if (n <= 0) { + close(vmstat); + return; + } + buf[n] = '\0'; + + m = buf; + while (m) { + if (sscanf(m, "%s %s", key, val) < 2) + goto vmstat_next; + if (!strcmp(key, "pgpgin")) + blockstat[sample].bi = atoi(val); + if (!strcmp(key, "pgpgout")) { + blockstat[sample].bo = atoi(val); + break; + } vmstat_next: - m = bufgetline(m); - if (!m) - break; - } - - if (!schedstat) { - /* overall CPU utilization */ - schedstat = open("/proc/schedstat", O_RDONLY); - if (schedstat == -1) { - perror("open /proc/schedstat"); - exit (EXIT_FAILURE); - } - } - - n = pread(schedstat, buf, sizeof(buf) - 1, 0); - if (n <= 0) { - close(schedstat); - return; - } - buf[n] = '\0'; - - m = buf; - while (m) { - 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) - /* Oops, we only have room for MAXCPUS data */ - break; - cpustat[c].sample[sample].runtime = atoll(rt); - cpustat[c].sample[sample].waittime = atoll(wt); - - if (c == cpus) - cpus = c + 1; - } + m = bufgetline(m); + if (!m) + break; + } + + if (!schedstat) { + /* overall CPU utilization */ + schedstat = open("/proc/schedstat", O_RDONLY); + if (schedstat == -1) { + perror("open /proc/schedstat"); + exit (EXIT_FAILURE); + } + } + + n = pread(schedstat, buf, sizeof(buf) - 1, 0); + if (n <= 0) { + close(schedstat); + return; + } + buf[n] = '\0'; + + m = buf; + while (m) { + 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) + /* Oops, we only have room for MAXCPUS data */ + break; + cpustat[c].sample[sample].runtime = atoll(rt); + cpustat[c].sample[sample].waittime = atoll(wt); + + if (c == cpus) + cpus = c + 1; + } schedstat_next: - m = bufgetline(m); - if (!m) - break; - } - - if (entropy) { - if (!e_fd) { - e_fd = open("/proc/sys/kernel/random/entropy_avail", O_RDONLY); - } - - if (e_fd) { - n = pread(e_fd, buf, sizeof(buf) - 1, 0); - if (n > 0) - entropy_avail[sample] = atoi(buf); - } - } - - /* all the per-process stuff goes here */ - if (!proc) { - /* find all processes */ - proc = opendir("/proc"); - if (!proc) - return; - } else { - rewinddir(proc); - } - - while ((ent = readdir(proc)) != NULL) { - char filename[PATH_MAX]; - int pid; - struct ps_struct *ps; - - if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) - continue; - - pid = atoi(ent->d_name); - - if (pid >= MAXPIDS) - continue; - - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - if (ps->pid == pid) - break; - } - - /* end of our LL? then append a new record */ - if (ps->pid != pid) { - char t[32]; - struct ps_struct *parent; - - ps->next_ps = malloc(sizeof(struct ps_struct)); - if (!ps->next_ps) { - perror("malloc(ps_struct)"); - exit (EXIT_FAILURE); - } - memset(ps->next_ps, 0, sizeof(struct ps_struct)); - ps = ps->next_ps; - ps->pid = pid; - - ps->sample = malloc(sizeof(struct ps_sched_struct) * (len + 1)); - if (!ps->sample) { - perror("malloc(ps_struct)"); - exit (EXIT_FAILURE); - } - memset(ps->sample, 0, sizeof(struct ps_sched_struct) * (len + 1)); - - pscount++; - - /* mark our first sample */ - ps->first = sample; - - /* get name, start time */ - if (!ps->sched) { - sprintf(filename, "/proc/%d/sched", pid); - ps->sched = open(filename, O_RDONLY); - if (ps->sched == -1) - continue; - } - - s = pread(ps->sched, buf, sizeof(buf) - 1, 0); - if (s <= 0) { - close(ps->sched); - continue; - } - - if (!sscanf(buf, "%s %*s %*s", key)) - continue; - - strncpy(ps->name, key, 16); - /* discard line 2 */ - m = bufgetline(buf); - if (!m) - continue; - - m = bufgetline(m); - if (!m) - continue; - - if (!sscanf(m, "%*s %*s %s", t)) - continue; - - ps->starttime = strtod(t, NULL) / 1000.0; - - /* ppid */ - sprintf(filename, "/proc/%d/stat", pid); - st = fopen(filename, "r"); - if (!st) - continue; - if (!fscanf(st, "%*s %*s %*s %i", &p)) { - fclose(st); - continue; - } - fclose(st); - ps->ppid = p; - - /* - * setup child pointers - * - * these are used to paint the tree coherently later - * each parent has a LL of children, and a LL of siblings - */ - if (pid == 1) - continue; /* nothing to do for init atm */ - - /* kthreadd has ppid=0, which breaks our tree ordering */ - if (ps->ppid == 0) - ps->ppid = 1; - - parent = ps_first; - while ((parent->next_ps && parent->pid != ps->ppid)) - parent = parent->next_ps; - - if ((!parent) || (parent->pid != ps->ppid)) { - /* orphan */ - ps->ppid = 1; - parent = ps_first->next_ps; - } - - ps->parent = parent; - - if (!parent->children) { - /* it's the first child */ - parent->children = ps; - } else { - /* walk all children and append */ - struct ps_struct *children; - children = parent->children; - while (children->next) - children = children->next; - children->next = ps; - } - } - - /* else -> found pid, append data in ps */ - - /* below here is all continuous logging parts - we get here on every - * iteration */ - - /* rt, wt */ - if (!ps->schedstat) { - sprintf(filename, "/proc/%d/schedstat", pid); - ps->schedstat = open(filename, O_RDONLY); - if (ps->schedstat == -1) - continue; - } - - if (pread(ps->schedstat, buf, sizeof(buf) - 1, 0) <= 0) { - /* clean up our file descriptors - assume that the process exited */ - close(ps->schedstat); - if (ps->sched) - close(ps->sched); - //if (ps->smaps) - // fclose(ps->smaps); - continue; - } - 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; - - if (!pss) - goto catch_rename; - /* Pss */ - if (!ps->smaps) { - sprintf(filename, "/proc/%d/smaps", pid); - ps->smaps = fopen(filename, "r"); - setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf)); - if (!ps->smaps) - continue; - } else { - rewind(ps->smaps); - } - - while (1) { - int pss_kb; - - /* 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) - break; - - pss_kb = atoi(&buf[61]); - ps->sample[sample].pss += pss_kb; - } - - if (ps->sample[sample].pss > ps->pss_max) - ps->pss_max = ps->sample[sample].pss; + m = bufgetline(m); + if (!m) + break; + } + + if (entropy) { + if (!e_fd) { + e_fd = open("/proc/sys/kernel/random/entropy_avail", O_RDONLY); + } + + if (e_fd) { + n = pread(e_fd, buf, sizeof(buf) - 1, 0); + if (n > 0) { + buf[n] = '\0'; + entropy_avail[sample] = atoi(buf); + } + } + } + + /* all the per-process stuff goes here */ + if (!proc) { + /* find all processes */ + proc = opendir("/proc"); + if (!proc) + return; + } else { + rewinddir(proc); + } + + while ((ent = readdir(proc)) != NULL) { + char filename[PATH_MAX]; + int pid; + struct ps_struct *ps; + + if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) + continue; + + pid = atoi(ent->d_name); + + if (pid >= MAXPIDS) + continue; + + ps = ps_first; + while (ps->next_ps) { + ps = ps->next_ps; + if (ps->pid == pid) + break; + } + + /* end of our LL? then append a new record */ + if (ps->pid != pid) { + char t[32]; + struct ps_struct *parent; + + ps->next_ps = malloc(sizeof(struct ps_struct)); + if (!ps->next_ps) { + perror("malloc(ps_struct)"); + exit (EXIT_FAILURE); + } + memset(ps->next_ps, 0, sizeof(struct ps_struct)); + ps = ps->next_ps; + ps->pid = pid; + + ps->sample = malloc(sizeof(struct ps_sched_struct) * (len + 1)); + if (!ps->sample) { + perror("malloc(ps_struct)"); + exit (EXIT_FAILURE); + } + memset(ps->sample, 0, sizeof(struct ps_sched_struct) * (len + 1)); + + pscount++; + + /* mark our first sample */ + ps->first = sample; + + /* get name, start time */ + if (!ps->sched) { + sprintf(filename, "/proc/%d/sched", pid); + ps->sched = open(filename, O_RDONLY); + if (ps->sched == -1) + continue; + } + + s = pread(ps->sched, buf, sizeof(buf) - 1, 0); + if (s <= 0) { + close(ps->sched); + continue; + } + buf[s] = '\0'; + + if (!sscanf(buf, "%s %*s %*s", key)) + continue; + + strncpy(ps->name, key, 16); + /* discard line 2 */ + m = bufgetline(buf); + if (!m) + continue; + + m = bufgetline(m); + if (!m) + continue; + + if (!sscanf(m, "%*s %*s %s", t)) + continue; + + ps->starttime = strtod(t, NULL) / 1000.0; + + /* ppid */ + sprintf(filename, "/proc/%d/stat", pid); + st = fopen(filename, "r"); + if (!st) + continue; + if (!fscanf(st, "%*s %*s %*s %i", &p)) { + fclose(st); + continue; + } + fclose(st); + ps->ppid = p; + + /* + * setup child pointers + * + * these are used to paint the tree coherently later + * each parent has a LL of children, and a LL of siblings + */ + if (pid == 1) + continue; /* nothing to do for init atm */ + + /* kthreadd has ppid=0, which breaks our tree ordering */ + if (ps->ppid == 0) + ps->ppid = 1; + + parent = ps_first; + while ((parent->next_ps && parent->pid != ps->ppid)) + parent = parent->next_ps; + + if ((!parent) || (parent->pid != ps->ppid)) { + /* orphan */ + ps->ppid = 1; + parent = ps_first->next_ps; + } + + ps->parent = parent; + + if (!parent->children) { + /* it's the first child */ + parent->children = ps; + } else { + /* walk all children and append */ + struct ps_struct *children; + children = parent->children; + while (children->next) + children = children->next; + children->next = ps; + } + } + + /* else -> found pid, append data in ps */ + + /* below here is all continuous logging parts - we get here on every + * iteration */ + + /* rt, wt */ + if (!ps->schedstat) { + sprintf(filename, "/proc/%d/schedstat", pid); + ps->schedstat = open(filename, O_RDONLY); + if (ps->schedstat == -1) + continue; + } + s = pread(ps->schedstat, buf, sizeof(buf) - 1, 0); + if (s <= 0) { + /* clean up our file descriptors - assume that the process exited */ + close(ps->schedstat); + if (ps->sched) + close(ps->sched); + //if (ps->smaps) + // fclose(ps->smaps); + continue; + } + buf[s] = '\0'; + + 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; + + if (!pss) + goto catch_rename; + /* Pss */ + if (!ps->smaps) { + sprintf(filename, "/proc/%d/smaps", pid); + ps->smaps = fopen(filename, "r"); + if (!ps->smaps) + continue; + setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf)); + } else { + rewind(ps->smaps); + } + + while (1) { + int pss_kb; + + /* 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) + break; + + pss_kb = atoi(&buf[61]); + ps->sample[sample].pss += pss_kb; + } + + if (ps->sample[sample].pss > ps->pss_max) + ps->pss_max = ps->sample[sample].pss; catch_rename: - /* catch process rename, try to randomize time */ - mod = (hz < 4.0) ? 4.0 : (hz / 4.0); - if (((samples - ps->first) + pid) % (int)(mod) == 0) { - - /* re-fetch name */ - /* get name, start time */ - if (!ps->sched) { - sprintf(filename, "/proc/%d/sched", pid); - ps->sched = open(filename, O_RDONLY); - if (ps->sched == -1) - continue; - } - if (pread(ps->sched, buf, sizeof(buf) - 1, 0) <= 0) { - /* clean up file descriptors */ - close(ps->sched); - if (ps->schedstat) - close(ps->schedstat); - //if (ps->smaps) - // fclose(ps->smaps); - continue; - } - - if (!sscanf(buf, "%s %*s %*s", key)) - continue; - - strncpy(ps->name, key, 16); - } - } + /* catch process rename, try to randomize time */ + mod = (hz < 4.0) ? 4.0 : (hz / 4.0); + if (((samples - ps->first) + pid) % (int)(mod) == 0) { + + /* re-fetch name */ + /* get name, start time */ + if (!ps->sched) { + sprintf(filename, "/proc/%d/sched", pid); + ps->sched = open(filename, O_RDONLY); + if (ps->sched == -1) + continue; + } + s = pread(ps->sched, buf, sizeof(buf) - 1, 0); + if (s <= 0) { + /* clean up file descriptors */ + close(ps->sched); + if (ps->schedstat) + close(ps->schedstat); + //if (ps->smaps) + // fclose(ps->smaps); + continue; + } + buf[s] = '\0'; + + if (!sscanf(buf, "%s %*s %*s", key)) + continue; + + strncpy(ps->name, key, 16); + } + } }