[netperf-dev] netperf4 commit notice r144 - branches/glib_migration/src

raj at netperf.org raj at netperf.org
Tue Apr 11 14:43:49 PDT 2006


Author: raj
Date: 2006-04-11 14:43:47 -0700 (Tue, 11 Apr 2006)
New Revision: 144

Added:
   branches/glib_migration/src/netsysstats_aix53.c
Modified:
   branches/glib_migration/src/netlib.h
   branches/glib_migration/src/netlib_aix.c
   branches/glib_migration/src/netlib_hpux.c
   branches/glib_migration/src/netlib_linux.c
   branches/glib_migration/src/netlib_none.c
   branches/glib_migration/src/netmsg.c
Log:
Add the code to bind the main netserver thread to the target binding of 
the test thread prior to launching the test thread.  After the test
thread is launched, unbind the main netserver thread, and as a belt and
suspenders sort of thing, call the routine to bind the test thread 
(just in case it wasn't inherited properly).

Also, add a netlib_aix53.c file which at one point will know how to do
the right things with the pidle, psys and puser counts rather than the
idle, sys and user counts that netlib_aix.c uses.  There are some HW
multi-threading issues there that need to be worked-out before use.


Modified: branches/glib_migration/src/netlib.h
===================================================================
--- branches/glib_migration/src/netlib.h	2006-04-11 20:22:23 UTC (rev 143)
+++ branches/glib_migration/src/netlib.h	2006-04-11 21:43:47 UTC (rev 144)
@@ -85,6 +85,13 @@
 			       char *loc_value,
 			       int debug,
 			       FILE *where);
+extern  int set_own_locality(char *loc_type,
+			     char *loc_value,
+			     int debug,
+			     FILE *where);
+extern int clear_own_locality(char *loc_type,
+			      int debug,
+			      FILE *where);
 
 #ifdef HAVE_GETHRTIME
 extern void netperf_timestamp(hrtime_t *timestamp);

Modified: branches/glib_migration/src/netlib_aix.c
===================================================================
--- branches/glib_migration/src/netlib_aix.c	2006-04-11 20:22:23 UTC (rev 143)
+++ branches/glib_migration/src/netlib_aix.c	2006-04-11 21:43:47 UTC (rev 144)
@@ -86,3 +86,24 @@
   return(err);
 }
 
+int 
+set_own_locality(char *loc_type, char *loc_value, int debug, FILE *where) {
+  tid_t my_id;
+
+  my_id = thread_self();
+
+  return(set_thread_locality((void *)&my_id,
+			     loc_type,
+			     loc_value,
+			     debug,
+			     where));
+}
+
+int
+clear_own_locality(char *loc_type, int debug, FILE *where){
+  int err;
+
+  err = bindprocessor(BINDTHREAD, thread_self(), PROCESSOR_CLASS_ANY);
+
+  return(NPE_SUCCESS);
+}

Modified: branches/glib_migration/src/netlib_hpux.c
===================================================================
--- branches/glib_migration/src/netlib_hpux.c	2006-04-11 20:22:23 UTC (rev 143)
+++ branches/glib_migration/src/netlib_hpux.c	2006-04-11 21:43:47 UTC (rev 144)
@@ -131,3 +131,51 @@
   return(err);
 }
 
