Home | History | Annotate | Download | only in netperf
      1 char   netcpu_kstat_id[]="\
      2 @(#)netcpu_kstat.c  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_UNISTD_H
     19 # include <unistd.h>
     20 #endif
     21 #if HAVE_STRINGS_H
     22 # include <strings.h>
     23 #endif
     24 #if STDC_HEADERS
     25 # include <stdlib.h>
     26 # include <stddef.h>
     27 #else
     28 # if HAVE_STDLIB_H
     29 #  include <stdlib.h>
     30 # endif
     31 #endif
     32 
     33 #include <kstat.h>
     34 #include <sys/sysinfo.h>
     35 
     36 #include "netsh.h"
     37 #include "netlib.h"
     38 
     39 /* the lib_start_count and lib_end_count arrays hold the starting
     40    and ending values of whatever is counting when the system is
     41    idle. The rate at which this increments during a test is compared
     42    with a previous calibrarion to arrive at a CPU utilization
     43    percentage. raj 2005-01-26 */
     44 static uint64_t  lib_start_count[MAXCPUS];
     45 static uint64_t  lib_end_count[MAXCPUS];
     46 
     47 static  kstat_t *cpu_ks[MAXCPUS]; /* the addresses that kstat will
     48                                      need to pull the cpu info from
     49                                      the kstat interface.  at least I
     50                                      think that is what this is :) raj
     51                                      8/2000 */
     52 
     53 #define UPDKCID(nk,ok) \
     54 if (nk == -1) { \
     55   perror("kstat_read "); \
     56   exit(1); \
     57 } \
     58 if (nk != ok)\
     59   goto kcid_changed;
     60 
     61 static kstat_ctl_t *kc = NULL;
     62 static kid_t kcid = 0;
     63 
     64 /* do the initial open of the kstat interface, get the chain id's all
     65    straightened-out and set-up the addresses for get_kstat_idle to do
     66    its thing.  liberally borrowed from the sources to TOP. raj 8/2000 */
     67 
     68 static int
     69 open_kstat()
     70 {
     71   kstat_t *ks;
     72   kid_t nkcid;
     73   int i;
     74   int changed = 0;
     75   static int ncpu = 0;
     76 
     77   kstat_named_t *kn;
     78 
     79   if (debug) {
     80     fprintf(where,"open_kstat: enter\n");
     81     fflush(where);
     82   }
     83 
     84   /*
     85    * 0. kstat_open
     86    */
     87 
     88   if (!kc)
     89     {
     90       kc = kstat_open();
     91       if (!kc)
     92         {
     93           perror("kstat_open ");
     94           exit(1);
     95         }
     96       changed = 1;
     97       kcid = kc->kc_chain_id;
     98     }
     99 #ifdef rickwasstupid
    100   else {
    101     fprintf(where,"open_kstat double open!\n");
    102     fflush(where);
    103     exit(1);
    104   }
    105 #endif
    106 
    107   /* keep doing it until no more changes */
    108  kcid_changed:
    109 
    110   if (debug) {
    111     fprintf(where,"passing kcid_changed\n");
    112     fflush(where);
    113   }
    114 
    115   /*
    116    * 1.  kstat_chain_update
    117    */
    118   nkcid = kstat_chain_update(kc);
    119   if (nkcid)
    120     {
    121       /* UPDKCID will abort if nkcid is -1, so no need to check */
    122       changed = 1;
    123       kcid = nkcid;
    124     }
    125   UPDKCID(nkcid,0);
    126 
    127   if (debug) {
    128     fprintf(where,"kstat_lookup for unix/system_misc\n");
    129     fflush(where);
    130   }
    131 
    132   ks = kstat_lookup(kc, "unix", 0, "system_misc");
    133   if (kstat_read(kc, ks, 0) == -1) {
    134     perror("kstat_read");
    135     exit(1);
    136   }
    137 
    138 
    139   if (changed) {
    140 
    141     /*
    142      * 2. get data addresses
    143      */
    144 
    145     ncpu = 0;
    146 
    147     kn = kstat_data_lookup(ks, "ncpus");
    148     if (kn && kn->value.ui32 > lib_num_loc_cpus) {
    149       fprintf(stderr,"number of CPU's mismatch!");
    150       exit(1);
    151     }
    152 
    153     for (ks = kc->kc_chain; ks;
    154          ks = ks->ks_next)
    155       {
    156         if (strncmp(ks->ks_name, "cpu_stat", 8) == 0)
    157           {
    158             nkcid = kstat_read(kc, ks, NULL);
    159             /* if kcid changed, pointer might be invalid. we'll deal
    160                wtih changes at this stage, but will not accept them
    161                when we are actually in the middle of reading
    162                values. hopefully this is not going to be a big
    163                issue. raj 8/2000 */
    164             UPDKCID(nkcid, kcid);
    165 
    166             if (debug) {
    167               fprintf(where,"cpu_ks[%d] getting %p\n",ncpu,ks);
    168               fflush(where);
    169             }
    170 
    171             cpu_ks[ncpu] = ks;
    172             ncpu++;
    173             if (ncpu > lib_num_loc_cpus)
    174               {
    175                 /* with the check above, would we ever hit this? */
    176                 fprintf(stderr,
    177                         "kstat finds too many cpus %d: should be %d\n",
    178                         ncpu,lib_num_loc_cpus);
    179                 exit(1);
    180               }
    181           }
    182       }
    183     /* note that ncpu could be less than ncpus, but that's okay */
    184     changed = 0;
    185   }
    186 }
    187 
    188 /* return the value of the idle tick counter for the specified CPU */
    189 static long
    190 get_kstat_idle(cpu)
    191      int cpu;
    192 {
    193   cpu_stat_t cpu_stat;
    194   kid_t nkcid;
    195 
    196   if (debug) {
    197     fprintf(where,
    198             "get_kstat_idle reading with kc %x and ks %p\n",
    199             kc,
    200             cpu_ks[cpu]);
    201   }
    202 
    203   nkcid = kstat_read(kc, cpu_ks[cpu], &cpu_stat);
    204   /* if kcid changed, pointer might be invalid, fail the test */
    205   UPDKCID(nkcid, kcid);
    206 
    207   return(cpu_stat.cpu_sysinfo.cpu[CPU_IDLE]);
    208 
    209  kcid_changed:
    210   perror("kcid changed midstream and I cannot deal with that!");
    211   exit(1);
    212 }
    213 
    214 void
    215 cpu_util_init(void)
    216 {
    217   open_kstat();
    218   return;
    219 }
    220 
    221 void
    222 cpu_util_terminate(void)
    223 {
    224   return;
    225 }
    226 
    227 int
    228 get_cpu_method(void)
    229 {
    230   return KSTAT;
    231 }
    232 
    233 void
    234 get_cpu_idle(uint64_t *res)
    235 {
    236 
    237   int i;
    238 
    239   /* this open may be redundant */
    240   open_kstat();
    241 
    242   for (i = 0; i < lib_num_loc_cpus; i++){
    243     res[i] = get_kstat_idle(i);
    244   }
    245   return;
    246 }
    247 
    248 float
    249 calibrate_idle_rate(int iterations, int interval)
    250 {
    251 
    252   long
    253     firstcnt[MAXCPUS],
    254     secondcnt[MAXCPUS];
    255 
    256   float
    257     elapsed,
    258     temp_rate,
    259     rate[MAXTIMES],
    260     local_maxrate;
    261 
    262   long
    263     sec,
    264     usec;
    265 
    266   int
    267     i,
    268     j;
    269 
    270   struct  timeval time1, time2 ;
    271   struct  timezone tz;
    272 
    273   if (debug) {
    274     fprintf(where,"calling open_kstat from calibrate_kstat\n");
    275     fflush(where);
    276   }
    277 
    278   open_kstat();
    279 
    280   if (iterations > MAXTIMES) {
    281     iterations = MAXTIMES;
    282   }
    283 
    284   local_maxrate = (float)-1.0;
    285 
    286   for(i = 0; i < iterations; i++) {
    287     rate[i] = (float)0.0;
    288     for (j = 0; j < lib_num_loc_cpus; j++) {
    289       firstcnt[j] = get_kstat_idle(j);
    290     }
    291     gettimeofday (&time1, &tz);
    292     sleep(interval);
    293     gettimeofday (&time2, &tz);
    294 
    295     if (time2.tv_usec < time1.tv_usec)
    296       {
    297         time2.tv_usec += 1000000;
    298         time2.tv_sec -=1;
    299       }
    300     sec = time2.tv_sec - time1.tv_sec;
    301     usec = time2.tv_usec - time1.tv_usec;
    302     elapsed = (float)sec + ((float)usec/(float)1000000.0);
    303 
    304     if(debug) {
    305       fprintf(where, "Calibration for kstat counter run: %d\n",i);
    306       fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
    307       fprintf(where,"\telapsed time = %g\n",elapsed);
    308     }
    309 
    310     for (j = 0; j < lib_num_loc_cpus; j++) {
    311       secondcnt[j] = get_kstat_idle(j);
    312       if(debug) {
    313         /* I know that there are situations where compilers know about */
    314         /* long long, but the library functions do not... raj 4/95 */
    315         fprintf(where,
    316                 "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n",
    317                 j,
    318                 firstcnt[j],
    319                 firstcnt[j],
    320                 j,
    321                 secondcnt[j],
    322                 secondcnt[j]);
    323       }
    324       /* we assume that it would wrap no more than once. we also */
    325       /* assume that the result of subtracting will "fit" raj 4/95 */
    326       temp_rate = (secondcnt[j] >= firstcnt[j]) ?
    327         (float)(secondcnt[j] - firstcnt[j])/elapsed :
    328           (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed;
    329       if (temp_rate > rate[i]) rate[i] = temp_rate;
    330       if(debug) {
    331         fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
    332         fflush(where);
    333       }
    334       if (local_maxrate < rate[i]) local_maxrate = rate[i];
    335     }
    336   }
    337   if(debug) {
    338     fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
    339     fflush(where);
    340   }
    341   return local_maxrate;
    342 }
    343 
    344 float
    345 calc_cpu_util_internal(float elapsed_time)
    346 {
    347   int i;
    348   float correction_factor;
    349   float actual_rate;
    350 
    351   lib_local_cpu_util = (float)0.0;
    352   /* It is possible that the library measured a time other than */
    353   /* the one that the user want for the cpu utilization */
    354   /* calculations - for example, tests that were ended by */
    355   /* watchdog timers such as the udp stream test. We let these */
    356   /* tests tell up what the elapsed time should be. */
    357 
    358   if (elapsed_time != 0.0) {
    359     correction_factor = (float) 1.0 +
    360       ((lib_elapsed - elapsed_time) / elapsed_time);
    361   }
    362   else {
    363     correction_factor = (float) 1.0;
    364   }
    365 
    366   for (i = 0; i < lib_num_loc_cpus; i++) {
    367 
    368     /* it would appear that on some systems, in loopback, nice is
    369      *very* effective, causing the looper process to stop dead in its
    370      tracks. if this happens, we need to ensure that the calculation
    371      does not go south. raj 6/95 and if we run completely out of idle,
    372      the same thing could in theory happen to the USE_KSTAT path. raj
    373      8/2000 */
    374 
    375     if (lib_end_count[i] == lib_start_count[i]) {
    376       lib_end_count[i]++;
    377     }
    378 
    379     actual_rate = (lib_end_count[i] > lib_start_count[i]) ?
    380       (float)(lib_end_count[i] - lib_start_count[i])/lib_elapsed :
    381       (float)(lib_end_count[i] - lib_start_count[i] +
    382 	      MAXLONG)/ lib_elapsed;
    383     if (debug) {
    384       fprintf(where,
    385               "calc_cpu_util: actual_rate on processor %d is %f start %lx end %lx\n",
    386               i,
    387               actual_rate,
    388               lib_start_count[i],
    389               lib_end_count[i]);
    390     }
    391     lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
    392       lib_local_maxrate * 100;
    393     lib_local_cpu_util += lib_local_per_cpu_util[i];
    394   }
    395   /* we want the average across all n processors */
    396   lib_local_cpu_util /= (float)lib_num_loc_cpus;
    397 
    398   lib_local_cpu_util *= correction_factor;
    399   return lib_local_cpu_util;
    400 
    401 
    402 }
    403 
    404 void
    405 cpu_start_internal(void)
    406 {
    407   get_cpu_idle(lib_start_count);
    408   return;
    409 }
    410 
    411 void
    412 cpu_stop_internal(void)
    413 {
    414   get_cpu_idle(lib_end_count);
    415 }
    416