| char netcpu_pstatnew_id[]="\ |
| @(#)netcpu_pstatnew.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.1"; |
| |
| /* since we "know" that this interface is available only on 11.23 and |
| later, and that 11.23 and later are strictly 64-bit kernels, we can |
| arbitrarily set _PSTAT64 here and not have to worry about it up in |
| the configure script and makefiles. raj 2005/09/06 */ |
| |
| #if HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include <stdio.h> |
| |
| #if HAVE_INTTYPES_H |
| # include <inttypes.h> |
| #else |
| # if HAVE_STDINT_H |
| # include <stdint.h> |
| # endif |
| #endif |
| |
| #include <unistd.h> |
| |
| #if HAVE_LIMITS_H |
| # include <limits.h> |
| #endif |
| |
| #include <sys/dk.h> |
| #include <sys/pstat.h> |
| |
| /* HP-UX 11.23 seems to have added three other cycle counters to the |
| original psp_idlecycles - one for user, one for kernel and one for |
| interrupt. so, we can now use those to calculate CPU utilization |
| without requiring any calibration phase. raj 2005-02-16 */ |
| |
| #ifndef PSTAT_IPCINFO |
| # error Sorry, pstat() CPU utilization on 10.0 and later only |
| #endif |
| |
| typedef struct cpu_time_counters { |
| uint64_t idle; |
| uint64_t user; |
| uint64_t kernel; |
| uint64_t interrupt; |
| } cpu_time_counters_t; |
| |
| uint64_t lib_iticksperclktick; |
| |
| #include "netsh.h" |
| #include "netlib.h" |
| |
| /* the lib_start_count and lib_end_count arrays hold the starting |
| and ending values of whatever is counting when the system is |
| idle. The rate at which this increments during a test is compared |
| with a previous calibrarion to arrive at a CPU utilization |
| percentage. raj 2005-01-26 */ |
| |
| static cpu_time_counters_t starting_cpu_counters[MAXCPUS]; |
| static cpu_time_counters_t ending_cpu_counters[MAXCPUS]; |
| static cpu_time_counters_t delta_cpu_counters[MAXCPUS]; |
| |
| void |
| cpu_util_init(void) |
| { |
| return; |
| } |
| |
| void |
| cpu_util_terminate(void) |
| { |
| return; |
| } |
| |
| int |
| get_cpu_method(void) |
| { |
| return HP_IDLE_COUNTER; |
| } |
| |
| void |
| get_cpu_counters(cpu_time_counters_t *res) |
| { |
| /* get the idle sycle counter for each processor. now while on a |
| 64-bit kernel the ".psc_hi" and ".psc_lo" fields are 64 bits, |
| only the bottom 32-bits are actually valid. don't ask me |
| why, that is just the way it is. soo, we shift the psc_hi |
| value by 32 bits and then just sum-in the psc_lo value. raj |
| 2005/09/06 */ |
| struct pst_processor *psp; |
| |
| psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp)); |
| if (psp == NULL) { |
| printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp)); |
| exit(1); |
| } |
| if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) { |
| int i; |
| /* we use lib_iticksperclktick in our sanity checking. we |
| ass-u-me it is the same value for each CPU - famous last |
| words no doubt. raj 2005/09/06 */ |
| lib_iticksperclktick = psp[0].psp_iticksperclktick; |
| for (i = 0; i < lib_num_loc_cpus; i++) { |
| res[i].idle = (((uint64_t)psp[i].psp_idlecycles.psc_hi << 32) + |
| psp[i].psp_idlecycles.psc_lo); |
| if(debug) { |
| fprintf(where, |
| "\tidle[%d] = 0x%"PRIx64" ", |
| i, |
| res[i].idle); |
| fflush(where); |
| } |
| res[i].user = (((uint64_t)psp[i].psp_usercycles.psc_hi << 32) + |
| psp[i].psp_usercycles.psc_lo); |
| if(debug) { |
| fprintf(where, |
| "user[%d] = 0x%"PRIx64" ", |
| i, |
| res[i].user); |
| fflush(where); |
| } |
| res[i].kernel = (((uint64_t)psp[i].psp_systemcycles.psc_hi << 32) + |
| psp[i].psp_systemcycles.psc_lo); |
| if(debug) { |
| fprintf(where, |
| "kern[%d] = 0x%"PRIx64" ", |
| i, |
| res[i].kernel); |
| fflush(where); |
| } |
| res[i].interrupt = (((uint64_t)psp[i].psp_interruptcycles.psc_hi << 32) + |
| psp[i].psp_interruptcycles.psc_lo); |
| if(debug) { |
| fprintf(where, |
| "intr[%d] = 0x%"PRIx64"\n", |
| i, |
| res[i].interrupt); |
| fflush(where); |
| } |
| } |
| free(psp); |
| } |
| } |
| |
| /* calibrate_pstatnew |
| there really isn't anything much to do here since we have all the |
| counters and use their ratios for CPU util measurement. raj |
| 2005-02-16 */ |
| |
| float |
| calibrate_idle_rate(int iterations, int interval) |
| { |
| return 0.0; |
| } |
| |
| static void |
| print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters) |
| { |
| fprintf(where,"%s[%d]:\n",name,instance); |
| fprintf(where, |
| "\t idle %llu\n",counters[instance].idle); |
| fprintf(where, |
| "\t user %llu\n",counters[instance].user); |
| fprintf(where, |
| "\t kernel %llu\n",counters[instance].kernel); |
| fprintf(where, |
| "\t interrupt %llu\n",counters[instance].interrupt); |
| } |
| |
| float |
| calc_cpu_util_internal(float elapsed_time) |
| { |
| int i; |
| |
| uint64_t total_cpu_cycles; |
| uint64_t sanity_cpu_cycles; |
| |
| #ifndef USE_INTEGER_MATH |
| double fraction_idle; |
| double fraction_user; |
| double fraction_kernel; |
| double fraction_interrupt; |
| double estimated_fraction_interrupt; |
| #else |
| uint64_t fraction_idle; |
| uint64_t fraction_user; |
| uint64_t fraction_kernel; |
| uint64_t fraction_interrupt; |
| uint64_t estimated_fraction_interrupt; |
| |
| #define CALC_PERCENT 100 |
| #define CALC_TENTH_PERCENT 1000 |
| #define CALC_HUNDREDTH_PERCENT 10000 |
| #define CALC_THOUSANDTH_PERCENT 100000 |
| #define CALC_ACCURACY CALC_THOUSANDTH_PERCENT |
| |
| #endif /* USE_INTEGER_MATH */ |
| float actual_rate; |
| float correction_factor; |
| |
| lib_local_cpu_util = (float)0.0; |
| |
| /* It is possible that the library measured a time other than */ |
| /* the one that the user want for the cpu utilization */ |
| /* calculations - for example, tests that were ended by */ |
| /* watchdog timers such as the udp stream test. We let these */ |
| /* tests tell up what the elapsed time should be. */ |
| |
| if (elapsed_time != 0.0) { |
| correction_factor = (float) 1.0 + |
| ((lib_elapsed - elapsed_time) / elapsed_time); |
| } |
| else { |
| correction_factor = (float) 1.0; |
| } |
| |
| /* calculate our sanity check on cycles */ |
| if (debug) { |
| fprintf(where, |
| "lib_elapsed %g _SC_CLK_TCK %d lib_iticksperclktick %"PRIu64"\n", |
| lib_elapsed, |
| sysconf(_SC_CLK_TCK), |
| lib_iticksperclktick); |
| } |
| |
| /* Ok, elsewhere I may have said that HP-UX 11.23 does the "right" |
| thing in measuring user, kernel, interrupt and idle all together |
| instead of overlapping interrupt with the others like an OS that |
| shall not be named. However.... it seems there is a bug in the |
| accounting for interrupt cycles, whereby the cycles do not get |
| properly accounted. The sum of user, kernel, interrupt and idle |
| does not equal the clock rate multiplied by the elapsed time. |
| Some cycles go missing. |
| |
| Since we see agreement between netperf and glance/vsar with the |
| old "pstat" mechanism, we can presume that the accounting for |
| idle cycles is sufficiently accurate. So, while we will still do |
| math with user, kernel and interrupt cycles, we will only |
| caculate CPU utilization based on the ratio of idle to _real_ |
| total cycles. I am told that a "future release" of HP-UX will |
| fix the interupt cycle accounting. raj 2005/09/14 */ |
| |
| /* calculate what the sum of CPU cycles _SHOULD_ be */ |
| sanity_cpu_cycles = (uint64_t) ((double)lib_elapsed * |
| (double) sysconf(_SC_CLK_TCK) * (double)lib_iticksperclktick); |
| |
| /* this looks just like the looper case. at least I think it */ |
| /* should :) raj 4/95 */ |
| for (i = 0; i < lib_num_loc_cpus; i++) { |
| |
| /* we ass-u-me that these counters will never wrap during a |
| netperf run. this may not be a particularly safe thing to |
| do. raj 2005-01-28 */ |
| delta_cpu_counters[i].idle = ending_cpu_counters[i].idle - |
| starting_cpu_counters[i].idle; |
| delta_cpu_counters[i].user = ending_cpu_counters[i].user - |
| starting_cpu_counters[i].user; |
| delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel - |
| starting_cpu_counters[i].kernel; |
| delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt - |
| starting_cpu_counters[i].interrupt; |
| |
| if (debug) { |
| print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters); |
| } |
| |
| /* now get the sum, which we ass-u-me does not overflow a 64-bit |
| counter. raj 2005-02-16 */ |
| total_cpu_cycles = |
| delta_cpu_counters[i].idle + |
| delta_cpu_counters[i].user + |
| delta_cpu_counters[i].kernel + |
| delta_cpu_counters[i].interrupt; |
| |
| if (debug) { |
| fprintf(where, |
| "total_cpu_cycles %"PRIu64" sanity_cpu_cycles %"PRIu64" missing %"PRIu64"\n", |
| total_cpu_cycles, |
| sanity_cpu_cycles, |
| sanity_cpu_cycles - total_cpu_cycles); |
| } |
| |
| /* since HP-UX 11.23 does the _RIGHT_ thing and idle/user/kernel |
| does _NOT_ overlap with interrupt, we do not have to apply any |
| correction kludge. raj 2005-02-16 */ |
| |
| #ifndef USE_INTEGER_MATH |
| /* when the accounting for interrupt time gets its act together, |
| we can use total_cpu_cycles rather than sanity_cpu_cycles, but |
| until then, use sanity_cpu_ccles. raj 2005/09/14 */ |
| |
| fraction_idle = (double)delta_cpu_counters[i].idle / |
| (double)sanity_cpu_cycles; |
| |
| fraction_user = (double)delta_cpu_counters[i].user / |
| (double)sanity_cpu_cycles; |
| |
| fraction_kernel = (double) delta_cpu_counters[i].kernel / |
| (double)sanity_cpu_cycles; |
| |
| fraction_interrupt = (double)delta_cpu_counters[i].interrupt / |
| (double)sanity_cpu_cycles; |
| |
| /* ass-u-me that it is only interrupt that is bogus, and assign |
| all the "missing" cycles to it. raj 2005/09/14 */ |
| estimated_fraction_interrupt = ((double)delta_cpu_counters[i].interrupt + |
| (sanity_cpu_cycles - total_cpu_cycles)) / |
| (double)sanity_cpu_cycles; |
| |
| if (debug) { |
| fprintf(where,"\tfraction_idle %g\n",fraction_idle); |
| fprintf(where,"\tfraction_user %g\n",fraction_user); |
| fprintf(where,"\tfraction_kernel %g\n",fraction_kernel); |
| fprintf(where,"\tfraction_interrupt %g WARNING, possibly under-counted!\n",fraction_interrupt); |
| fprintf(where,"\testimated_fraction_interrupt %g\n", |
| estimated_fraction_interrupt); |
| } |
| |
| /* and finally, what is our CPU utilization? */ |
| lib_local_per_cpu_util[i] = 100.0 - (fraction_idle * 100.0); |
| #else |
| /* and now some fun with integer math. i initially tried to |
| promote things to long doubled but that didn't seem to result |
| in happiness and joy. raj 2005-01-28 */ |
| |
| /* multiply by 100 and divide by total and you get whole |
| percentages. multiply by 1000 and divide by total and you get |
| tenths of percentages. multiply by 10000 and divide by total |
| and you get hundredths of percentages. etc etc etc raj |
| 2005-01-28 */ |
| |
| /* when the accounting for interrupt time gets its act together, |
| we can use total_cpu_cycles rather than sanity_cpu_cycles, but |
| until then, use sanity_cpu_ccles. raj 2005/09/14 */ |
| |
| fraction_idle = |
| (delta_cpu_counters[i].idle * CALC_ACCURACY) / sanity_cpu_cycles; |
| |
| fraction_user = |
| (delta_cpu_counters[i].user * CALC_ACCURACY) / sanity_cpu_cycles; |
| |
| fraction_kernel = |
| (delta_cpu_counters[i].kernel * CALC_ACCURACY) / sanity_cpu_cycles; |
| |
| fraction_interrupt = |
| (delta_cpu_counters[i].interrupt * CALC_ACCURACY) / sanity_cpu_cycles; |
| |
| |
| estimated_fraction_interrupt = |
| ((delta_cpu_counters[i].interrupt + |
| (sanity_cpu_cycles - total_cpu_cycles)) * |
| CALC_ACCURACY) / sanity_cpu_cycles; |
| |
| if (debug) { |
| fprintf(where,"\tfraction_idle %"PRIu64"\n",fraction_idle); |
| fprintf(where,"\tfraction_user %"PRIu64"\n",fraction_user); |
| fprintf(where,"\tfraction_kernel %"PRIu64"\n",fraction_kernel); |
| fprintf(where,"\tfraction_interrupt %"PRIu64"WARNING, possibly under-counted!\n",fraction_interrupt); |
| fprintf(where,"\testimated_fraction_interrupt %"PRIu64"\n", |
| estimated_fraction_interrupt); |
| } |
| |
| /* and finally, what is our CPU utilization? */ |
| lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle / |
| (float)CALC_ACCURACY) * 100.0); |
| #endif |
| if (debug) { |
| fprintf(where, |
| "lib_local_per_cpu_util[%d] %g\n", |
| i, |
| lib_local_per_cpu_util[i]); |
| } |
| lib_local_cpu_util += lib_local_per_cpu_util[i]; |
| } |
| /* we want the average across all n processors */ |
| lib_local_cpu_util /= (float)lib_num_loc_cpus; |
| |
| lib_local_cpu_util *= correction_factor; |
| |
| if (debug) { |
| fprintf(where, |
| "calc_cpu_util: returning %g\n",lib_local_cpu_util); |
| } |
| |
| return lib_local_cpu_util; |
| |
| } |
| void |
| cpu_start_internal(void) |
| { |
| get_cpu_counters(starting_cpu_counters); |
| } |
| |
| void |
| cpu_stop_internal(void) |
| { |
| get_cpu_counters(ending_cpu_counters); |
| } |