Home | History | Annotate | Download | only in netperf
      1 char   netcpu_pstatnew_id[]="\
      2 @(#)netcpu_pstatnew.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.1";
      3 
      4 /* since we "know" that this interface is available only on 11.23 and
      5    later, and that 11.23 and later are strictly 64-bit kernels, we can
      6    arbitrarily set _PSTAT64 here and not have to worry about it up in
      7    the configure script and makefiles. raj 2005/09/06 */
      8 
      9 #if HAVE_CONFIG_H
     10 # include <config.h>
     11 #endif
     12 
     13 #include <stdio.h>
     14 
     15 #if HAVE_INTTYPES_H
     16 # include <inttypes.h>
     17 #else
     18 # if HAVE_STDINT_H
     19 #  include <stdint.h>
     20 # endif
     21 #endif
     22 
     23 #include <unistd.h>
     24 
     25 #if HAVE_LIMITS_H
     26 # include <limits.h>
     27 #endif
     28 
     29 #include <sys/dk.h>
     30 #include <sys/pstat.h>
     31 
     32 /* HP-UX 11.23 seems to have added three other cycle counters to the
     33    original psp_idlecycles - one for user, one for kernel and one for
     34    interrupt. so, we can now use those to calculate CPU utilization
     35    without requiring any calibration phase.  raj 2005-02-16 */
     36 
     37 #ifndef PSTAT_IPCINFO
     38 # error Sorry, pstat() CPU utilization on 10.0 and later only
     39 #endif
     40 
     41 typedef struct cpu_time_counters {
     42   uint64_t idle;
     43   uint64_t user;
     44   uint64_t kernel;
     45   uint64_t interrupt;
     46 } cpu_time_counters_t;
     47 
     48 uint64_t lib_iticksperclktick;
     49 
     50 #include "netsh.h"
     51 #include "netlib.h"
     52 
     53 /* the lib_start_count and lib_end_count arrays hold the starting
     54    and ending values of whatever is counting when the system is
     55    idle. The rate at which this increments during a test is compared
     56    with a previous calibrarion to arrive at a CPU utilization
     57    percentage. raj 2005-01-26 */
     58 
     59 static cpu_time_counters_t  starting_cpu_counters[MAXCPUS];
     60 static cpu_time_counters_t  ending_cpu_counters[MAXCPUS];
     61 static cpu_time_counters_t  delta_cpu_counters[MAXCPUS];
     62 
     63 void
     64 cpu_util_init(void)
     65 {
     66   return;
     67 }
     68 
     69 void
     70 cpu_util_terminate(void)
     71 {
     72   return;
     73 }
     74 
     75 int
     76 get_cpu_method(void)
     77 {
     78   return HP_IDLE_COUNTER;
     79 }
     80 
     81 void
     82 get_cpu_counters(cpu_time_counters_t *res)
     83 {
     84       /* get the idle sycle counter for each processor. now while on a
     85 	 64-bit kernel the ".psc_hi" and ".psc_lo" fields are 64 bits,
     86 	 only the bottom 32-bits are actually valid.  don't ask me
     87 	 why, that is just the way it is.  soo, we shift the psc_hi
     88 	 value by 32 bits and then just sum-in the psc_lo value.  raj
     89 	 2005/09/06 */
     90       struct pst_processor *psp;
     91 
     92       psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
     93       if (psp == NULL) {
     94         printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
     95         exit(1);
     96 	  }
     97       if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
     98         int i;
     99 	/* we use lib_iticksperclktick in our sanity checking. we
    100 	   ass-u-me it is the same value for each CPU - famous last
    101 	   words no doubt. raj 2005/09/06 */
    102 	lib_iticksperclktick = psp[0].psp_iticksperclktick;
    103         for (i = 0; i < lib_num_loc_cpus; i++) {
    104           res[i].idle = (((uint64_t)psp[i].psp_idlecycles.psc_hi << 32) +
    105 			 psp[i].psp_idlecycles.psc_lo);
    106           if(debug) {
    107             fprintf(where,
    108                     "\tidle[%d] = 0x%"PRIx64" ",
    109                     i,
    110                     res[i].idle);
    111             fflush(where);
    112           }
    113           res[i].user = (((uint64_t)psp[i].psp_usercycles.psc_hi << 32) +
    114 			 psp[i].psp_usercycles.psc_lo);
    115           if(debug) {
    116             fprintf(where,
    117                     "user[%d] = 0x%"PRIx64" ",
    118                     i,
    119                     res[i].user);
    120             fflush(where);
    121           }
    122           res[i].kernel = (((uint64_t)psp[i].psp_systemcycles.psc_hi << 32) +
    123 			    psp[i].psp_systemcycles.psc_lo);
    124           if(debug) {
    125             fprintf(where,
    126                     "kern[%d] = 0x%"PRIx64" ",
    127                     i,
    128                     res[i].kernel);
    129             fflush(where);
    130           }
    131           res[i].interrupt = (((uint64_t)psp[i].psp_interruptcycles.psc_hi << 32) +
    132 			      psp[i].psp_interruptcycles.psc_lo);
    133           if(debug) {
    134             fprintf(where,
    135                     "intr[%d] = 0x%"PRIx64"\n",
    136                     i,
    137                     res[i].interrupt);
    138             fflush(where);
    139           }
    140         }
    141         free(psp);
    142       }
    143 }
    144 
    145 /* calibrate_pstatnew
    146    there really isn't anything much to do here since we have all the
    147    counters and use their ratios for CPU util measurement. raj
    148    2005-02-16 */
    149 
    150 float
    151 calibrate_idle_rate(int iterations, int interval)
    152 {
    153   return 0.0;
    154 }
    155 
    156 static void
    157 print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters)
    158 {
    159   fprintf(where,"%s[%d]:\n",name,instance);
    160   fprintf(where,
    161 	  "\t idle %llu\n",counters[instance].idle);
    162   fprintf(where,
    163 	  "\t user %llu\n",counters[instance].user);
    164   fprintf(where,
    165 	  "\t kernel %llu\n",counters[instance].kernel);
    166   fprintf(where,
    167 	  "\t interrupt %llu\n",counters[instance].interrupt);
    168 }
    169 
    170 float
    171 calc_cpu_util_internal(float elapsed_time)
    172 {
    173   int i;
    174 
    175   uint64_t total_cpu_cycles;
    176   uint64_t sanity_cpu_cycles;
    177 
    178 #ifndef USE_INTEGER_MATH
    179   double fraction_idle;
    180   double fraction_user;
    181   double fraction_kernel;
    182   double fraction_interrupt;
    183   double estimated_fraction_interrupt;
    184 #else
    185   uint64_t fraction_idle;
    186   uint64_t fraction_user;
    187   uint64_t fraction_kernel;
    188   uint64_t fraction_interrupt;
    189   uint64_t estimated_fraction_interrupt;
    190 
    191 #define CALC_PERCENT 100
    192 #define CALC_TENTH_PERCENT 1000
    193 #define CALC_HUNDREDTH_PERCENT 10000
    194 #define CALC_THOUSANDTH_PERCENT 100000
    195 #define CALC_ACCURACY CALC_THOUSANDTH_PERCENT
    196 
    197 #endif /* USE_INTEGER_MATH */
    198   float actual_rate;
    199   float correction_factor;
    200 
    201   lib_local_cpu_util = (float)0.0;
    202 
    203   /* It is possible that the library measured a time other than */
    204   /* the one that the user want for the cpu utilization */
    205   /* calculations - for example, tests that were ended by */
    206   /* watchdog timers such as the udp stream test. We let these */
    207   /* tests tell up what the elapsed time should be. */
    208 
    209   if (elapsed_time != 0.0) {
    210     correction_factor = (float) 1.0 +
    211       ((lib_elapsed - elapsed_time) / elapsed_time);
    212   }
    213   else {
    214     correction_factor = (float) 1.0;
    215   }
    216 
    217   /* calculate our sanity check on cycles */
    218   if (debug) {
    219     fprintf(where,
    220 	    "lib_elapsed %g _SC_CLK_TCK %d lib_iticksperclktick %"PRIu64"\n",
    221 	    lib_elapsed,
    222 	    sysconf(_SC_CLK_TCK),
    223 	    lib_iticksperclktick);
    224   }
    225 
    226   /* Ok, elsewhere I may have said that HP-UX 11.23 does the "right"
    227      thing in measuring user, kernel, interrupt and idle all together
    228      instead of overlapping interrupt with the others like an OS that
    229      shall not be named.  However.... it seems there is a bug in the
    230      accounting for interrupt cycles, whereby the cycles do not get
    231      properly accounted.  The sum of user, kernel, interrupt and idle
    232      does not equal the clock rate multiplied by the elapsed time.
    233      Some cycles go missing.
    234 
    235      Since we see agreement between netperf and glance/vsar with the
    236      old "pstat" mechanism, we can presume that the accounting for
    237      idle cycles is sufficiently accurate.  So, while we will still do
    238      math with user, kernel and interrupt cycles, we will only
    239      caculate CPU utilization based on the ratio of idle to _real_
    240      total cycles.  I am told that a "future release" of HP-UX will
    241      fix the interupt cycle accounting.  raj 2005/09/14 */
    242 
    243   /* calculate what the sum of CPU cycles _SHOULD_ be */
    244   sanity_cpu_cycles = (uint64_t) ((double)lib_elapsed *
    245     (double) sysconf(_SC_CLK_TCK) * (double)lib_iticksperclktick);
    246 
    247   /* this looks just like the looper case. at least I think it */
    248   /* should :) raj 4/95 */
    249   for (i = 0; i < lib_num_loc_cpus; i++) {
    250 
    251     /* we ass-u-me that these counters will never wrap during a
    252        netperf run.  this may not be a particularly safe thing to
    253        do. raj 2005-01-28 */
    254     delta_cpu_counters[i].idle = ending_cpu_counters[i].idle -
    255       starting_cpu_counters[i].idle;
    256     delta_cpu_counters[i].user = ending_cpu_counters[i].user -
    257       starting_cpu_counters[i].user;
    258     delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel -
    259       starting_cpu_counters[i].kernel;
    260     delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt -
    261       starting_cpu_counters[i].interrupt;
    262 
    263     if (debug) {
    264       print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters);
    265     }
    266 
    267     /* now get the sum, which we ass-u-me does not overflow a 64-bit
    268        counter. raj 2005-02-16 */
    269     total_cpu_cycles =
    270       delta_cpu_counters[i].idle +
    271       delta_cpu_counters[i].user +
    272       delta_cpu_counters[i].kernel +
    273       delta_cpu_counters[i].interrupt;
    274 
    275     if (debug) {
    276       fprintf(where,
    277 	      "total_cpu_cycles %"PRIu64" sanity_cpu_cycles %"PRIu64" missing %"PRIu64"\n",
    278 	      total_cpu_cycles,
    279 	      sanity_cpu_cycles,
    280 	      sanity_cpu_cycles - total_cpu_cycles);
    281     }
    282 
    283     /* since HP-UX 11.23 does the _RIGHT_ thing and idle/user/kernel
    284        does _NOT_ overlap with interrupt, we do not have to apply any
    285        correction kludge. raj 2005-02-16 */
    286 
    287 #ifndef USE_INTEGER_MATH
    288     /* when the accounting for interrupt time gets its act together,
    289        we can use total_cpu_cycles rather than sanity_cpu_cycles, but
    290        until then, use sanity_cpu_ccles. raj 2005/09/14 */
    291 
    292     fraction_idle = (double)delta_cpu_counters[i].idle /
    293       (double)sanity_cpu_cycles;
    294 
    295     fraction_user = (double)delta_cpu_counters[i].user /
    296       (double)sanity_cpu_cycles;
    297 
    298     fraction_kernel = (double) delta_cpu_counters[i].kernel /
    299       (double)sanity_cpu_cycles;
    300 
    301     fraction_interrupt = (double)delta_cpu_counters[i].interrupt /
    302       (double)sanity_cpu_cycles;
    303 
    304     /* ass-u-me that it is only interrupt that is bogus, and assign
    305        all the "missing" cycles to it. raj 2005/09/14 */
    306     estimated_fraction_interrupt = ((double)delta_cpu_counters[i].interrupt +
    307 				    (sanity_cpu_cycles - total_cpu_cycles)) /
    308       (double)sanity_cpu_cycles;
    309 
    310     if (debug) {
    311       fprintf(where,"\tfraction_idle %g\n",fraction_idle);
    312       fprintf(where,"\tfraction_user %g\n",fraction_user);
    313       fprintf(where,"\tfraction_kernel %g\n",fraction_kernel);
    314       fprintf(where,"\tfraction_interrupt %g WARNING, possibly under-counted!\n",fraction_interrupt);
    315       fprintf(where,"\testimated_fraction_interrupt %g\n",
    316 	      estimated_fraction_interrupt);
    317     }
    318 
    319     /* and finally, what is our CPU utilization? */
    320     lib_local_per_cpu_util[i] = 100.0 - (fraction_idle * 100.0);
    321 #else
    322     /* and now some fun with integer math.  i initially tried to
    323        promote things to long doubled but that didn't seem to result
    324        in happiness and joy. raj 2005-01-28 */
    325 
    326     /* multiply by 100 and divide by total and you get whole
    327        percentages. multiply by 1000 and divide by total and you get
    328        tenths of percentages.  multiply by 10000 and divide by total
    329        and you get hundredths of percentages. etc etc etc raj
    330        2005-01-28 */
    331 
    332     /* when the accounting for interrupt time gets its act together,
    333        we can use total_cpu_cycles rather than sanity_cpu_cycles, but
    334        until then, use sanity_cpu_ccles. raj 2005/09/14 */
    335 
    336     fraction_idle =
    337       (delta_cpu_counters[i].idle * CALC_ACCURACY) / sanity_cpu_cycles;
    338 
    339     fraction_user =
    340       (delta_cpu_counters[i].user * CALC_ACCURACY) / sanity_cpu_cycles;
    341 
    342     fraction_kernel =
    343       (delta_cpu_counters[i].kernel * CALC_ACCURACY) / sanity_cpu_cycles;
    344 
    345     fraction_interrupt =
    346       (delta_cpu_counters[i].interrupt * CALC_ACCURACY) / sanity_cpu_cycles;
    347 
    348 
    349     estimated_fraction_interrupt =
    350       ((delta_cpu_counters[i].interrupt +
    351 	(sanity_cpu_cycles - total_cpu_cycles)) *
    352        CALC_ACCURACY) / sanity_cpu_cycles;
    353 
    354     if (debug) {
    355       fprintf(where,"\tfraction_idle %"PRIu64"\n",fraction_idle);
    356       fprintf(where,"\tfraction_user %"PRIu64"\n",fraction_user);
    357       fprintf(where,"\tfraction_kernel %"PRIu64"\n",fraction_kernel);
    358       fprintf(where,"\tfraction_interrupt %"PRIu64"WARNING, possibly under-counted!\n",fraction_interrupt);
    359       fprintf(where,"\testimated_fraction_interrupt %"PRIu64"\n",
    360 	      estimated_fraction_interrupt);
    361     }
    362 
    363     /* and finally, what is our CPU utilization? */
    364     lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle /
    365 					  (float)CALC_ACCURACY) * 100.0);
    366 #endif
    367     if (debug) {
    368       fprintf(where,
    369 	      "lib_local_per_cpu_util[%d] %g\n",
    370 	      i,
    371 	      lib_local_per_cpu_util[i]);
    372     }
    373     lib_local_cpu_util += lib_local_per_cpu_util[i];
    374   }
    375   /* we want the average across all n processors */
    376   lib_local_cpu_util /= (float)lib_num_loc_cpus;
    377 
    378   lib_local_cpu_util *= correction_factor;
    379 
    380   if (debug) {
    381     fprintf(where,
    382 	    "calc_cpu_util: returning %g\n",lib_local_cpu_util);
    383   }
    384 
    385   return lib_local_cpu_util;
    386 
    387 }
    388 void
    389 cpu_start_internal(void)
    390 {
    391   get_cpu_counters(starting_cpu_counters);
    392 }
    393 
    394 void
    395 cpu_stop_internal(void)
    396 {
    397   get_cpu_counters(ending_cpu_counters);
    398 }
    399