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