1char netcpu_perfstat_id[]="\ 2@(#)netcpu_perfstat.c 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 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 68static void 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, 226 "Calibration for perfstat counter run: %d\n" 227 "\tsec = %ld usec = %ld\n" 228 "\telapsed time = %g\n", 229 i, 230 sec,usec, 231 elapsed); 232 } 233 234 for (j = 0; j < lib_num_loc_cpus; j++) { 235 secondcnt[j] = per_cpu_pointer->idle; 236 per_cpu_pointer++; 237 if(debug) { 238 /* I know that there are situations where compilers know about 239 long long, but the library functions do not... raj 4/95 */ 240 fprintf(where, 241 "\tfirstcnt[%d] = 0x%8.8lx%8.8lx secondcnt[%d] = 0x%8.8lx%8.8lx\n", 242 j, 243 firstcnt[j], 244 firstcnt[j], 245 j, 246 secondcnt[j], 247 secondcnt[j]); 248 } 249 /* we assume that it would wrap no more than once. we also 250 assume that the result of subtracting will "fit" raj 4/95 */ 251 temp_rate = (secondcnt[j] >= firstcnt[j]) ? 252 (float)(secondcnt[j] - firstcnt[j])/elapsed : 253 (float)(secondcnt[j]-firstcnt[j]+MAXLONG)/elapsed; 254 if (temp_rate > rate[i]) rate[i] = temp_rate; 255 if(debug) { 256 fprintf(where,"\trate[%d] = %g\n",i,rate[i]); 257 fflush(where); 258 } 259 if (local_maxrate < rate[i]) local_maxrate = rate[i]; 260 } 261 } 262 if(debug) { 263 fprintf(where,"\tlocal maxrate = %g per sec. \n",local_maxrate); 264 fflush(where); 265 } 266 free(perfstat_buffer); 267 return local_maxrate; 268} 269 270float 271calc_cpu_util_internal(float elapsed_time) 272{ 273 int i; 274 275 float actual_rate; 276 float correction_factor; 277 278 memset(&lib_local_cpu_stats, 0, sizeof(lib_local_cpu_stats)); 279 280 /* It is possible that the library measured a time other than the 281 one that the user want for the cpu utilization calculations - for 282 example, tests that were ended by watchdog timers such as the udp 283 stream test. We let these tests tell up what the elapsed time 284 should be. */ 285 286 if (elapsed_time != 0.0) { 287 correction_factor = (float) 1.0 + 288 ((lib_elapsed - elapsed_time) / elapsed_time); 289 } 290 else { 291 correction_factor = (float) 1.0; 292 } 293 294 /* this looks just like the looper case. at least I think it should 295 :) raj 4/95 */ 296 for (i = 0; i < lib_num_loc_cpus; i++) { 297 298 /* we assume that the two are not more than a long apart. I know 299 that this is bad, but trying to go from long longs to a float 300 (perhaps a double) is boggling my mind right now. raj 4/95 */ 301 302 long long 303 diff; 304 305 if (lib_end_count[i] >= lib_start_count[i]) { 306 diff = lib_end_count[i] - lib_start_count[i]; 307 } 308 else { 309 diff = lib_end_count[i] - lib_start_count[i] + LONG_LONG_MAX; 310 } 311 actual_rate = (float) diff / lib_elapsed; 312 lib_local_per_cpu_util[i] = (lib_local_maxrate - actual_rate) / 313 lib_local_maxrate * 100; 314 lib_local_cpu_stats.cpu_util += lib_local_per_cpu_util[i]; 315 if (debug) { 316 fprintf(where, 317 "calc_cpu_util: actual_rate on cpu %d is %g max_rate %g cpu %6.2f\n", 318 i, 319 actual_rate, 320 lib_local_maxrate, 321 lib_local_per_cpu_util[i]); 322 } 323 } 324 325 /* we want the average across all n processors */ 326 lib_local_cpu_stats.cpu_util /= (float)lib_num_loc_cpus; 327 328 if (debug) { 329 fprintf(where, 330 "calc_cpu_util: average across CPUs is %g\n", 331 lib_local_cpu_stats.cpu_util); 332 } 333 334 lib_local_cpu_stats.cpu_util *= correction_factor; 335 336 if (debug) { 337 fprintf(where, 338 "calc_cpu_util: returning %g\n",lib_local_cpu_stats.cpu_util); 339 } 340 341 return lib_local_cpu_stats.cpu_util; 342 343} 344void 345cpu_start_internal(void) 346{ 347 get_cpu_idle(lib_start_count); 348 return; 349} 350 351void 352cpu_stop_internal(void) 353{ 354 get_cpu_idle(lib_end_count); 355} 356