Home | History | Annotate | Download | only in src
      1 char   netcpu_pstatnew_id[]="\
      2 @(#)netcpu_pstatnew.c (c) Copyright 2005-2012 Hewlett-Packard Company, Version 2.6.0";
      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 /* there can be more "processors" in the system than are actually
     64    online. so, we can either walk all the processors one at a time,
     65    which would be slow, or we can track not just lib_num_loc_cpu,
     66    which is the number of active "processors" but also the total
     67    number, and retrieve all of them at one shot and walk the list
     68    once, ignoring those that are offline.  we will ass-u-me there is
     69    no change to the number of processors online while we are running
     70    or there will be strange things happening to CPU utilization. raj
     71    2010-04-27 */
     72 
     73 static long max_proc_count;
     74 
     75 void
     76 cpu_util_init(void)
     77 {
     78   struct pst_dynamic psd;
     79   if (pstat_getdynamic((struct pst_dynamic *)&psd,
     80                        (size_t)sizeof(psd), (size_t)1, 0) != -1) {
     81     max_proc_count = psd.psd_max_proc_cnt;
     82   }
     83   else {
     84     /* we hope this never happens */
     85     max_proc_count = lib_num_loc_cpus;
     86   }
     87 
     88   return;
     89 }
     90 
     91 void
     92 cpu_util_terminate(void)
     93 {
     94   return;
     95 }
     96 
     97 int
     98 get_cpu_method(void)
     99 {
    100   return HP_IDLE_COUNTER;
    101 }
    102 
    103 void
    104 get_cpu_counters(cpu_time_counters_t *res)
    105 {
    106       /* get the idle sycle counter for each processor. now while on a
    107 	 64-bit kernel the ".psc_hi" and ".psc_lo" fields are 64 bits,
    108 	 only the bottom 32-bits are actually valid.  don't ask me
    109 	 why, that is just the way it is.  soo, we shift the psc_hi
    110 	 value by 32 bits and then just sum-in the psc_lo value.  raj
    111 	 2005/09/06 */
    112       struct pst_processor *psp;
    113 
    114       /* to handle the cases of "processors" present but disabled, we
    115 	 will have to allocate a buffer big enough for everyone and
    116 	 then walk the entire list, pulling data for those which are
    117 	 online, assuming the processors online have not changed in
    118 	 the middle of the run. raj 2010-04-27 */
    119       psp = (struct pst_processor *)malloc(max_proc_count * sizeof(*psp));
    120       if (psp == NULL) {
    121         printf("malloc(%d) failed!\n", max_proc_count * sizeof(*psp));
    122         exit(1);
    123       }
    124       if (pstat_getprocessor(psp, sizeof(*psp), max_proc_count, 0) != -1) {
    125         int i,j;
    126 	/* we use lib_iticksperclktick in our sanity checking. we
    127 	   ass-u-me it is the same value for each CPU - famous last
    128 	   words no doubt. raj 2005/09/06 */
    129 	lib_iticksperclktick = psp[0].psp_iticksperclktick;
    130 	i = j = 0;
    131 	while ((i < lib_num_loc_cpus) && (j < max_proc_count)) {
    132 	  if (psp[j].psp_processor_state == PSP_SPU_DISABLED) {
    133 	    j++;
    134 	    continue;
    135 	  }
    136 	  /* we know that psp[j] is online */
    137           res[i].idle = (((uint64_t)psp[j].psp_idlecycles.psc_hi << 32) +
    138 			 psp[j].psp_idlecycles.psc_lo);
    139           if(debug) {
    140             fprintf(where,
    141                     "\tidle[%d] = 0x%"PRIx64" ",
    142                     i,
    143                     res[i].idle);
    144             fflush(where);
    145           }
    146           res[i].user = (((uint64_t)psp[j].psp_usercycles.psc_hi << 32) +
    147 			 psp[j].psp_usercycles.psc_lo);
    148           if(debug) {
    149             fprintf(where,
    150                     "user[%d] = 0x%"PRIx64" ",
    151                     i,
    152                     res[i].user);
    153             fflush(where);
    154           }
    155           res[i].kernel = (((uint64_t)psp[j].psp_systemcycles.psc_hi << 32) +
    156 			    psp[j].psp_systemcycles.psc_lo);
    157           if(debug) {
    158             fprintf(where,
    159                     "kern[%d] = 0x%"PRIx64" ",
    160                     i,
    161                     res[i].kernel);
    162             fflush(where);
    163           }
    164           res[i].interrupt = (((uint64_t)psp[j].psp_interruptcycles.psc_hi << 32) +
    165 			      psp[j].psp_interruptcycles.psc_lo);
    166           if(debug) {
    167             fprintf(where,
    168                     "intr[%d] = 0x%"PRIx64"\n",
    169                     i,
    170                     res[i].interrupt);
    171             fflush(where);
    172           }
    173 	  i++;
    174 	  j++;
    175 	}
    176         free(psp);
    177       }
    178 }
    179 
    180 /* calibrate_pstatnew
    181    there really isn't anything much to do here since we have all the
    182    counters and use their ratios for CPU util measurement. raj
    183    2005-02-16 */
    184 
    185 float
    186 calibrate_idle_rate(int iterations, int interval)
    187 {
    188   return 0.0;
    189 }
    190 
    191 static void
    192 print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters)
    193 {
    194   fprintf(where,
    195 	  "%s[%d]:\n"
    196 	  "\t idle %llu\n"
    197 	  "\t user %llu\n"
    198 	  "\t kernel %llu\n"
    199 	  "\t interrupt %llu\n",
    200 	  name,instance,
    201 	  counters[instance].idle,
    202 	  counters[instance].user,
    203 	  counters[instance].kernel,
    204 	  counters[instance].interrupt);
    205 }
    206 
    207 float
    208 calc_cpu_util_internal(float elapsed_time)
    209 {
    210   int i;
    211 
    212   uint64_t total_cpu_cycles;
    213   uint64_t sanity_cpu_cycles;
    214 
    215 #ifndef USE_INTEGER_MATH
    216   double fraction_idle;
    217   double fraction_user;
    218   double fraction_kernel;
    219   double fraction_interrupt;
    220   double estimated_fraction_interrupt;
    221 #else
    222   uint64_t fraction_idle;
    223   uint64_t fraction_user;
    224   uint64_t fraction_kernel;
    225   uint64_t fraction_interrupt;
    226   uint64_t estimated_fraction_interrupt;
    227 
    228 #define CALC_PERCENT 100
    229 #define CALC_TENTH_PERCENT 1000
    230 #define CALC_HUNDREDTH_PERCENT 10000
    231 #define CALC_THOUSANDTH_PERCENT 100000
    232 #define CALC_ACCURACY CALC_THOUSANDTH_PERCENT
    233 
    234 #endif /* USE_INTEGER_MATH */
    235   float actual_rate;
    236   float correction_factor;
    237 
    238   memset(&lib_local_cpu_stats, 0, sizeof(lib_local_cpu_stats));
    239 
    240   /* It is possible that the library measured a time other than */
    241   /* the one that the user want for the cpu utilization */
    242   /* calculations - for example, tests that were ended by */
    243   /* watchdog timers such as the udp stream test. We let these */
    244   /* tests tell up what the elapsed time should be. */
    245 
    246   if (elapsed_time != 0.0) {
    247     correction_factor = (float) 1.0 +
    248       ((lib_elapsed - elapsed_time) / elapsed_time);
    249   }
    250   else {
    251     correction_factor = (float) 1.0;
    252   }
    253 
    254   /* calculate our sanity check on cycles */
    255   if (debug) {
    256     fprintf(where,
    257 	    "lib_elapsed %g _SC_CLK_TCK %d lib_iticksperclktick %"PRIu64"\n",
    258 	    lib_elapsed,
    259 	    sysconf(_SC_CLK_TCK),
    260 	    lib_iticksperclktick);
    261   }
    262 
    263   /* Ok, elsewhere I may have said that HP-UX 11.23 does the "right"
    264      thing in measuring user, kernel, interrupt and idle all together
    265      instead of overlapping interrupt with the others like an OS that
    266      shall not be named.  However.... it seems there is a bug in the
    267      accounting for interrupt cycles, whereby the cycles do not get
    268      properly accounted.  The sum of user, kernel, interrupt and idle
    269      does not equal the clock rate multiplied by the elapsed time.
    270      Some cycles go missing.
    271 
    272      Since we see agreement between netperf and glance/vsar with the
    273      old "pstat" mechanism, we can presume that the accounting for
    274      idle cycles is sufficiently accurate.  So, while we will still do
    275      math with user, kernel and interrupt cycles, we will only
    276      caculate CPU utilization based on the ratio of idle to _real_
    277      total cycles.  I am told that a "future release" of HP-UX will
    278      fix the interupt cycle accounting.  raj 2005/09/14 */
    279 
    280   /* calculate what the sum of CPU cycles _SHOULD_ be */
    281   sanity_cpu_cycles = (uint64_t) ((double)lib_elapsed *
    282     (double) sysconf(_SC_CLK_TCK) * (double)lib_iticksperclktick);
    283 
    284   /* this looks just like the looper case. at least I think it */
    285   /* should :) raj 4/95 */
    286   for (i = 0; i < lib_num_loc_cpus; i++) {
    287 
    288     /* we ass-u-me that these counters will never wrap during a
    289        netperf run.  this may not be a particularly safe thing to
    290        do. raj 2005-01-28 */
    291     delta_cpu_counters[i].idle = ending_cpu_counters[i].idle -
    292       starting_cpu_counters[i].idle;
    293     delta_cpu_counters[i].user = ending_cpu_counters[i].user -
    294       starting_cpu_counters[i].user;
    295     delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel -
    296       starting_cpu_counters[i].kernel;
    297     delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt -
    298       starting_cpu_counters[i].interrupt;
    299 
    300     if (debug) {
    301       print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters);
    302     }
    303 
    304     /* now get the sum, which we ass-u-me does not overflow a 64-bit
    305        counter. raj 2005-02-16 */
    306     total_cpu_cycles =
    307       delta_cpu_counters[i].idle +
    308       delta_cpu_counters[i].user +
    309       delta_cpu_counters[i].kernel +
    310       delta_cpu_counters[i].interrupt;
    311 
    312     if (debug) {
    313       fprintf(where,
    314 	      "total_cpu_cycles %"PRIu64" sanity_cpu_cycles %"PRIu64
    315 	      " missing %"PRIu64"\n",
    316 	      total_cpu_cycles,
    317 	      sanity_cpu_cycles,
    318 	      sanity_cpu_cycles - total_cpu_cycles);
    319     }
    320 
    321     /* since HP-UX 11.23 does the _RIGHT_ thing and idle/user/kernel
    322        does _NOT_ overlap with interrupt, we do not have to apply any
    323        correction kludge. raj 2005-02-16 */
    324 
    325 #ifndef USE_INTEGER_MATH
    326     /* when the accounting for interrupt time gets its act together,
    327        we can use total_cpu_cycles rather than sanity_cpu_cycles, but
    328        until then, use sanity_cpu_ccles. raj 2005/09/14 */
    329 
    330     fraction_idle = (double)delta_cpu_counters[i].idle /
    331       (double)sanity_cpu_cycles;
    332 
    333     fraction_user = (double)delta_cpu_counters[i].user /
    334       (double)sanity_cpu_cycles;
    335 
    336     fraction_kernel = (double) delta_cpu_counters[i].kernel /
    337       (double)sanity_cpu_cycles;
    338 
    339     fraction_interrupt = (double)delta_cpu_counters[i].interrupt /
    340       (double)sanity_cpu_cycles;
    341 
    342     /* ass-u-me that it is only interrupt that is bogus, and assign
    343        all the "missing" cycles to it. raj 2005/09/14 */
    344     estimated_fraction_interrupt = ((double)delta_cpu_counters[i].interrupt +
    345 				    (sanity_cpu_cycles - total_cpu_cycles)) /
    346       (double)sanity_cpu_cycles;
    347 
    348     if (debug) {
    349       fprintf(where,
    350 	      "\tfraction_idle %g\n"
    351 	      "\tfraction_user %g\n"
    352 	      "\tfraction_kernel %g\n"
    353 	      "\tfraction_interrupt %g WARNING, possibly under-counted!\n"
    354 	      "\testimated_fraction_interrupt %g\n",
    355 	      fraction_idle,
    356 	      fraction_user,
    357 	      fraction_kernel,
    358 	      fraction_interrupt,
    359 	      estimated_fraction_interrupt);
    360     }
    361 
    362     /* and finally, what is our CPU utilization? */
    363     lib_local_per_cpu_util[i] = 100.0 - (fraction_idle * 100.0);
    364 #else
    365     /* and now some fun with integer math.  i initially tried to
    366        promote things to long doubled but that didn't seem to result
    367        in happiness and joy. raj 2005-01-28 */
    368 
    369     /* multiply by 100 and divide by total and you get whole
    370        percentages. multiply by 1000 and divide by total and you get
    371        tenths of percentages.  multiply by 10000 and divide by total
    372        and you get hundredths of percentages. etc etc etc raj
    373        2005-01-28 */
    374 
    375     /* when the accounting for interrupt time gets its act together,
    376        we can use total_cpu_cycles rather than sanity_cpu_cycles, but
    377        until then, use sanity_cpu_ccles. raj 2005/09/14 */
    378 
    379     fraction_idle =
    380       (delta_cpu_counters[i].idle * CALC_ACCURACY) / sanity_cpu_cycles;
    381 
    382     fraction_user =
    383       (delta_cpu_counters[i].user * CALC_ACCURACY) / sanity_cpu_cycles;
    384 
    385     fraction_kernel =
    386       (delta_cpu_counters[i].kernel * CALC_ACCURACY) / sanity_cpu_cycles;
    387 
    388     fraction_interrupt =
    389       (delta_cpu_counters[i].interrupt * CALC_ACCURACY) / sanity_cpu_cycles;
    390 
    391 
    392     estimated_fraction_interrupt =
    393       ((delta_cpu_counters[i].interrupt +
    394 	(sanity_cpu_cycles - total_cpu_cycles)) *
    395        CALC_ACCURACY) / sanity_cpu_cycles;
    396 
    397     if (debug) {
    398       fprintf(where,
    399 	      "\tfraction_idle %"PRIu64"\n"
    400 	      "\tfraction_user %"PRIu64"\n"
    401 	      "\tfraction_kernel %"PRIu64"\n"
    402 	      "\tfraction_interrupt %"PRIu64"WARNING, possibly under-counted!\n"
    403 	      "\testimated_fraction_interrupt %"PRIu64"\n",
    404 	      fraction_idle,
    405 	      fraction_user,
    406 	      fraction_kernel,
    407 	      fraction_interrupt,
    408 	      estimated_fraction_interrupt);
    409     }
    410 
    411     /* and finally, what is our CPU utilization? */
    412     lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle /
    413 					  (float)CALC_ACCURACY) * 100.0);
    414 #endif
    415     lib_local_per_cpu_util[i] *= correction_factor;
    416     if (debug) {
    417       fprintf(where,
    418 	      "lib_local_per_cpu_util[%d] %g  cf %f\n",
    419 	      i,
    420 	      lib_local_per_cpu_util[i],
    421 	      correction_factor);
    422     }
    423     lib_local_cpu_stats.cpu_util += lib_local_per_cpu_util[i];
    424   }
    425   /* we want the average across all n processors */
    426   lib_local_cpu_stats.cpu_util /= (float)lib_num_loc_cpus;
    427 
    428   if (debug) {
    429     fprintf(where,
    430 	    "calc_cpu_util: returning %g\n",
    431 	    lib_local_cpu_stats.cpu_util);
    432   }
    433 
    434   return lib_local_cpu_stats.cpu_util;
    435 
    436 }
    437 void
    438 cpu_start_internal(void)
    439 {
    440   get_cpu_counters(starting_cpu_counters);
    441 }
    442 
    443 void
    444 cpu_stop_internal(void)
    445 {
    446   get_cpu_counters(ending_cpu_counters);
    447 }
    448