• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 char   netcpu_pstat_id[]="\
2 @(#)netcpu_pstat.c (c) Copyright 2005-2012, Hewlett-Packard Company, Version 2.6.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 static 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   memset(&lib_local_cpu_stats, 0, sizeof(lib_local_cpu_stats));
232 
233   /* It is possible that the library measured a time other than */
234   /* the one that the user want for the cpu utilization */
235   /* calculations - for example, tests that were ended by */
236   /* watchdog timers such as the udp stream test. We let these */
237   /* tests tell up what the elapsed time should be. */
238 
239   if (elapsed_time != 0.0) {
240     correction_factor = (float) 1.0 +
241       ((lib_elapsed - elapsed_time) / elapsed_time);
242   }
243   else {
244     correction_factor = (float) 1.0;
245   }
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 assume that the two are not more than a long apart. I */
252     /* know that this is bad, but trying to go from long longs to */
253     /* a float (perhaps a double) is boggling my mind right now. */
254     /* raj 4/95 */
255 
256     long long
257       diff;
258 
259     if (lib_end_count[i] >= lib_start_count[i]) {
260       diff = lib_end_count[i] - lib_start_count[i];
261     }
262     else {
263       diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX;
264     }
265     actual_rate = (float) diff / lib_elapsed;
266     lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) /
267       lib_local_maxrate * 100;
268     lib_local_per_cpu_util[i] *= correction_factor;
269     lib_local_cpu_stats.cpu_util += lib_local_per_cpu_util[i];
270     if (debug) {
271       fprintf(where,
272 	      "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f cf %f\n",
273 	      i,
274 	      actual_rate,
275 	      lib_local_maxrate,
276 	      lib_local_per_cpu_util[i],
277 	      correction_factor);
278     }
279   }
280 
281   /* we want the average across all n processors */
282   lib_local_cpu_stats.cpu_util /= (float)lib_num_loc_cpus;
283 
284   if (debug) {
285     fprintf(where,
286 	    "calc_cpu_util: average across CPUs is %g\n",
287             lib_local_cpu_stats.cpu_util);
288   }
289 
290   return lib_local_cpu_stats.cpu_util;
291 
292 }
293 void
cpu_start_internal(void)294 cpu_start_internal(void)
295 {
296   get_cpu_idle(lib_start_count);
297   return;
298 }
299 
300 void
cpu_stop_internal(void)301 cpu_stop_internal(void)
302 {
303   get_cpu_idle(lib_end_count);
304 }
305