[netperf-dev] netperf2 commit notice r300 - in trunk: . doc src

raj at netperf.org raj at netperf.org
Wed May 27 14:49:43 PDT 2009


Author: raj
Date: 2009-05-27 14:49:42 -0700 (Wed, 27 May 2009)
New Revision: 300

Modified:
   trunk/AUTHORS
   trunk/Release_Notes
   trunk/doc/netperf.info
   trunk/src/netcpu_procstat.c
Log:
procstat fixes from andrew

Modified: trunk/AUTHORS
===================================================================
--- trunk/AUTHORS	2009-04-07 22:44:13 UTC (rev 299)
+++ trunk/AUTHORS	2009-05-27 21:49:42 UTC (rev 300)
@@ -104,6 +104,7 @@
 for assistance with the FreeBSD sysctl() stuff, and later making it
 calibration-free
 fixes to configure to recognize Solaris 11
+fixes to netcpu_procstat.c for later linux kernels
 
 Mark Cooper
 pointing-out the need for -lresolv when compiling -DDO_DNS on RedHat
@@ -230,4 +231,4 @@
 MingW cnd MSDOS (djgpp) leanups.
 
 Marcel Shuldman
-Changes to make netperf more profiling friendly
\ No newline at end of file
+Changes to make netperf more profiling friendly

Modified: trunk/Release_Notes
===================================================================
--- trunk/Release_Notes	2009-04-07 22:44:13 UTC (rev 299)
+++ trunk/Release_Notes	2009-05-27 21:49:42 UTC (rev 300)
@@ -2,6 +2,9 @@
 
 Things changed in this release:
 
+*) Fixes for Linux procstat-based CPU utilization on newer kernels
+   from Andrew Gallatin.
+
 *) Fix for a TCP_RR hang from Michael Shuldman
 
 *) Compilation cleanups for MingW cnd MSDOS (djgpp) ourtesy of Gisle

Modified: trunk/doc/netperf.info
===================================================================
--- trunk/doc/netperf.info	2009-04-07 22:44:13 UTC (rev 299)
+++ trunk/doc/netperf.info	2009-05-27 21:49:42 UTC (rev 300)
@@ -2656,8 +2656,8 @@
 Netperf4 is the shorthand name given to version 4.X.X of netperf.  This
 is really a separate benchmark more than a newer version of netperf,
 but it is a decendant of netperf so the netperf name is kept.  The
-facitious way to describe netperf4 is to say it is the
-egg-laying-wolly-milk-pig version of netperf :)  The more respectful
+facetious way to describe netperf4 is to say it is the
+egg-laying-woolly-milk-pig version of netperf :)  The more respectful
 way to describe it is to say it is the version of netperf with support
 for synchronized, multiple-thread, multiple-test, multiple-system,
 network-oriented benchmarking.
@@ -2853,7 +2853,7 @@
 Node: Address Resolution114090
 Node: Enhancing Netperf116066
 Node: Netperf4117303
-Node: Concept Index118212
-Node: Option Index120602
+Node: Concept Index118213
+Node: Option Index120603
 
 End Tag Table

Modified: trunk/src/netcpu_procstat.c
===================================================================
--- trunk/src/netcpu_procstat.c	2009-04-07 22:44:13 UTC (rev 299)
+++ trunk/src/netcpu_procstat.c	2009-05-27 21:49:42 UTC (rev 300)
@@ -40,12 +40,29 @@
    idle. The rate at which this increments during a test is compared
    with a previous calibrarion to arrive at a CPU utilization
    percentage. raj 2005-01-26 */
-static uint64_t  lib_start_count[MAXCPUS];
-static uint64_t  lib_end_count[MAXCPUS];
 
+#define IDLE_IDX 4
+#define CPU_STATES 9
 
+typedef struct cpu_states
+{
+  uint64_t     	user;
+  uint64_t     	nice;
+  uint64_t     	sys;
+  uint64_t     	idle;
+  uint64_t     	iowait;
+  uint64_t     	hard_irq;
+  uint64_t     	soft_irq;
+  uint64_t     	steal;
+  uint64_t     	guest;  
+} cpu_states_t;
+
+static cpu_states_t  lib_start_count[MAXCPUS];
+static cpu_states_t  lib_end_count[MAXCPUS];
+
+
 /* The max. length of one line of /proc/stat cpu output */