+int 
+set_own_locality(char *loc_type, char *loc_value, int debug, FILE *where) {
+  pthread_t my_id;
+
+  my_id = pthread_self();
+
+  return(set_thread_locality((void *)&my_id,
+			     loc_type,
+			     loc_value,
+			     debug,
+			     where));
+}
+
+int
+clear_own_locality(char *loc_type, int debug, FILE *where){
+
+  int err = -1;
+  psetid_t       pset;
+  pthread_ldom_t ldom;
+  pthread_spu_t  spu;
+
+  NETPERF_DEBUG_ENTRY(debug,where);
+
+  if (strcmp(loc_type,"PROC") == 0) {
+    err  = pthread_processor_bind_np(
+             PTHREAD_BIND_FORCED_NP,
+             &spu,
+             PTHREAD_SPUFLOAT_NP,
+             pthread_self());
+  }
+  else if (strcmp(loc_type,"LDOM") == 0) {
+    err  = pthread_ldom_bind_np(
+             &ldom,
+             PTHREAD_LDOMFLOAT_NP,
+             pthread_self());
+  }
+  else if (strcmp(loc_type,"PSET") == 0) {
+    /* well, it seems as there is no "FLOAT" pset identifier, which
+       means we could only go back to where we were before, assuming
+       of course, we actually knew where that happened to be. at the
+       moment, we have no clue, so we will do nothing. raj
+       2006-04-11 */
+
+  }
+
+  return(NPE_SUCCESS);
+
+}

Modified: branches/glib_migration/src/netlib_linux.c
===================================================================
--- branches/glib_migration/src/netlib_linux.c	2006-04-11 20:22:23 UTC (rev 143)
+++ branches/glib_migration/src/netlib_linux.c	2006-04-11 21:43:47 UTC (rev 144)
@@ -128,22 +128,23 @@
   NETPERF_DEBUG_EXIT(debug,where);
   return(err);
 }
+int 
+clear_own_locality(char *loc_type, int debug, FILE *where) {
+  cpu_set_t      mask;
+  int i;
 
-int
-set_test_locality(test_t *test, char *loc_type, char *loc_value)
-{
-  int   ret;
+  NETPERF_DEBUG_ENTRY(debug,where);
 
-  NETPERF_DEBUG_ENTRY(test->debug,test->where);
+  for(i = 0; i < CPU_SETSIZE; i++) {
+    CPU_SET(i,&mask);
+  }
 
-  ret = set_thread_locality(test->native_thread_id_ptr,
-			    loc_type,
-			    loc_value,
-			    test->debug,
-			    test->where);
+  i = sched_setaffinity(pthread_self,
+			sizeof(mask),
+			&mask);
+  /* yes, we really should do some error checking here */
+  return(NPE_SUCCESS);
 
-  NETPERF_DEBUG_EXIT(test->debug,test->where);
-  return(ret);
 }
 #else
 int
@@ -157,17 +158,50 @@
   NETPERF_DEBUG_EXIT(debug,where);
   return(NPE_SUCCESS);
 }
+int 
+clear_own_locality(char *loc_type, char *loc_value, int debug, FILE *where) {
+  pthread_t my_id;
+  NETPERF_DEBUG_ENTRY(debug,where);
+  if (debug) {
+    fprintf(where,
+	    "No call to set CPU affinity available, request ignored.\n");
+    fflush(where);
+  }
+  return(NPE_SUCCESS);
+}
 
+#endif
+
+int 
+set_own_locality(char *loc_type, char *loc_value, int debug, FILE *where) {
+  pthread_t my_id;
+
+  NETPERF_DEBUG_ENTRY(debug,where);
+
+  my_id = pthread_self();
+
+  return(set_thread_locality((void *)&my_id,
+			     loc_type,
+			     loc_value,
+			     debug,
+			     where));
+}
+
 int
 set_test_locality(test_t *test, char *loc_type, char *loc_value)
 {
+  int   ret;
+
   NETPERF_DEBUG_ENTRY(test->debug,test->where);
-  if (test->debug) {
-    fprintf(test->where,
-	    "No call to set CPU affinity available, request ignored.\n");
-    fflush(test->where);
-  }
+
+  ret = set_thread_locality(test->native_thread_id_ptr,
+			    loc_type,
+			    loc_value,
+			    test->debug,
+			    test->where);
+
   NETPERF_DEBUG_EXIT(test->debug,test->where);
-  return(NPE_SUCCESS);
+  return(ret);
 }
-#endif
+
+

