summaryrefslogtreecommitdiff
path: root/src/bootchart
diff options
context:
space:
mode:
authorGianpaolo Macario <gmacario@gmail.com>2015-06-11 10:03:30 +0000
committerGianpaolo Macario <gianpaolo_macario@mentor.com>2015-06-25 13:39:41 +0000
commitcaa4339784fe83d93327fcf8b5e9f0a3ef09a225 (patch)
tree41b9e67679dd454b803461c5b70956d86088fde1 /src/bootchart
parent9ebdb1e057045d2b96f5980c61667cd41914177b (diff)
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
Diffstat (limited to 'src/bootchart')
-rw-r--r--src/bootchart/store.c58
1 files changed, 58 insertions, 0 deletions
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;