]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootchart: Account CPU time spent in non-main threads of processes (v5) 366/head
authorGianpaolo Macario <gmacario@gmail.com>
Thu, 11 Jun 2015 10:03:30 +0000 (10:03 +0000)
committerGianpaolo Macario <gianpaolo_macario@mentor.com>
Thu, 25 Jun 2015 13:39:41 +0000 (13:39 +0000)
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

index f159cbafe2a226bc4d171603875f81f50eaa1ad3..00439f0409280a3140379c5ec486cda501669be0 100644 (file)
@@ -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;