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