From: Gianpaolo Macario Date: Thu, 11 Jun 2015 10:03:30 +0000 (+0000) Subject: bootchart: Account CPU time spent in non-main threads of processes (v5) X-Git-Tag: v222~76^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F366%2Fhead;p=thirdparty%2Fsystemd.git 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 --- diff --git a/src/bootchart/store.c b/src/bootchart/store.c index f159cbafe2a..00439f04092 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;