From caa4339784fe83d93327fcf8b5e9f0a3ef09a225 Mon Sep 17 00:00:00 2001 From: Gianpaolo Macario Date: Thu, 11 Jun 2015 10:03:30 +0000 Subject: bootchart: Account CPU time spent in non-main threads of processes (v5) Fix for issue https://github.com/systemd/systemd/issues/139 - Implement fixes suggested by @teg to -v2 - Implement fixes suggested by @zonque to -v3 and -v4 --- src/bootchart/store.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'src/bootchart/store.c') diff --git a/src/bootchart/store.c b/src/bootchart/store.c index f159cbafe2..00439f0409 100644 --- a/src/bootchart/store.c +++ b/src/bootchart/store.c @@ -115,6 +115,7 @@ int log_sample(DIR *proc, struct list_sample_data *sampledata; struct ps_sched_struct *ps_prev = NULL; int procfd; + int taskfd = -1; sampledata = *ptr; @@ -409,6 +410,63 @@ schedstat_next: ps->total = (ps->last->runtime - ps->first->runtime) / 1000000000.0; + /* Take into account CPU runtime/waittime spent in non-main threads of the process + * by parsing "/proc/[pid]/task/[tid]/schedstat" for all [tid] != [pid] + * See https://github.com/systemd/systemd/issues/139 + */ + + /* Browse directory "/proc/[pid]/task" to know the thread ids of process [pid] */ + snprintf(filename, sizeof(filename), PID_FMT "/task", pid); + taskfd = openat(procfd, filename, O_RDONLY|O_DIRECTORY|O_CLOEXEC); + if (taskfd >= 0) { + _cleanup_closedir_ DIR *taskdir = NULL; + + taskdir = fdopendir(taskfd); + if (!taskdir) { + safe_close(taskfd); + return -errno; + } + FOREACH_DIRENT(ent, taskdir, break) { + int r; + int tid = -1; + _cleanup_close_ int tid_schedstat = -1; + long long delta_rt; + long long delta_wt; + + if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) + continue; + + /* Skip main thread as it was already accounted */ + r = safe_atoi(ent->d_name, &tid); + if (r < 0 || tid == pid) + continue; + + /* Parse "/proc/[pid]/task/[tid]/schedstat" */ + snprintf(filename, sizeof(filename), PID_FMT "/schedstat", tid); + tid_schedstat = openat(taskfd, filename, O_RDONLY|O_CLOEXEC); + + if (tid_schedstat == -1) + continue; + + s = pread(tid_schedstat, buf, sizeof(buf) - 1, 0); + if (s <= 0) + continue; + buf[s] = '\0'; + + if (!sscanf(buf, "%s %s %*s", rt, wt)) + continue; + + r = safe_atolli(rt, &delta_rt); + if (r < 0) + continue; + r = safe_atolli(rt, &delta_wt); + if (r < 0) + continue; + ps->sample->runtime += delta_rt; + ps->sample->waittime += delta_wt; + } + } + if (!arg_pss) goto catch_rename; -- cgit v1.2.3-54-g00ecf