The aggregate "cpu" line of /proc/stat currently just repeats cpu0's
values.  As on Linux, it should be the sum over all CPUs: top, htop and
other tools divide it by the number of CPUs to obtain the per-CPU
average, so on SMP systems every reported CPU percentage was scaled by
the number of CPUs (e.g. 800% for one busy core on an 8-CPU box).

* procfs/rootdir.c (rootdir_gc_stat): read every CPU's idle time,
sum them and emit the aggregate "cpu" line from the totals.
---
 procfs/rootdir.c | 47 +++++++++++++++++++++++++++++------------------
 1 file changed, 29 insertions(+), 18 deletions(-)

diff --git a/procfs/rootdir.c b/procfs/rootdir.c
index 56e1906..fc2c607 100644
--- a/procfs/rootdir.c
+++ b/procfs/rootdir.c
@@ -224,7 +224,9 @@ rootdir_gc_stat (void *hook, char **contents, ssize_t 
*contents_len)
 {
   struct timeval boottime, time, idletime;
   struct vm_statistics vmstats;
-  unsigned long up_ticks, idle_ticks;
+  unsigned long up_ticks;
+  unsigned long *idle_ticks;
+  unsigned long long total_idle;
   int i;
   FILE *m;
   host_basic_info_t basic;
@@ -242,14 +244,28 @@ rootdir_gc_stat (void *hook, char **contents, ssize_t 
*contents_len)
   if (err)
     return err;
 
-  err = get_idletime (hook, &idletime, 0);
-  if (err)
-    return err;
-
   err = vm_statistics (mach_task_self (), &vmstats);
   if (err)
     return EIO;
 
+  idle_ticks = malloc (basic->avail_cpus * sizeof *idle_ticks);
+  if (idle_ticks == NULL)
+    return ENOMEM;
+
+  total_idle = 0;
+  for (i = 0; i < basic->avail_cpus; i++)
+    {
+      err = get_idletime (hook, &idletime, i);
+      if (err)
+        {
+          free (idle_ticks);
+          return err;
+        }
+
+      idle_ticks[i] = opt_clk_tck * (idletime.tv_sec * 1000000. + 
idletime.tv_usec) / 1000000.;
+      total_idle += idle_ticks[i];
+    }
+
   m = open_memstream (contents, (size_t *) contents_len);
   if (m == NULL)
     {
@@ -259,22 +275,16 @@ rootdir_gc_stat (void *hook, char **contents, ssize_t 
*contents_len)
 
   timersub (&time, &boottime, &time);
   up_ticks = opt_clk_tck * (time.tv_sec * 1000000. + time.tv_usec) / 1000000.;
-  idle_ticks = opt_clk_tck * (idletime.tv_sec * 1000000. + idletime.tv_usec) / 
1000000.;
 
   fprintf (m,
-      "cpu  %lu 0 0 %lu 0 0 0 0 0\n"
-      "cpu0 %lu 0 0 %lu 0 0 0 0 0\n",
-      up_ticks - idle_ticks, idle_ticks,
-      up_ticks - idle_ticks, idle_ticks);
+      "cpu  %llu 0 0 %llu 0 0 0 0 0\n",
+      (unsigned long long) basic->avail_cpus * up_ticks - total_idle,
+      total_idle);
 
-  for (i = 1; i < basic->avail_cpus; i++)
-    {
-      err = get_idletime (hook, &idletime, i);
-      idle_ticks = opt_clk_tck * (idletime.tv_sec * 1000000. + 
idletime.tv_usec) / 1000000.;
-      fprintf (m,
-          "cpu%d %lu 0 0 %lu 0 0 0 0 0\n",
-          i, up_ticks - idle_ticks, idle_ticks);
-    }
+  for (i = 0; i < basic->avail_cpus; i++)
+    fprintf (m,
+        "cpu%d %lu 0 0 %lu 0 0 0 0 0\n",
+        i, up_ticks - idle_ticks[i], idle_ticks[i]);
 
   fprintf (m,
       "intr 0\n"
@@ -284,6 +294,7 @@ rootdir_gc_stat (void *hook, char **contents, ssize_t 
*contents_len)
       boottime.tv_sec);
 
  out:
+  free (idle_ticks);
   if (m)
     fclose (m);
   return err;
-- 
2.47.3


Reply via email to