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