1char   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
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
63void
64cpu_util_init(void)
65{
66  return;
67}
68
69void
70cpu_util_terminate(void)
71{
72  return;
73}
74
75int
76get_cpu_method(void)
77{
78  return HP_IDLE_COUNTER;
79}
80
81void
82get_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
150float
151calibrate_idle_rate(int iterations, int interval)
152{
153  return 0.0;
154}
155
156static void
157print_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
170float
171calc_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}
388void
389cpu_start_internal(void)
390{
391  get_cpu_counters(starting_cpu_counters);
392}
393
394void
395cpu_stop_internal(void)
396{
397  get_cpu_counters(ending_cpu_counters);
398}
399