Home | History | Annotate | Download | only in netperf
      1 char   netcpu_pstat_id[]="\
      2 @(#)netcpu_pstat.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.0";
      3 
      4 #if HAVE_CONFIG_H
      5 # include <config.h>
      6 #endif
      7 
      8 #include <stdio.h>
      9 
     10 #if HAVE_INTTYPES_H
     11 # include <inttypes.h>
     12 #else
     13 # if HAVE_STDINT_H
     14 #  include <stdint.h>
     15 # endif
     16 #endif
     17 
     18 #if HAVE_LIMITS_H
     19 # include <limits.h>
     20 #endif
     21 
     22 #include <sys/dk.h>
     23 #include <sys/pstat.h>
     24 
     25 #ifndef PSTAT_IPCINFO
     26 # error Sorry, pstat() CPU utilization on 10.0 and later only
     27 #endif
     28 
     29 #include "netsh.h"
     30 #include "netlib.h"
     31 
     32 /* the lib_start_count and lib_end_count arrays hold the starting
     33    and ending values of whatever is counting when the system is
     34    idle. The rate at which this increments during a test is compared
     35    with a previous calibrarion to arrive at a CPU utilization
     36    percentage. raj 2005-01-26 */
     37 static uint64_t  lib_start_count[MAXCPUS];
     38 static uint64_t  lib_end_count[MAXCPUS];
     39 
     40 void
     41 cpu_util_init(void)
     42 {
     43   return;
     44 }
     45 
     46 void
     47 cpu_util_terminate(void)
     48 {
     49   return;
     50 }
     51 
     52 int
     53 get_cpu_method(void)
     54 {
     55   return HP_IDLE_COUNTER;
     56 }
     57 
     58 void
     59 get_cpu_idle(uint64_t *res)
     60 {
     61       /* get the idle sycle counter for each processor */
     62       struct pst_processor *psp;
     63       union overlay_u {
     64         long long full;
     65         long      word[2];
     66       } *overlay;
     67 
     68       psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
     69       if (psp == NULL) {
     70         printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
     71         exit(1);
     72 	  }
     73       if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
     74         int i;
     75         for (i = 0; i < lib_num_loc_cpus; i++) {
     76           overlay = (union overlay_u *)&(res[i]);
     77           overlay->word[0] = psp[i].psp_idlecycles.psc_hi;
     78           overlay->word[1] = psp[i].psp_idlecycles.psc_lo;
     79           if(debug) {
     80             fprintf(where,
     81                     "\tres[%d] = 0x%8.8x%8.8x\n",
     82                     i,
     83                     hi_32(&res[i]),
     84                     lo_32(&res[i]));
     85             fflush(where);
     86           }
     87         }
     88         free(psp);
     89       }
     90 }
     91 
     92 /* calibrate_pstat
     93    Loop a number of iterations, sleeping wait_time seconds each and
     94    count how high the idle counter gets each time. Return  the measured
     95    cpu rate to the calling routine.  */
     96 
     97 float
     98 calibrate_idle_rate(int iterations, int interval)
     99 {
    100 
    101   uint64_t
    102     firstcnt[MAXCPUS],
    103     secondcnt[MAXCPUS];
    104 
    105   float
    106     elapsed,
    107     temp_rate,
    108     rate[MAXTIMES],
    109     local_maxrate;
    110 
    111   long
    112     sec,
    113     usec;
    114 
    115   int
    116     i,
    117     j;
    118 
    119   long  count;
    120 
    121   struct  timeval time1, time2;
    122   struct  timezone tz;
    123 
    124   struct pst_processor *psp;
    125 
    126   if (iterations > MAXTIMES) {
    127     iterations = MAXTIMES;
    128   }
    129 
    130   local_maxrate = -1.0;
    131 
    132   psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
    133   if (psp == NULL) {
    134     printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
    135     exit(1);
    136   }
    137 
    138   for(i = 0; i < iterations; i++) {
    139     rate[i] = 0.0;
    140     /* get the idle sycle counter for each processor */
    141     if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
    142       for (j = 0; j < lib_num_loc_cpus; j++) {
    143         union overlay_u {
    144           long long full;
    145           long      word[2];
    146         } *overlay;
    147         overlay = (union overlay_u *)&(firstcnt[j]);
    148         overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
    149         overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
    150       }
    151     }
    152     else {
    153       fprintf(where,"pstat_getprocessor failure errno %d\n",errno);
    154       fflush(where);
    155       exit(1);
    156     }
    157 
    158     gettimeofday (&time1, &tz);
    159     sleep(interval);
    160     gettimeofday (&time2, &tz);
    161 
    162     if (time2.tv_usec < time1.tv_usec)
    163       {
    164         time2.tv_usec += 1000000;
    165         time2.tv_sec -=1;
    166       }
    167     sec = time2.tv_sec - time1.tv_sec;
    168     usec = time2.tv_usec - time1.tv_usec;
    169     elapsed = (float)sec + ((float)usec/(float)1000000.0);
    170 
    171     if(debug) {
    172       fprintf(where, "Calibration for counter run: %d\n",i);
    173       fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
    174       fprintf(where,"\telapsed time = %g\n",elapsed);
    175     }
    176 
    177     if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
    178       for (j = 0; j < lib_num_loc_cpus; j++) {
    179         union overlay_u {
    180           long long full;
    181           long      word[2];
    182         } *overlay;
    183         overlay = (union overlay_u *)&(secondcnt[j]);
    184         overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
    185         overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
    186         if(debug) {
    187           /* I know that there are situations where compilers know about */
    188           /* long long, but the library fucntions do not... raj 4/95 */
    189           fprintf(where,
    190                   "\tfirstcnt[%d] = 0x%8.8x%8.8x secondcnt[%d] = 0x%8.8x%8.8x\n",
    191                   j,
    192                   hi_32(&firstcnt[j]),
    193                   lo_32(&firstcnt[j]),
    194                   j,
    195                   hi_32(&secondcnt[j]),
    196                   lo_32(&secondcnt[j]));
    197         }
    198         temp_rate = (secondcnt[j] >= firstcnt[j]) ?
    199           (float)(secondcnt[j] - firstcnt[j] )/elapsed :
    200             (float)(secondcnt[j] - firstcnt[j] + LONG_LONG_MAX)/elapsed;
    201         if (temp_rate > rate[i]) rate[i] = temp_rate;
    202         if(debug) {
    203           fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
    204           fflush(where);
    205         }
    206         if (local_maxrate < rate[i]) local_maxrate = rate[i];
    207       }
    208     }
    209     else {
    210       fprintf(where,"pstat failure; errno %d\n",errno);
    211       fflush(where);
    212       exit(1);
    213     }
    214   }
    215   if(debug) {
    216     fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
    217     fflush(where);
    218   }
    219   return local_maxrate;
    220 
    221 }
    222 
    223 float
    224 calc_cpu_util_internal(float elapsed_time)
    225 {
    226   int i;
    227 
    228   float actual_rate;
    229   float correction_factor;
    230 
    231   lib_local_cpu_util = (float)0.0;
    232   /* It is possible that the library measured a time other than */
    233   /* the one that the user want for the cpu utilization */
    234   /* calculations - for example, tests that were ended by */
    235   /* watchdog timers such as the udp stream test. We let these */
    236   /* tests tell up what the elapsed time should be. */
    237 
    238   if (elapsed_time != 0.0) {
    239     correction_factor = (float) 1.0 +
    240       ((lib_elapsed - elapsed_time) / elapsed_time);
    241   }
    242   else {
    243     correction_factor = (float) 1.0;
    244   }
    245 
    246   /* this looks just like the looper case. at least I think it */
    247   /* should :) raj 4/95 */
    248   for (i = 0; i < lib_num_loc_cpus; i++) {
    249 
    250     /* we assume that the two are not more than a long apart. I */
    251     /* know that this is bad, but trying to go from long longs to */
    252     /* a float (perhaps a double) is boggling my mind right now. */
    253     /* raj 4/95 */
    254 
    255     long long
    256       diff;
    257 
    258     if (lib_end_count[i] >= lib_start_count[i]) {
    259       diff = lib_end_count[i] - lib_start_count[i];
    260     }
    261     else {
    262       diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX;
    263     }
    264     actual_rate = (float) diff / lib_elapsed;
    265     lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
    266       lib_local_maxrate * 100;
    267     lib_local_cpu_util += lib_local_per_cpu_util[i];
    268     if (debug) {
    269       fprintf(where,
    270 	      "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n",
    271 	      i,
    272 	      actual_rate,
    273 	      lib_local_maxrate,
    274 	      lib_local_per_cpu_util[i]);
    275     }
    276   }
    277 
    278   /* we want the average across all n processors */
    279   lib_local_cpu_util /= (float)lib_num_loc_cpus;
    280 
    281   if (debug) {
    282     fprintf(where,
    283 	    "calc_cpu_util: average across CPUs is %g\n",lib_local_cpu_util);
    284   }
    285 
    286   lib_local_cpu_util *= correction_factor;
    287 
    288   if (debug) {
    289     fprintf(where,
    290 	    "calc_cpu_util: returning %g\n",lib_local_cpu_util);
    291   }
    292 
    293   return lib_local_cpu_util;
    294 
    295 }
    296 void
    297 cpu_start_internal(void)
    298 {
    299   get_cpu_idle(lib_start_count);
    300   return;
    301 }
    302 
    303 void
    304 cpu_stop_internal(void)
    305 {
    306   get_cpu_idle(lib_end_count);
    307 }
    308