1 char netcpu_pstatnew_id[]="\
2 @(#)netcpu_pstatnew.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.1";
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 void
cpu_util_init(void)64 cpu_util_init(void)
65 {
66 return;
67 }
68
69 void
cpu_util_terminate(void)70 cpu_util_terminate(void)
71 {
72 return;
73 }
74
75 int
get_cpu_method(void)76 get_cpu_method(void)
77 {
78 return HP_IDLE_COUNTER;
79 }
80
81 void
get_cpu_counters(cpu_time_counters_t * res)82 get_cpu_counters(cpu_time_counters_t *res)
83 {
84 /* get the idle sycle counter for each processor. now while on a
85 64-bit kernel the ".psc_hi" and ".psc_lo" fields are 64 bits,
86 only the bottom 32-bits are actually valid. don't ask me
87 why, that is just the way it is. soo, we shift the psc_hi
88 value by 32 bits and then just sum-in the psc_lo value. raj
89 2005/09/06 */
90 struct pst_processor *psp;
91
92 psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
93 if (psp == NULL) {
94 printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
95 exit(1);
96 }
97 if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
98 int i;
99 /* we use lib_iticksperclktick in our sanity checking. we
100 ass-u-me it is the same value for each CPU - famous last
101 words no doubt. raj 2005/09/06 */
102 lib_iticksperclktick = psp[0].psp_iticksperclktick;
103 for (i = 0; i < lib_num_loc_cpus; i++) {
104 res[i].idle = (((uint64_t)psp[i].psp_idlecycles.psc_hi << 32) +
105 psp[i].psp_idlecycles.psc_lo);
106 if(debug) {
107 fprintf(where,
108 "\tidle[%d] = 0x%"PRIx64" ",
109 i,
110 res[i].idle);
111 fflush(where);
112 }
113 res[i].user = (((uint64_t)psp[i].psp_usercycles.psc_hi << 32) +
114 psp[i].psp_usercycles.psc_lo);
115 if(debug) {
116 fprintf(where,
117 "user[%d] = 0x%"PRIx64" ",
118 i,
119 res[i].user);
120 fflush(where);
121 }
122 res[i].kernel = (((uint64_t)psp[i].psp_systemcycles.psc_hi << 32) +
123 psp[i].psp_systemcycles.psc_lo);
124 if(debug) {
125 fprintf(where,
126 "kern[%d] = 0x%"PRIx64" ",
127 i,
128 res[i].kernel);
129 fflush(where);
130 }
131 res[i].interrupt = (((uint64_t)psp[i].psp_interruptcycles.psc_hi << 32) +
132 psp[i].psp_interruptcycles.psc_lo);
133 if(debug) {
134 fprintf(where,
135 "intr[%d] = 0x%"PRIx64"\n",
136 i,
137 res[i].interrupt);
138 fflush(where);
139 }
140 }
141 free(psp);
142 }
143 }
144
145 /* calibrate_pstatnew
146 there really isn't anything much to do here since we have all the
147 counters and use their ratios for CPU util measurement. raj
148 2005-02-16 */
149
150 float
calibrate_idle_rate(int iterations,int interval)151 calibrate_idle_rate(int iterations, int interval)
152 {
153 return 0.0;
154 }
155
156 static void
print_cpu_time_counters(char * name,int instance,cpu_time_counters_t * counters)157 print_cpu_time_counters(char *name, int instance, cpu_time_counters_t *counters)
158 {
159 fprintf(where,"%s[%d]:\n",name,instance);
160 fprintf(where,
161 "\t idle %llu\n",counters[instance].idle);
162 fprintf(where,
163 "\t user %llu\n",counters[instance].user);
164 fprintf(where,
165 "\t kernel %llu\n",counters[instance].kernel);
166 fprintf(where,
167 "\t interrupt %llu\n",counters[instance].interrupt);
168 }
169
170 float
calc_cpu_util_internal(float elapsed_time)171 calc_cpu_util_internal(float elapsed_time)
172 {
173 int i;
174
175 uint64_t total_cpu_cycles;
176 uint64_t sanity_cpu_cycles;
177
178 #ifndef USE_INTEGER_MATH
179 double fraction_idle;
180 double fraction_user;
181 double fraction_kernel;
182 double fraction_interrupt;
183 double estimated_fraction_interrupt;
184 #else
185 uint64_t fraction_idle;
186 uint64_t fraction_user;
187 uint64_t fraction_kernel;
188 uint64_t fraction_interrupt;
189 uint64_t estimated_fraction_interrupt;
190
191 #define CALC_PERCENT 100
192 #define CALC_TENTH_PERCENT 1000
193 #define CALC_HUNDREDTH_PERCENT 10000
194 #define CALC_THOUSANDTH_PERCENT 100000
195 #define CALC_ACCURACY CALC_THOUSANDTH_PERCENT
196
197 #endif /* USE_INTEGER_MATH */
198 float actual_rate;
199 float correction_factor;
200
201 lib_local_cpu_util = (float)0.0;
202
203 /* It is possible that the library measured a time other than */
204 /* the one that the user want for the cpu utilization */
205 /* calculations - for example, tests that were ended by */
206 /* watchdog timers such as the udp stream test. We let these */
207 /* tests tell up what the elapsed time should be. */
208
209 if (elapsed_time != 0.0) {
210 correction_factor = (float) 1.0 +
211 ((lib_elapsed - elapsed_time) / elapsed_time);
212 }
213 else {
214 correction_factor = (float) 1.0;
215 }
216
217 /* calculate our sanity check on cycles */
218 if (debug) {
219 fprintf(where,
220 "lib_elapsed %g _SC_CLK_TCK %d lib_iticksperclktick %"PRIu64"\n",
221 lib_elapsed,
222 sysconf(_SC_CLK_TCK),
223 lib_iticksperclktick);
224 }
225
226 /* Ok, elsewhere I may have said that HP-UX 11.23 does the "right"
227 thing in measuring user, kernel, interrupt and idle all together
228 instead of overlapping interrupt with the others like an OS that
229 shall not be named. However.... it seems there is a bug in the
230 accounting for interrupt cycles, whereby the cycles do not get
231 properly accounted. The sum of user, kernel, interrupt and idle
232 does not equal the clock rate multiplied by the elapsed time.
233 Some cycles go missing.
234
235 Since we see agreement between netperf and glance/vsar with the
236 old "pstat" mechanism, we can presume that the accounting for
237 idle cycles is sufficiently accurate. So, while we will still do
238 math with user, kernel and interrupt cycles, we will only
239 caculate CPU utilization based on the ratio of idle to _real_
240 total cycles. I am told that a "future release" of HP-UX will
241 fix the interupt cycle accounting. raj 2005/09/14 */
242
243 /* calculate what the sum of CPU cycles _SHOULD_ be */
244 sanity_cpu_cycles = (uint64_t) ((double)lib_elapsed *
245 (double) sysconf(_SC_CLK_TCK) * (double)lib_iticksperclktick);
246
247 /* this looks just like the looper case. at least I think it */
248 /* should :) raj 4/95 */
249 for (i = 0; i < lib_num_loc_cpus; i++) {
250
251 /* we ass-u-me that these counters will never wrap during a
252 netperf run. this may not be a particularly safe thing to
253 do. raj 2005-01-28 */
254 delta_cpu_counters[i].idle = ending_cpu_counters[i].idle -
255 starting_cpu_counters[i].idle;
256 delta_cpu_counters[i].user = ending_cpu_counters[i].user -
257 starting_cpu_counters[i].user;
258 delta_cpu_counters[i].kernel = ending_cpu_counters[i].kernel -
259 starting_cpu_counters[i].kernel;
260 delta_cpu_counters[i].interrupt = ending_cpu_counters[i].interrupt -
261 starting_cpu_counters[i].interrupt;
262
263 if (debug) {
264 print_cpu_time_counters("delta_cpu_counters",i,delta_cpu_counters);
265 }
266
267 /* now get the sum, which we ass-u-me does not overflow a 64-bit
268 counter. raj 2005-02-16 */
269 total_cpu_cycles =
270 delta_cpu_counters[i].idle +
271 delta_cpu_counters[i].user +
272 delta_cpu_counters[i].kernel +
273 delta_cpu_counters[i].interrupt;
274
275 if (debug) {
276 fprintf(where,
277 "total_cpu_cycles %"PRIu64" sanity_cpu_cycles %"PRIu64" missing %"PRIu64"\n",
278 total_cpu_cycles,
279 sanity_cpu_cycles,
280 sanity_cpu_cycles - total_cpu_cycles);
281 }
282
283 /* since HP-UX 11.23 does the _RIGHT_ thing and idle/user/kernel
284 does _NOT_ overlap with interrupt, we do not have to apply any
285 correction kludge. raj 2005-02-16 */
286
287 #ifndef USE_INTEGER_MATH
288 /* when the accounting for interrupt time gets its act together,
289 we can use total_cpu_cycles rather than sanity_cpu_cycles, but
290 until then, use sanity_cpu_ccles. raj 2005/09/14 */
291
292 fraction_idle = (double)delta_cpu_counters[i].idle /
293 (double)sanity_cpu_cycles;
294
295 fraction_user = (double)delta_cpu_counters[i].user /
296 (double)sanity_cpu_cycles;
297
298 fraction_kernel = (double) delta_cpu_counters[i].kernel /
299 (double)sanity_cpu_cycles;
300
301 fraction_interrupt = (double)delta_cpu_counters[i].interrupt /
302 (double)sanity_cpu_cycles;
303
304 /* ass-u-me that it is only interrupt that is bogus, and assign
305 all the "missing" cycles to it. raj 2005/09/14 */
306 estimated_fraction_interrupt = ((double)delta_cpu_counters[i].interrupt +
307 (sanity_cpu_cycles - total_cpu_cycles)) /
308 (double)sanity_cpu_cycles;
309
310 if (debug) {
311 fprintf(where,"\tfraction_idle %g\n",fraction_idle);
312 fprintf(where,"\tfraction_user %g\n",fraction_user);
313 fprintf(where,"\tfraction_kernel %g\n",fraction_kernel);
314 fprintf(where,"\tfraction_interrupt %g WARNING, possibly under-counted!\n",fraction_interrupt);
315 fprintf(where,"\testimated_fraction_interrupt %g\n",
316 estimated_fraction_interrupt);
317 }
318
319 /* and finally, what is our CPU utilization? */
320 lib_local_per_cpu_util[i] = 100.0 - (fraction_idle * 100.0);
321 #else
322 /* and now some fun with integer math. i initially tried to
323 promote things to long doubled but that didn't seem to result
324 in happiness and joy. raj 2005-01-28 */
325
326 /* multiply by 100 and divide by total and you get whole
327 percentages. multiply by 1000 and divide by total and you get
328 tenths of percentages. multiply by 10000 and divide by total
329 and you get hundredths of percentages. etc etc etc raj
330 2005-01-28 */
331
332 /* when the accounting for interrupt time gets its act together,
333 we can use total_cpu_cycles rather than sanity_cpu_cycles, but
334 until then, use sanity_cpu_ccles. raj 2005/09/14 */
335
336 fraction_idle =
337 (delta_cpu_counters[i].idle * CALC_ACCURACY) / sanity_cpu_cycles;
338
339 fraction_user =
340 (delta_cpu_counters[i].user * CALC_ACCURACY) / sanity_cpu_cycles;
341
342 fraction_kernel =
343 (delta_cpu_counters[i].kernel * CALC_ACCURACY) / sanity_cpu_cycles;
344
345 fraction_interrupt =
346 (delta_cpu_counters[i].interrupt * CALC_ACCURACY) / sanity_cpu_cycles;
347
348
349 estimated_fraction_interrupt =
350 ((delta_cpu_counters[i].interrupt +
351 (sanity_cpu_cycles - total_cpu_cycles)) *
352 CALC_ACCURACY) / sanity_cpu_cycles;
353
354 if (debug) {
355 fprintf(where,"\tfraction_idle %"PRIu64"\n",fraction_idle);
356 fprintf(where,"\tfraction_user %"PRIu64"\n",fraction_user);
357 fprintf(where,"\tfraction_kernel %"PRIu64"\n",fraction_kernel);
358 fprintf(where,"\tfraction_interrupt %"PRIu64"WARNING, possibly under-counted!\n",fraction_interrupt);
359 fprintf(where,"\testimated_fraction_interrupt %"PRIu64"\n",
360 estimated_fraction_interrupt);
361 }
362
363 /* and finally, what is our CPU utilization? */
364 lib_local_per_cpu_util[i] = 100.0 - (((float)fraction_idle /
365 (float)CALC_ACCURACY) * 100.0);
366 #endif
367 if (debug) {
368 fprintf(where,
369 "lib_local_per_cpu_util[%d] %g\n",
370 i,
371 lib_local_per_cpu_util[i]);
372 }
373 lib_local_cpu_util += lib_local_per_cpu_util[i];
374 }
375 /* we want the average across all n processors */
376 lib_local_cpu_util /= (float)lib_num_loc_cpus;
377
378 lib_local_cpu_util *= correction_factor;
379
380 if (debug) {
381 fprintf(where,
382 "calc_cpu_util: returning %g\n",lib_local_cpu_util);
383 }
384
385 return lib_local_cpu_util;
386
387 }
388 void
cpu_start_internal(void)389 cpu_start_internal(void)
390 {
391 get_cpu_counters(starting_cpu_counters);
392 }
393
394 void
cpu_stop_internal(void)395 cpu_stop_internal(void)
396 {
397 get_cpu_counters(ending_cpu_counters);
398 }
399