-#define CPU_LINE_LENGTH ((8 * sizeof (long) / 3 + 1) * 4 + 8)
+#define CPU_LINE_LENGTH ((CPU_STATES * sizeof (long) / 3 + 1) * 4 + 8)
 #define PROC_STAT_FILE_NAME "/proc/stat"
 #define N_CPU_LINES(nr) (nr == 1 ? 1 : 1 + nr)
 
@@ -140,8 +157,8 @@
   return sysconf (_SC_CLK_TCK);
 }
 
-void
-get_cpu_idle (uint64_t *res)
+static void
+get_cpu (cpu_states_t *res)
 {
   int space;
   int i;
@@ -158,15 +175,31 @@
   /* Skip first line (total) on SMP */
   if (n > 1) p = strchr (p, '\n');
 
-  /* Idle time is the 4th space-separated token */
   for (i = 0; i < n; i++) {
-    for (space = 0; space < 4; space ++) {
-      p = strchr (p, ' ');
-      while (*++p == ' ');
-    };
-    res[i] = strtoul (p, &p, 10);
+    memset(&res[i], 0, sizeof (&res[i]));
+    p = strchr (p, ' ');
+    sscanf(p, "%llu %llu %llu %llu %llu %llu %llu %llu %llu",
+	   (unsigned long long *)&res[i].user,
+	   (unsigned long long *)&res[i].nice,
+	   (unsigned long long *)&res[i].sys,
+	   (unsigned long long *)&res[i].idle,
+	   (unsigned long long *)&res[i].iowait,
+	   (unsigned long long *)&res[i].hard_irq,
+	   (unsigned long long *)&res[i].soft_irq,
+	   (unsigned long long *)&res[i].steal,
+	   (unsigned long long *)&res[i].guest);
     if (debug) {
-      fprintf(where,"res[%d] is %llu\n",i,res[i]);
+      fprintf(where,"res[%d] is %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
+           i,
+	   (unsigned long long)res[i].user,
+	   (unsigned long long)res[i].nice,
+	   (unsigned long long)res[i].sys,
+	   (unsigned long long)res[i].idle,
+	   (unsigned long long)res[i].iowait,
+	   (unsigned long long)res[i].hard_irq,
+	   (unsigned long long)res[i].soft_irq,
+	   (unsigned long long)res[i].steal,
+	   (unsigned long long)res[i].guest);
       fflush(where);
     }
     p = strchr (p, '\n');
@@ -181,30 +214,50 @@
 measure_cpu_start()
 {
   cpu_method = PROC_STAT;
-  get_cpu_idle(lib_start_count);
+  get_cpu(lib_start_count);
 }
 
 /* collect final CPU utilization raw data */
 void
 measure_cpu_stop()
 {
-  get_cpu_idle(lib_end_count);
+  get_cpu(lib_end_count);
 }
 
+static uint64_t
+tick_subtract(uint64_t start, uint64_t end)
+{
+  uint64_t ret;
+
+  if (end >= start || (start & 0xffffffff00000000ULL))
+    return (end - start);
+
+  /* 
+   *  We wrapped, and it is likely that the kernel is suppling 32-bit
+   *  counters, because "start" is less than 32-bits wide.  If that's
+   *  the case, then handle the wrap by subtracting off everything but
+   *  the lower 32-bits so as to get back to unsigned 32-bit
+   *  arithmetic.
+   */
+  return (end - start +  0xffffffff00000000ULL);
+}
+
 float
 calc_cpu_util_internal(float elapsed_time)
 {
-  int i;
+  int i, j;
 
-  float actual_rate;
   float correction_factor;
+  cpu_states_t diff;
+  uint64_t total_ticks;
 
   lib_local_cpu_util = (float)0.0;
-  /* It is possible that the library measured a time other than */
-  /* the one that the user want for the cpu utilization */
-  /* calculations - for example, tests that were ended by */
-  /* watchdog timers such as the udp stream test. We let these */
-  /* tests tell up what the elapsed time should be. */
+
+  /* It is possible that the library measured a time other than the
+     one that the user want for the cpu utilization calculations - for
+     example, tests that were ended by watchdog timers such as the udp
+     stream test. We let these tests tell up what the elapsed time
+     should be. */
   
   if (elapsed_time != 0.0) {
     correction_factor = (float) 1.0 + 
@@ -214,6 +267,10 @@
     correction_factor = (float) 1.0;
   }
 
+  if (debug) {
+    fprintf(where,
+	    "lib_local_maxrate = %f\n", lib_local_maxrate);
+  }
   for (i = 0; i < lib_num_loc_cpus; i++) {
 
     /* it would appear that on some systems, in loopback, nice is
@@ -222,25 +279,55 @@
      does not go south. raj 6/95 and if we run completely out of idle,
      the same thing could in theory happen to the USE_KSTAT path. raj
      8/2000 */ 
-    
-    if (lib_end_count[i] == lib_start_count[i]) {
-      lib_end_count[i]++;
+
+    /* Find the difference in all CPU stat fields */
+    diff.user = 
+      tick_subtract(lib_start_count[i].user, lib_end_count[i].user);
+    diff.nice = 
+      tick_subtract(lib_start_count[i].nice, lib_end_count[i].nice);
+    diff.sys =
+      tick_subtract(lib_start_count[i].sys, lib_end_count[i].sys);
+    diff.idle =
+      tick_subtract(lib_start_count[i].idle, lib_end_count[i].idle);
+    diff.iowait =
+      tick_subtract(lib_start_count[i].iowait, lib_end_count[i].iowait);
+    diff.hard_irq =
+      tick_subtract(lib_start_count[i].hard_irq, lib_end_count[i].hard_irq);
+    diff.soft_irq =
+      tick_subtract(lib_start_count[i].soft_irq, lib_end_count[i].soft_irq);
+    diff.steal =
+      tick_subtract(lib_start_count[i].steal, lib_end_count[i].steal);
+    diff.guest =
+      tick_subtract(lib_start_count[i].guest, lib_end_count[i].guest);
+    total_ticks = diff.user + diff.nice + diff.sys + diff.idle + diff.iowait 
+      + diff.hard_irq + diff.soft_irq + diff.steal + diff.guest;
+
+    /* calculate idle time as a percentage of all CPU states */
+    if (total_ticks == 0) {
+      fprintf(stderr, "Total ticks 0 on CPU %d, charging nothing!\n", i);
+      lib_local_per_cpu_util[i] = 100.0;
+    } else {
+      lib_local_per_cpu_util[i] = 100.0 * 
+	((float) diff.idle / (float) total_ticks);
     }
-    
-    actual_rate = (lib_end_count[i] > lib_start_count[i]) ?
-      (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed :
-      (float)(lib_end_count[i] - lib_start_count[i] +
-	      MAXLONG)/ lib_elapsed;
-    lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
-      lib_local_maxrate * 100;
+    /* invert percentage to reflect non-idle time */
+    lib_local_per_cpu_util[i] = 100.0 - lib_local_per_cpu_util[i];
+
+    /* apply correction factor */
     lib_local_per_cpu_util[i] *= correction_factor;
     if (debug) {
       fprintf(where,
-              "calc_cpu_util: actual_rate on processor %d is %f start %llx end %llx util %f cf %f\n",
+              "calc_cpu_util: util on processor %d, diff = %llu %llu %llu %llu %llu %llu %llu %llu %llu util %f cf %f\n",
               i,
-              actual_rate,
-              lib_start_count[i],
-              lib_end_count[i],
+	      (unsigned long long)diff.user,
+	      (unsigned long long)diff.nice,
+	      (unsigned long long)diff.sys,
+	      (unsigned long long)diff.idle,
+	      (unsigned long long)diff.iowait,
+	      (unsigned long long)diff.hard_irq,
+	      (unsigned long long)diff.soft_irq,
+	      (unsigned long long)diff.steal,
+	      (unsigned long long)diff.guest,
 	      lib_local_per_cpu_util[i],
 	      correction_factor);
     }
@@ -255,12 +342,12 @@
 void
 cpu_start_internal(void)
 {
-  get_cpu_idle(lib_start_count);
+  get_cpu(lib_start_count);
   return;
 }
 
 void
 cpu_stop_internal(void)
 {
-  get_cpu_idle(lib_end_count);
+  get_cpu(lib_end_count);
 }



More information about the netperf-dev mailing list