Home | History | Annotate | Download | only in src
      1 char   netcpu_perfstat_id[]="\
      2 @(#)netcpu_perfstat.c Version 2.6.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 TIME_WITH_SYS_TIME
     19 # include <sys/time.h>
     20 # include <time.h>
     21 #else
     22 # if HAVE_SYS_TIME_H
     23 #  include <sys/time.h>
     24 # else
     25 #  include <time.h>
     26 # endif
     27 #endif
     28 
     29 #if HAVE_LIMITS_H
     30 # include <limits.h>
     31 # ifndef LONG_LONG_MAX
     32 #  define LONG_LONG_MAX LLONG_MAX
     33 # endif /* LONG_LONG_MAX */
     34 #endif
     35 
     36 #include <errno.h>
     37 
     38 #include "netsh.h"
     39 #include "netlib.h"
     40 
     41 /* the lib_start_count and lib_end_count arrays hold the starting
     42    and ending values of whatever is counting when the system is
     43    idle. The rate at which this increments during a test is compared
     44    with a previous calibration to arrive at a CPU utilization
     45    percentage. raj 2005-01-26 */
     46 static uint64_t  lib_start_count[MAXCPUS];
     47 static uint64_t  lib_end_count[MAXCPUS];
     48 
     49 
     50 void
     51 cpu_util_init(void)
     52 {
     53   return;
     54 }
     55 
     56 void
     57 cpu_util_terminate(void)
     58 {
     59   return;
     60 }
     61 
     62 int
     63 get_cpu_method(void)
     64 {
     65   return PERFSTAT;
     66 }
     67 
     68 static void
     69 get_cpu_idle(uint64_t *res)
     70 {
     71   perfstat_cpu_t *perfstat_buffer;
     72   perfstat_cpu_t *per_cpu_pointer;
     73   perfstat_id_t  name;
     74   int i,ret;
     75 
     76   /* a name of "" will cause us to start from the beginning */
     77   strcpy(name.name,"");
     78   perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus *
     79 					     sizeof(perfstat_cpu_t));
     80   if (perfstat_buffer == NULL) {
     81     fprintf(where,
     82 	    "cpu_start: malloc failed errno %d\n",
     83 	    errno);
     84     fflush(where);
     85     exit(-1);
     86   }
     87 
     88   /* happiness and joy, keep going */
     89   ret = perfstat_cpu(&name,
     90 		     perfstat_buffer,
     91 		     sizeof(perfstat_cpu_t),
     92 		     lib_num_loc_cpus);
     93 
     94   if ((ret == -1) ||
     95       (ret != lib_num_loc_cpus)) {
     96     fprintf(where,
     97 	    "cpu_start: perfstat_cpu failed/count off; errno %d cpus %d count %d\n",
     98 	    errno,
     99 	    lib_num_loc_cpus,
    100 	    ret);
    101     fflush(where);
    102     exit(-1);
    103   }
    104 
    105   per_cpu_pointer = perfstat_buffer;
    106   for (i = 0; i < lib_num_loc_cpus; i++){
    107     res[i] = per_cpu_pointer->idle;
    108     per_cpu_pointer++;
    109   }
    110   free(perfstat_buffer);
    111 
    112   return;
    113 }
    114 
    115 float
    116 calibrate_idle_rate(int iterations, int interval)
    117 {
    118   unsigned long long
    119     firstcnt[MAXCPUS],
    120     secondcnt[MAXCPUS];
    121 
    122   float
    123     elapsed,
    124     temp_rate,
    125     rate[MAXTIMES],
    126     local_maxrate;
    127 
    128   long
    129     sec,
    130     usec;
    131 
    132   int
    133     i,
    134     j;
    135 
    136   struct  timeval time1, time2 ;
    137   struct  timezone tz;
    138 
    139   perfstat_cpu_t  *perfstat_buffer;
    140   perfstat_cpu_t  *per_cpu_pointer;
    141   perfstat_id_t   name;
    142   int ret;
    143 
    144   if (debug) {
    145     fprintf(where,"enter calibrate_perfstat\n");
    146     fflush(where);
    147   }
    148 
    149   if (iterations > MAXTIMES) {
    150     iterations = MAXTIMES;
    151   }
    152 
    153   local_maxrate = (float)-1.0;
    154 
    155   perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus *
    156                                              sizeof(perfstat_cpu_t));
    157   if (perfstat_buffer == NULL) {
    158     fprintf(where,
    159             "calibrate_perfstat: malloc failed errno %d\n",
    160             errno);
    161     fflush(where);
    162     exit(-1);
    163   }
    164 
    165   for(i = 0; i < iterations; i++) {
    166     rate[i] = (float)0.0;
    167     /* a name of "" will cause us to start from the beginning */
    168     strcpy(name.name,"");
    169 
    170     /* happiness and joy, keep going */
    171     ret = perfstat_cpu(&name,
    172                        perfstat_buffer,
    173                        sizeof(perfstat_cpu_t),
    174                        lib_num_loc_cpus);
    175 
    176     if ((ret == -1) ||
    177         (ret != lib_num_loc_cpus)) {
    178       fprintf(where,
    179               "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n",
    180               errno,
    181               lib_num_loc_cpus,
    182               ret);
    183       fflush(where);
    184       exit(-1);
    185     }
    186 
    187     per_cpu_pointer = perfstat_buffer;
    188     for (j = 0; j < lib_num_loc_cpus; j++) {
    189       firstcnt[j] = per_cpu_pointer->idle;
    190       per_cpu_pointer++;
    191     }
    192     gettimeofday (&time1, &tz);
    193     sleep(interval);
    194     gettimeofday (&time2, &tz);
    195 
    196     if (time2.tv_usec < time1.tv_usec)
    197       {
    198         time2.tv_usec += 1000000;
    199         time2.tv_sec -=1;
    200       }
    201     sec = time2.tv_sec - time1.tv_sec;
    202     usec = time2.tv_usec - time1.tv_usec;
    203     elapsed = (float)sec + ((float)usec/(float)1000000.0);
    204 
    205     /* happiness and joy, keep going */
    206     ret = perfstat_cpu(&name,
    207                        perfstat_buffer,
    208                        sizeof(perfstat_cpu_t),
    209                        lib_num_loc_cpus);
    210 
    211     if ((ret == -1) ||
    212         (ret != lib_num_loc_cpus)) {
    213       fprintf(where,
    214               "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n",
    215               errno,
    216               lib_num_loc_cpus,
    217               ret);
    218       fflush(where);
    219       exit(-1);
    220     }
    221 
    222     per_cpu_pointer = perfstat_buffer;
    223 
    224     if(debug) {
    225       fprintf(where,
    226 	      "Calibration for perfstat counter run: %d\n"
    227 	      "\tsec = %ld usec = %ld\n"
    228 	      "\telapsed time = %g\n",
    229 	      i,
    230 	      sec,usec,
    231 	      elapsed);
    232     }
    233 
    234     for (j = 0; j < lib_num_loc_cpus; j++) {
    235       secondcnt[j] = per_cpu_pointer->idle;
    236       per_cpu_pointer++;
    237       if(debug) {
    238         /* I know that there are situations where compilers know about
    239            long long, but the library functions do not... raj 4/95 */
    240         fprintf(where,
    241                 "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n",
    242                 j,
    243                 firstcnt[j],
    244                 firstcnt[j],
    245                 j,
    246                 secondcnt[j],
    247                 secondcnt[j]);
    248       }
    249       /* we assume that it would wrap no more than once. we also
    250 	 assume that the result of subtracting will "fit" raj 4/95 */
    251       temp_rate = (secondcnt[j] >= firstcnt[j]) ?
    252         (float)(secondcnt[j] - firstcnt[j])/elapsed :
    253           (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed;
    254       if (temp_rate > rate[i]) rate[i] = temp_rate;
    255       if(debug) {
    256         fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
    257         fflush(where);
    258       }
    259       if (local_maxrate < rate[i]) local_maxrate = rate[i];
    260     }
    261   }
    262   if(debug) {
    263     fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
    264     fflush(where);
    265   }
    266   free(perfstat_buffer);
    267   return local_maxrate;
    268 }
    269 
    270 float
    271 calc_cpu_util_internal(float elapsed_time)
    272 {
    273   int i;
    274 
    275   float actual_rate;
    276   float correction_factor;
    277 
    278   memset(&lib_local_cpu_stats, 0, sizeof(lib_local_cpu_stats));
    279 
    280   /* It is possible that the library measured a time other than the
    281      one that the user want for the cpu utilization calculations - for
    282      example, tests that were ended by watchdog timers such as the udp
    283      stream test. We let these tests tell up what the elapsed time
    284      should be. */
    285 
    286   if (elapsed_time != 0.0) {
    287     correction_factor = (float) 1.0 +
    288       ((lib_elapsed - elapsed_time) / elapsed_time);
    289   }
    290   else {
    291     correction_factor = (float) 1.0;
    292   }
    293 
    294   /* this looks just like the looper case. at least I think it should
    295      :) raj 4/95 */
    296   for (i = 0; i < lib_num_loc_cpus; i++) {
    297 
    298     /* we assume that the two are not more than a long apart. I know
    299        that this is bad, but trying to go from long longs to a float
    300        (perhaps a double) is boggling my mind right now.  raj 4/95 */
    301 
    302     long long
    303       diff;
    304 
    305     if (lib_end_count[i] >= lib_start_count[i]) {
    306       diff = lib_end_count[i] - lib_start_count[i];
    307     }
    308     else {
    309       diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX;
    310     }
    311     actual_rate = (float) diff / lib_elapsed;
    312     lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
    313       lib_local_maxrate * 100;
    314     lib_local_cpu_stats.cpu_util += lib_local_per_cpu_util[i];
    315     if (debug) {
    316       fprintf(where,
    317               "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n",
    318               i,
    319               actual_rate,
    320               lib_local_maxrate,
    321               lib_local_per_cpu_util[i]);
    322     }
    323   }
    324 
    325   /* we want the average across all n processors */
    326   lib_local_cpu_stats.cpu_util /= (float)lib_num_loc_cpus;
    327 
    328   if (debug) {
    329     fprintf(where,
    330             "calc_cpu_util: average across CPUs is %g\n",
    331             lib_local_cpu_stats.cpu_util);
    332   }
    333 
    334   lib_local_cpu_stats.cpu_util *= correction_factor;
    335 
    336   if (debug) {
    337     fprintf(where,
    338             "calc_cpu_util: returning %g\n",lib_local_cpu_stats.cpu_util);
    339   }
    340 
    341   return lib_local_cpu_stats.cpu_util;
    342 
    343 }
    344 void
    345 cpu_start_internal(void)
    346 {
    347   get_cpu_idle(lib_start_count);
    348   return;
    349 }
    350 
    351 void
    352 cpu_stop_internal(void)
    353 {
    354   get_cpu_idle(lib_end_count);
    355 }
    356