• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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