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