1char 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 41typedef 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 48uint64_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 59static cpu_time_counters_t starting_cpu_counters[MAXCPUS]; 60static cpu_time_counters_t ending_cpu_counters[MAXCPUS]; 61static 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 73static long max_proc_count; 74 75void 76cpu_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 91void 92cpu_util_terminate(void) 93{ 94 return; 95} 96 97int 98get_cpu_method(void) 99{ 100 return HP_IDLE_COUNTER; 101} 102 103void 104get_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 185float 186calibrate_idle_rate(int iterations, int interval) 187{ 188 return 0.0; 189} 190 191static void 192print_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 207float 208calc_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} 437void 438cpu_start_internal(void) 439{ 440 get_cpu_counters(starting_cpu_counters); 441} 442 443void 444cpu_stop_internal(void) 445{ 446 get_cpu_counters(ending_cpu_counters); 447} 448