1char netcpu_perfstat_id[]="\ 2@(#)netcpu_perfstat.c 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 TIME_WITH_SYS_TIME 19# include <sys/time.h> 20# include <time.h> 21#else 22# if HAVE_SYS_TIME_H 23# include <sys/time.h> 24# else 25# include <time.h> 26# endif 27#endif 28 29#if HAVE_LIMITS_H 30# include <limits.h> 31# ifndef LONG_LONG_MAX 32# define LONG_LONG_MAX LLONG_MAX 33# endif /* LONG_LONG_MAX */ 34#endif 35 36#include <errno.h> 37 38#include "netsh.h" 39#include "netlib.h" 40 41/* the lib_start_count and lib_end_count arrays hold the starting 42 and ending values of whatever is counting when the system is 43 idle. The rate at which this increments during a test is compared 44 with a previous calibration to arrive at a CPU utilization 45 percentage. raj 2005-01-26 */ 46static uint64_t lib_start_count[MAXCPUS]; 47static uint64_t lib_end_count[MAXCPUS]; 48 49 50void 51cpu_util_init(void) 52{ 53 return; 54} 55 56void 57cpu_util_terminate(void) 58{ 59 return; 60} 61 62int 63get_cpu_method(void) 64{ 65 return PERFSTAT; 66} 67 68void 69get_cpu_idle(uint64_t *res) 70{ 71 perfstat_cpu_t *perfstat_buffer; 72 perfstat_cpu_t *per_cpu_pointer; 73 perfstat_id_t name; 74 int i,ret; 75 76 /* a name of "" will cause us to start from the beginning */ 77 strcpy(name.name,""); 78 perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus * 79 sizeof(perfstat_cpu_t)); 80 if (perfstat_buffer == NULL) { 81 fprintf(where, 82 "cpu_start: malloc failed errno %d\n", 83 errno); 84 fflush(where); 85 exit(-1); 86 } 87 88 /* happiness and joy, keep going */ 89 ret = perfstat_cpu(&name, 90 perfstat_buffer, 91 sizeof(perfstat_cpu_t), 92 lib_num_loc_cpus); 93 94 if ((ret == -1) || 95 (ret != lib_num_loc_cpus)) { 96 fprintf(where, 97 "cpu_start: perfstat_cpu failed/count off; errno %d cpus %d count %d\n", 98 errno, 99 lib_num_loc_cpus, 100 ret); 101 fflush(where); 102 exit(-1); 103 } 104 105 per_cpu_pointer = perfstat_buffer; 106 for (i = 0; i < lib_num_loc_cpus; i++){ 107 res[i] = per_cpu_pointer->idle; 108 per_cpu_pointer++; 109 } 110 free(perfstat_buffer); 111 112 return; 113} 114 115float 116calibrate_idle_rate(int iterations, int interval) 117{ 118 unsigned long long 119 firstcnt[MAXCPUS], 120 secondcnt[MAXCPUS]; 121 122 float 123 elapsed, 124 temp_rate, 125 rate[MAXTIMES], 126 local_maxrate; 127 128 long 129 sec, 130 usec; 131 132 int 133 i, 134 j; 135 136 struct timeval time1, time2 ; 137 struct timezone tz; 138 139 perfstat_cpu_t *perfstat_buffer; 140 perfstat_cpu_t *per_cpu_pointer; 141 perfstat_id_t name; 142 int ret; 143 144 if (debug) { 145 fprintf(where,"enter calibrate_perfstat\n"); 146 fflush(where); 147 } 148 149 if (iterations > MAXTIMES) { 150 iterations = MAXTIMES; 151 } 152 153 local_maxrate = (float)-1.0; 154 155 perfstat_buffer = (perfstat_cpu_t *)malloc(lib_num_loc_cpus * 156 sizeof(perfstat_cpu_t)); 157 if (perfstat_buffer == NULL) { 158 fprintf(where, 159 "calibrate_perfstat: malloc failed errno %d\n", 160 errno); 161 fflush(where); 162 exit(-1); 163 } 164 165 for(i = 0; i < iterations; i++) { 166 rate[i] = (float)0.0; 167 /* a name of "" will cause us to start from the beginning */ 168 strcpy(name.name,""); 169 170 /* happiness and joy, keep going */ 171 ret = perfstat_cpu(&name, 172 perfstat_buffer, 173 sizeof(perfstat_cpu_t), 174 lib_num_loc_cpus); 175 176 if ((ret == -1) || 177 (ret != lib_num_loc_cpus)) { 178 fprintf(where, 179 "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n", 180 errno, 181 lib_num_loc_cpus, 182 ret); 183 fflush(where); 184 exit(-1); 185 } 186 187 per_cpu_pointer = perfstat_buffer; 188 for (j = 0; j < lib_num_loc_cpus; j++) { 189 firstcnt[j] = per_cpu_pointer->idle; 190 per_cpu_pointer++; 191 } 192 gettimeofday (&time1, &tz); 193 sleep(interval); 194 gettimeofday (&time2, &tz); 195 196 if (time2.tv_usec < time1.tv_usec) 197 { 198 time2.tv_usec += 1000000; 199 time2.tv_sec -=1; 200 } 201 sec = time2.tv_sec - time1.tv_sec; 202 usec = time2.tv_usec - time1.tv_usec; 203 elapsed = (float)sec + ((float)usec/(float)1000000.0); 204 205 /* happiness and joy, keep going */ 206 ret = perfstat_cpu(&name, 207 perfstat_buffer, 208 sizeof(perfstat_cpu_t), 209 lib_num_loc_cpus); 210 211 if ((ret == -1) || 212 (ret != lib_num_loc_cpus)) { 213 fprintf(where, 214 "calibrate_perfstat: perfstat_cpu failed/count off; errno %d cpus %d count %d\n", 215 errno, 216 lib_num_loc_cpus, 217 ret); 218 fflush(where); 219 exit(-1); 220 } 221 222 per_cpu_pointer = perfstat_buffer; 223 224 if(debug) { 225 fprintf(where, "Calibration for perfstat counter run: %d\n",i); 226 fprintf(where,"\tsec = %ld usec = %ld\n",sec,usec); 227 fprintf(where,"\telapsed time = %g\n",elapsed); 228 } 229 230 for (j = 0; j < lib_num_loc_cpus; j++) { 231 secondcnt[j] = per_cpu_pointer->idle; 232 per_cpu_pointer++; 233 if(debug) { 234 /* I know that there are situations where compilers know about */ 235 /* long long, but the library functions do not... raj 4/95 */ 236 fprintf(where, 237 "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n", 238 j, 239 firstcnt[j], 240 firstcnt[j], 241 j, 242 secondcnt[j], 243 secondcnt[j]); 244 } 245 /* we assume that it would wrap no more than once. we also */ 246 /* assume that the result of subtracting will "fit" raj 4/95 */ 247 temp_rate = (secondcnt[j] >= firstcnt[j]) ? 248 (float)(secondcnt[j] - firstcnt[j])/elapsed : 249 (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed; 250 if (temp_rate > rate[i]) rate[i] = temp_rate; 251 if(debug) { 252 fprintf(where,"\trate[%d] = %g\n",i,rate[i]); 253 fflush(where); 254 } 255 if (local_maxrate < rate[i]) local_maxrate = rate[i]; 256 } 257 } 258 if(debug) { 259 fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate); 260 fflush(where); 261 } 262 free(perfstat_buffer); 263 return local_maxrate; 264} 265 266float 267calc_cpu_util_internal(float elapsed_time) 268{ 269 int i; 270 271 float actual_rate; 272 float correction_factor; 273 274 lib_local_cpu_util = (float)0.0; 275 /* It is possible that the library measured a time other than */ 276 /* the one that the user want for the cpu utilization */ 277 /* calculations - for example, tests that were ended by */ 278 /* watchdog timers such as the udp stream test. We let these */ 279 /* tests tell up what the elapsed time should be. */ 280 281 if (elapsed_time != 0.0) { 282 correction_factor = (float) 1.0 + 283 ((lib_elapsed - elapsed_time) / elapsed_time); 284 } 285 else { 286 correction_factor = (float) 1.0; 287 } 288 289 /* this looks just like the looper case. at least I think it */ 290 /* should :) raj 4/95 */ 291 for (i = 0; i < lib_num_loc_cpus; i++) { 292 293 /* we assume that the two are not more than a long apart. I */ 294 /* know that this is bad, but trying to go from long longs to */ 295 /* a float (perhaps a double) is boggling my mind right now. */ 296 /* raj 4/95 */ 297 298 long long 299 diff; 300 301 if (lib_end_count[i] >= lib_start_count[i]) { 302 diff = lib_end_count[i] - lib_start_count[i]; 303 } 304 else { 305 diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX; 306 } 307 actual_rate = (float) diff / lib_elapsed; 308 lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / 309 lib_local_maxrate * 100; 310 lib_local_cpu_util += lib_local_per_cpu_util[i]; 311 if (debug) { 312 fprintf(where, 313 "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n", 314 i, 315 actual_rate, 316 lib_local_maxrate, 317 lib_local_per_cpu_util[i]); 318 } 319 } 320 321 /* we want the average across all n processors */ 322 lib_local_cpu_util /= (float)lib_num_loc_cpus; 323 324 if (debug) { 325 fprintf(where, 326 "calc_cpu_util: average across CPUs is %g\n",lib_local_cpu_util); 327 } 328 329 lib_local_cpu_util *= correction_factor; 330 331 if (debug) { 332 fprintf(where, 333 "calc_cpu_util: returning %g\n",lib_local_cpu_util); 334 } 335 336 return lib_local_cpu_util; 337 338} 339void 340cpu_start_internal(void) 341{ 342 get_cpu_idle(lib_start_count); 343 return; 344} 345 346void 347cpu_stop_internal(void) 348{ 349 get_cpu_idle(lib_end_count); 350} 351 352