Modified: branches/glib_migration/src/netlib_none.c
===================================================================
--- branches/glib_migration/src/netlib_none.c	2006-04-11 20:22:23 UTC (rev 143)
+++ branches/glib_migration/src/netlib_none.c	2006-04-11 21:43:47 UTC (rev 144)
@@ -67,3 +67,13 @@
   return(NPE_SUCCESS);
 }
 
+int 
+set_own_locality(char *loc_type, char *loc_value, int debug, FILE *where) {
+  int my_id = 0;
+
+  return(set_thread_locality((void *)&my_id,
+			     loc_type,
+			     loc_value,
+			     debug,
+			     where));
+}

Modified: branches/glib_migration/src/netmsg.c
===================================================================
--- branches/glib_migration/src/netmsg.c	2006-04-11 20:22:23 UTC (rev 143)
+++ branches/glib_migration/src/netmsg.c	2006-04-11 21:43:47 UTC (rev 144)
@@ -869,11 +869,12 @@
 test_message(xmlNodePtr msg, xmlDocPtr doc, server_t *server)
 {
   int        rc = NPE_SUCCESS;
+  int        rc2;
   test_t    *new_test;
   xmlNodePtr test_node;
   xmlChar   *testid;
-  xmlChar   *loc_type;
-  xmlChar   *loc_value;
+  xmlChar   *loc_type = NULL;
+  xmlChar   *loc_value = NULL;
   thread_launch_state_t *launch_state;
 
   NETPERF_DEBUG_ENTRY(debug,where);
@@ -935,6 +936,24 @@
       if (launch_state) {
 	launch_state->data_arg = new_test;
 	launch_state->start_routine = new_test->test_func;
+
+	/* before we launch the thread, we should bind ourselves to
+	   the cpu to which the thread will be bound (if at all) to
+	   make sure that stuff like stack allocation happens on the
+	   desired CPU. raj 2006-04-11 */
+
+	loc_type  = xmlGetProp(test_node,(const xmlChar *)"locality_type");
+	loc_value = xmlGetProp(test_node,(const xmlChar *)"locality_value");
+	if ((loc_type != NULL) && (loc_value != NULL)) {
+	  /* we use rc2 because we aren't going to fail the run if the
+	     affinity didn't work, but eventually we should emit some
+	     sort of warning */
+	  rc2 = set_own_locality((char *)loc_type,
+				 (char *)loc_value,
+				 debug,
+				 where);
+	}
+
 	rc = launch_thread(&new_test->thread_id,launch_pad,launch_state);
 	if (debug) {
 	  fprintf(where,
@@ -942,6 +961,8 @@
 		  new_test->thread_id);
 	  fflush(where);
 	}
+	/* having launched the test thread, we really aught to unbind
+	   ourselves from that CPU. at the moment, we do not do that */
       }
       else {
 	rc = NPE_MALLOC_FAILED2;
@@ -970,11 +991,29 @@
 
     /* now we can set test thread locality */
     if (rc == NPE_SUCCESS) {
-      loc_type  = xmlGetProp(test_node,(const xmlChar *)"locality_type");
-      loc_value = xmlGetProp(test_node,(const xmlChar *)"locality_value");
+      /* we will have already extracted loc_type and loc_value if they
+	 exist and there is no possibility of them having spontaneously
+	 appeared in the last N lines of code, so we don't need the
+	 xmlGetProp calls here :)  raj 2006-04-11 */
       if ((loc_type != NULL) && (loc_value != NULL)) {
-        rc = set_test_locality(new_test, (char *)loc_type, (char *)loc_value);
+	/* we use rc2 because we aren't going to fail the run if the
+	   affinity didn't work, but eventually we should emit some
+	   sort of warning */
+        rc2 = set_test_locality(new_test, (char *)loc_type, (char *)loc_value);
+	rc2 = clear_own_locality((char *)loc_type,debug,where);
       }
+      /* however, at this point we need to be sure to free loc_type
+	 and/or loc_value. nulling may be a bit over the top, but
+	 might as well, this isn't supposed to be that performance
+	 critical */
+      if (NULL != loc_type)  {
+	free(loc_type);
+	loc_type = NULL;
+      }
+      if (NULL != loc_value) {
+	free(loc_value);
+	loc_value = NULL;
+      }
     }
 
     if (rc != NPE_SUCCESS) {

Added: branches/glib_migration/src/netsysstats_aix53.c
===================================================================
--- branches/glib_migration/src/netsysstats_aix53.c	2006-04-11 20:22:23 UTC (rev 143)
+++ branches/glib_migration/src/netsysstats_aix53.c	2006-04-11 21:43:47 UTC (rev 144)
@@ -0,0 +1,193 @@
+char netsysstats_specific_id[]="\
+@(#)(c) Copyright 2005, Hewlett-Packard Company, $Id: netsysstats_hpux.c 133 2006-04-06 21:06:23Z raj $";
+
+/*
+
+This file is part of netperf4.
+
+Netperf4 is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+Netperf4 is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
+
+In addition, as a special exception, the copyright holders give
+permission to link the code of netperf4 with the OpenSSL project's
+"OpenSSL" library (or with modified versions of it that use the same
+license as the "OpenSSL" library), and distribute the linked
+executables.  You must obey the GNU General Public License in all
+respects for all of the code used other than "OpenSSL".  If you modify
+this file, you may extend this exception to your version of the file,
+but you are not obligated to do so.  If you do not wish to do so,
+delete this exception statement from your version.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <libperfstat.h>
+
+#include "netperf.h"
+#include "netlib.h"
+#include "netsysstats.h"
+
+/* data is kept is malloced data structures which are referenced from
+   the test specific data structure.  a pointer to platform specific data
+   is passed for holding data needed for each platform.  255-10-18 sgb */
+
+enum {
+  HPUX_SYS_STATS_PSTAT_GETPROCESSOR_FAILED = -5,
+  HPUX_SYS_STATS_MALLOC_FAILED = -4,
+  HPUX_SYS_STATS_GETDYNAMIC_FAILED = -3,
+  HPUX_SYS_STATS_REQUESTED_STATE_INVALID = -2,
+  HPUX_SYS_STATS_STATE_CORRUPTED = -1,
+  HPUX_SYS_STATS_SUCCESS = 0
+};
+
+
+int
+sys_cpu_util_init(test_t *test)
+{
+  int num_cpus;
+  perfstat_cpu_total_t *perfstat_total_buffer;
+
+  int ret;
+  int err = HPUX_SYS_STATS_SUCCESS;
+  netsysstat_data_t *tsd = GET_TEST_DATA(test);
+
+  /* one of these days I really aught to check the return value */
+  perfstat_total_buffer = (perfstat_cpu_total_t *)
+    malloc(sizeof(perfstat_cpu_total_t));
+
+  /* while they seem to have kept the parms similar between
+     perfstat_cpu and perfstat_cpu_total, it seems that
+     perfstat_cpu_total never wants a "real" name parm given to it. I
+     suppose that if I were paranoid, I'd call perfstat_cpu_total once
+     with the first two parms NULL to get the number of totals, but
+     for now we just ass-u-me it will be one :) raj 2006-04-07 */
+
+  ret = perfstat_cpu_total(NULL,
+			   perfstat_total_buffer,
+			   sizeof(perfstat_cpu_total_t),
+			   1);
+
+  tsd->num_cpus = perfstat_total_buffer->ncpus;
+
+  tsd->method = "AIX53_PERFSTAT";
+  /* save the pointer to the perfstat_total_buffer - from it we will
+     be grabbing the processor frequency, which we use for a
+     calibration-free CPU utilization measurement. */
+  tsd->psd    = perfstat_total_buffer;
+
+  return(err);
+}
+
+/* random musings about idle vs pidle...  the pidle fields seem to
+   come from the PURR a register in Power5.  values from that are
+   provided in pidle, psys and puser.  this is in contrast to the old
+   sampled stuff in idle, sys and user.  A naieve person might
+   ass-u-me that the PURR counts at the frequenty of the CPU and so
+   one could use processorHZ from a perfstat_cpu_total call.  however,
+   this naieve person tried that and noticed that the CPU utilization
+   being reported was concitently much too high.  after a bunch of web
+   surfing he found:
+
+   which reads in part:
+
+      When the processor is in single-thread mode, the PURR increments
+      by one every eight processor clock cycles. When the processor is
+      in SMT mode, the thread that dispatches a group of instructions
+      in a cycle increments the counter by 1/8 in that cycle. If no
+      group dispatch occurs in a given cycle, both threads increment
+      their PURR by 1/16. Over a period of time, the sum of the two
+      PURR registers, when running in SMT mode, should be very close,
+      but not greater than the number of timebase ticks.
+
+   so, it seems that one has to divide processorHZ by 8  
+
+   of course, I tried that and still got results that were obviously
+   too high, so there may need to be some sort of SMT knowledge added
+   to netperf :( */
+
+void
+get_cpu_time_counters(cpu_time_counters_t *res,
+                      struct timeval *timestamp,
+		      test_t *test)
+{
+
+  netsysstat_data_t *tsd = GET_TEST_DATA(test);
+  perfstat_cpu_total_t *psp      = tsd->psd;
+  perfstat_cpu_t       *per_cpu_data;
+  perfstat_id_t        name;
+  int                   num_cpus = tsd->num_cpus;
+  int                   i;
+  double                elapsed;
+
+  strcpy(name.name,"");
+
+  per_cpu_data = (perfstat_cpu_t *)malloc(num_cpus *
+					  sizeof(perfstat_cpu_t));
+
+  if (perfstat_cpu(&name,
+		   per_cpu_data,
+		   sizeof(perfstat_cpu_t),
+		   num_cpus) == num_cpus) {
+    gettimeofday(timestamp, NULL);
+    /* "elapsed" isn't "really" elapsed, but it works for what we want */
+    elapsed = (double)timestamp->tv_sec + 
+      ((double)timestamp->tv_usec / (double)1000000);
+
+    for (i = 0; i < num_cpus; i++) {
+      /* our "calibration" value will be our "elapsed" time multiplied
+	 by the processorHZ/8? */
+      res[i].calibrate = (uint64_t)(elapsed * 
+				    (double) (psp->processorHZ / 8));
+      res[i].idle      = per_cpu_data[i].pidle;
+#ifndef EXTRA_COUNTERS_MISSING
+      res[i].user      = per_cpu_data[i].puser;
+      res[i].kernel    = per_cpu_data[i].psys;
+      res[i].interrupt = 0;
+
+      res[i].other     = res[i].calibrate;
+      res[i].other    -= res[i].idle;
+      res[i].other    -= res[i].user;
+      res[i].other    -= res[i].kernel;
+      res[i].other    -= res[i].interrupt;
+#endif
+      
+      if(test->debug) {
+	fprintf(test->where, "\tcalibrate[%d] = %"PRIx64, i, res[i].calibrate);
+	fprintf(test->where, "\tidle[%d] = %"PRIx64, i, res[i].idle);
+#ifndef EXTRA_COUNTERS_MISSING
+	fprintf(test->where, "\tuser[%d] = %"PRIx64, i, res[i].user);
+	fprintf(test->where, "\tkern[%d] = %"PRIx64, i, res[i].kernel);
+	fprintf(test->where, "\tintr[%d] = %"PRIx64, i, res[i].interrupt);
+	fprintf(test->where, "\tothr[%d] = %"PRIx64, i, res[i].other);
+#endif
+        fprintf(test->where, "\n");
+	fflush(test->where);
+      }
+    }
+    if (test->debug) {
+      fprintf(test->where, "\tseconds=%d\tusec=%d\telapsed=%f\n",
+              timestamp->tv_sec,timestamp->tv_usec,elapsed);
+      fflush(test->where);
+    }
+  }
+}
+



More information about the netperf-dev mailing list