1 char   netcpu_pstat_id[]="\
2 @(#)netcpu_pstat.c (c) Copyright 2005, Hewlett-Packard Company, Version 2.4.0";
3 
4 #if HAVE_CONFIG_H
5 # include <config.h>
6 #endif
7 
8 #include <stdio.h>
9 
10 #if HAVE_INTTYPES_H
11 # include <inttypes.h>
12 #else
13 # if HAVE_STDINT_H
14 #  include <stdint.h>
15 # endif
16 #endif
17 
18 #if HAVE_LIMITS_H
19 # include <limits.h>
20 #endif
21 
22 #include <sys/dk.h>
23 #include <sys/pstat.h>
24 
25 #ifndef PSTAT_IPCINFO
26 # error Sorry, pstat() CPU utilization on 10.0 and later only
27 #endif
28 
29 #include "netsh.h"
30 #include "netlib.h"
31 
32 /* the lib_start_count and lib_end_count arrays hold the starting
33    and ending values of whatever is counting when the system is
34    idle. The rate at which this increments during a test is compared
35    with a previous calibrarion to arrive at a CPU utilization
36    percentage. raj 2005-01-26 */
37 static uint64_t  lib_start_count[MAXCPUS];
38 static uint64_t  lib_end_count[MAXCPUS];
39 
40 void
cpu_util_init(void)41 cpu_util_init(void)
42 {
43   return;
44 }
45 
46 void
cpu_util_terminate(void)47 cpu_util_terminate(void)
48 {
49   return;
50 }
51 
52 int
get_cpu_method(void)53 get_cpu_method(void)
54 {
55   return HP_IDLE_COUNTER;
56 }
57 
58 void
get_cpu_idle(uint64_t * res)59 get_cpu_idle(uint64_t *res)
60 {
61       /* get the idle sycle counter for each processor */
62       struct pst_processor *psp;
63       union overlay_u {
64         long long full;
65         long      word[2];
66       } *overlay;
67 
68       psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
69       if (psp == NULL) {
70         printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
71         exit(1);
72 	  }
73       if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
74         int i;
75         for (i = 0; i < lib_num_loc_cpus; i++) {
76           overlay = (union overlay_u *)&(res[i]);
77           overlay->word[0] = psp[i].psp_idlecycles.psc_hi;
78           overlay->word[1] = psp[i].psp_idlecycles.psc_lo;
79           if(debug) {
80             fprintf(where,
81                     "\tres[%d] = 0x%8.8x%8.8x\n",
82                     i,
83                     hi_32(&res[i]),
84                     lo_32(&res[i]));
85             fflush(where);
86           }
87         }
88         free(psp);
89       }
90 }
91 
92 /* calibrate_pstat
93    Loop a number of iterations, sleeping wait_time seconds each and
94    count how high the idle counter gets each time. Return  the measured
95    cpu rate to the calling routine.  */
96 
97 float
calibrate_idle_rate(int iterations,int interval)98 calibrate_idle_rate(int iterations, int interval)
99 {
100 
101   uint64_t
102     firstcnt[MAXCPUS],
103     secondcnt[MAXCPUS];
104 
105   float
106     elapsed,
107     temp_rate,
108     rate[MAXTIMES],
109     local_maxrate;
110 
111   long
112     sec,
113     usec;
114 
115   int
116     i,
117     j;
118 
119   long  count;
120 
121   struct  timeval time1, time2;
122   struct  timezone tz;
123 
124   struct pst_processor *psp;
125 
126   if (iterations > MAXTIMES) {
127     iterations = MAXTIMES;
128   }
129 
130   local_maxrate = -1.0;
131 
132   psp = (struct pst_processor *)malloc(lib_num_loc_cpus * sizeof(*psp));
133   if (psp == NULL) {
134     printf("malloc(%d) failed!\n", lib_num_loc_cpus * sizeof(*psp));
135     exit(1);
136   }
137 
138   for(i = 0; i < iterations; i++) {
139     rate[i] = 0.0;
140     /* get the idle sycle counter for each processor */
141     if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
142       for (j = 0; j < lib_num_loc_cpus; j++) {
143         union overlay_u {
144           long long full;
145           long      word[2];
146         } *overlay;
147         overlay = (union overlay_u *)&(firstcnt[j]);
148         overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
149         overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
150       }
151     }
152     else {
153       fprintf(where,"pstat_getprocessor failure errno %d\n",errno);
154       fflush(where);
155       exit(1);
156     }
157 
158     gettimeofday (&time1, &tz);
159     sleep(interval);
160     gettimeofday (&time2, &tz);
161 
162     if (time2.tv_usec < time1.tv_usec)
163       {
164         time2.tv_usec += 1000000;
165         time2.tv_sec -=1;
166       }
167     sec = time2.tv_sec - time1.tv_sec;
168     usec = time2.tv_usec - time1.tv_usec;
169     elapsed = (float)sec + ((float)usec/(float)1000000.0);
170 
171     if(debug) {
172       fprintf(where, "Calibration for counter run: %d\n",i);
173       fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec);
174       fprintf(where,"\telapsed time = %g\n",elapsed);
175     }
176 
177     if (pstat_getprocessor(psp, sizeof(*psp), lib_num_loc_cpus, 0) != -1) {
178       for (j = 0; j < lib_num_loc_cpus; j++) {
179         union overlay_u {
180           long long full;
181           long      word[2];
182         } *overlay;
183         overlay = (union overlay_u *)&(secondcnt[j]);
184         overlay->word[0] = psp[j].psp_idlecycles.psc_hi;
185         overlay->word[1] = psp[j].psp_idlecycles.psc_lo;
186         if(debug) {
187           /* I know that there are situations where compilers know about */
188           /* long long, but the library fucntions do not... raj 4/95 */
189           fprintf(where,
190                   "\tfirstcnt[%d] = 0x%8.8x%8.8x secondcnt[%d] = 0x%8.8x%8.8x\n",
191                   j,
192                   hi_32(&firstcnt[j]),
193                   lo_32(&firstcnt[j]),
194                   j,
195                   hi_32(&secondcnt[j]),
196                   lo_32(&secondcnt[j]));
197         }
198         temp_rate = (secondcnt[j] >= firstcnt[j]) ?
199           (float)(secondcnt[j] - firstcnt[j] )/elapsed :
200             (float)(secondcnt[j] - firstcnt[j] + LONG_LONG_MAX)/elapsed;
201         if (temp_rate > rate[i]) rate[i] = temp_rate;
202         if(debug) {
203           fprintf(where,"\trate[%d] = %g\n",i,rate[i]);
204           fflush(where);
205         }
206         if (local_maxrate < rate[i]) local_maxrate = rate[i];
207       }
208     }
209     else {
210       fprintf(where,"pstat failure; errno %d\n",errno);
211       fflush(where);
212       exit(1);
213     }
214   }
215   if(debug) {
216     fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate);
217     fflush(where);
218   }
219   return local_maxrate;
220 
221 }
222 
223 float
calc_cpu_util_internal(float elapsed_time)224 calc_cpu_util_internal(float elapsed_time)
225 {
226   int i;
227 
228   float actual_rate;
229   float correction_factor;
230 
231   lib_local_cpu_util = (float)0.0;
232   /* It is possible that the library measured a time other than */
233   /* the one that the user want for the cpu utilization */
234   /* calculations - for example, tests that were ended by */
235   /* watchdog timers such as the udp stream test. We let these */
236   /* tests tell up what the elapsed time should be. */
237 
238   if (elapsed_time != 0.0) {
239     correction_factor = (float) 1.0 +
240       ((lib_elapsed - elapsed_time) / elapsed_time);
241   }
242   else {
243     correction_factor = (float) 1.0;
244   }
245 
246   /* this looks just like the looper case. at least I think it */
247   /* should :) raj 4/95 */
248   for (i = 0; i < lib_num_loc_cpus; i++) {
249 
250     /* we assume that the two are not more than a long apart. I */
251     /* know that this is bad, but trying to go from long longs to */
252     /* a float (perhaps a double) is boggling my mind right now. */
253     /* raj 4/95 */
254 
255     long long
256       diff;
257 
258     if (lib_end_count[i] >= lib_start_count[i]) {
259       diff = lib_end_count[i] - lib_start_count[i];
260     }
261     else {
262       diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX;
263     }
264     actual_rate = (float) diff / lib_elapsed;
265     lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
266       lib_local_maxrate * 100;
267     lib_local_cpu_util += lib_local_per_cpu_util[i];
268     if (debug) {
269       fprintf(where,
270 	      "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n",
271 	      i,
272 	      actual_rate,
273 	      lib_local_maxrate,
274 	      lib_local_per_cpu_util[i]);
275     }
276   }
277 
278   /* we want the average across all n processors */
279   lib_local_cpu_util /= (float)lib_num_loc_cpus;
280 
281   if (debug) {
282     fprintf(where,
283 	    "calc_cpu_util: average across CPUs is %g\n",lib_local_cpu_util);
284   }
285 
286   lib_local_cpu_util *= correction_factor;
287 
288   if (debug) {
289     fprintf(where,
290 	    "calc_cpu_util: returning %g\n",lib_local_cpu_util);
291   }
292 
293   return lib_local_cpu_util;
294 
295 }
296 void
cpu_start_internal(void)297 cpu_start_internal(void)
298 {
299   get_cpu_idle(lib_start_count);
300   return;
301 }
302 
303 void
cpu_stop_internal(void)304 cpu_stop_internal(void)
305 {
306   get_cpu_idle(lib_end_count);
307 }
308