00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "config.h"
00019
00020 #include <ctype.h>
00021 #include <errno.h>
00022 #include <stdio.h>
00023 #include <fcntl.h>
00024 #include <string.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027
00028 #include <sys/types.h>
00029
00030 #include "assert_pp.h"
00031 #include "instrumentation.h"
00032
00033 #include <rk.h>
00034 #include "rk_util.h"
00035
00036
00037
00038 #if defined(INSTR_rk_resource_set_get_usage_data)
00039 static struct iPoint INSTR_get_point = {
00040 INSTR_rk_resource_set_get_usage_data,
00041 };
00042 #endif
00043
00044 #if defined(INSTR_rk_proc_usage_data)
00045 static struct iPoint INSTR_rk_proc_usage_point = {
00046 INSTR_rk_proc_usage_data,
00047 };
00048 #endif
00049
00050
00051
00052 rk_resource_set_t rk_resource_set_get_by_name(const char *name)
00053 {
00054 rk_resource_set_t retval = NULL_RESOURCE_SET;
00055 #define MAX_RK_SETS 128
00056 rk_resource_set_t rk_sets[MAX_RK_SETS];
00057 char rs_name[RK_NAME_LEN + 1];
00058 int lpc, actual;
00059
00060 require(name != NULL);
00061
00062 actual = rk_resource_sets_get_list(rk_sets, MAX_RK_SETS);
00063 for( lpc = 0; (lpc < actual) && (retval == NULL_RESOURCE_SET); lpc++ )
00064 {
00065 rs_name[0] = '\0';
00066 if( (rk_resource_set_get_name(rk_sets[lpc], rs_name) == 0) &&
00067 (strcmp(rs_name, name) == 0) )
00068 {
00069 retval = rk_sets[lpc];
00070 }
00071 }
00072 #undef MAX_RK_SETS
00073 return( retval );
00074 }
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 static int rk_resource_set_proc_compare(const void *a, const void *b)
00086 {
00087 rk_resource_set_proc_t pca, pcb;
00088 int retval = 0;
00089
00090 require(a != NULL);
00091 require(b != NULL);
00092
00093 pca = (rk_resource_set_proc_t)a;
00094 pcb = (rk_resource_set_proc_t)b;
00095
00096 if( pca->pid < pcb->pid )
00097 retval = -1;
00098 else if( pca->pid == pcb->pid )
00099 retval = 0;
00100 else if( pca->pid > pcb->pid )
00101 retval = 1;
00102
00103 ensure(retval >= -1);
00104 ensure(retval <= 1);
00105
00106 return( retval );
00107 }
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 static int rk_resource_set_proc_cache_search(rk_resource_set_proc_cache_t pc,
00118 pid_t pid)
00119 {
00120 int high, low = 0, probe, retval;
00121
00122 require(pc != NULL);
00123 require(pc->data != NULL);
00124 require(pc->used <= pc->length);
00125 require(pid != 0);
00126
00127
00128 high = pc->used;
00129 while( low <= (high - 1) )
00130 {
00131 probe = (low + high) / 2;
00132 if( pid > pc->data[probe].pid )
00133 low = probe + 1;
00134 else
00135 high = probe;
00136 }
00137 if( (high >= pc->used) || (pc->data[high].pid != pid) )
00138 {
00139 retval = -1;
00140 }
00141 else
00142 {
00143 retval = high;
00144 }
00145
00146 ensure(retval >= -1);
00147 ensure((retval == -1) || (retval < pc->used));
00148 ensure((retval == -1) || (pc->data[retval].pid == pid));
00149
00150 return( retval );
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 static int rk_resource_set_proc_cache_add(rk_resource_set_proc_cache_t pc,
00162 pid_t pid)
00163 {
00164 int retval = -1;
00165
00166 require(pc != NULL);
00167 require(pc->data != NULL);
00168 require(pc->used <= pc->length);
00169 require(pid != 0);
00170
00171
00172 if( pc->used < pc->length )
00173 {
00174 int index;
00175
00176
00177 index = pc->used;
00178 pc->used += 1;
00179
00180 pc->data[index].pid = pid;
00181 pc->data[index].fd = -1;
00182 pc->data[index].cpu_usage = 0;
00183
00184 qsort(pc->data,
00185 pc->used,
00186 sizeof(struct rk_resource_set_proc),
00187 rk_resource_set_proc_compare);
00188
00189 retval = rk_resource_set_proc_cache_search(pc, pid);
00190 }
00191
00192 ensure(retval >= -1);
00193 ensure(retval < pc->used);
00194 ensure((retval == -1) || (pc->data[retval].pid == pid));
00195
00196 return( retval );
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 static unsigned long long rk_resource_set_proc_cache_intersect(
00208 rk_resource_set_proc_cache_t pc, pid_t *procs, size_t procs_length)
00209 {
00210 unsigned long long retval = 0;
00211 unsigned int lpc;
00212
00213 require(pc != NULL);
00214 require(pc->data != NULL);
00215 require(pc->used <= pc->length);
00216 require(procs != NULL);
00217
00218 for( lpc = 0; lpc < pc->used; )
00219 {
00220 int lpc2;
00221
00222
00223 for( lpc2 = 0;
00224 (lpc2 < procs_length) && (procs[lpc2] != pc->data[lpc].pid);
00225 lpc2++ )
00226 {
00227 }
00228
00229 if( lpc2 == procs_length )
00230 {
00231 close(pc->data[lpc].fd);
00232 retval += pc->data[lpc].cpu_usage;
00233 pc->data[lpc] = pc->data[lpc + 1];
00234 pc->used -= 1;
00235 }
00236 else
00237 {
00238 lpc += 1;
00239 }
00240 }
00241 return( retval );
00242 }
00243
00244 int rk_resource_set_get_usage(rk_resource_set_t rs,
00245 rk_resource_set_usage_t rsu_inout,
00246 rk_resource_set_proc_cache_t pc_inout)
00247 {
00248 int retval = 0;
00249
00250 if( (rs == NULL) || (rsu_inout == NULL) )
00251 {
00252 retval = EINVAL;
00253 }
00254 else if( (pc_inout != NULL) && (pc_inout->used > pc_inout->length) )
00255 {
00256 retval = EINVAL;
00257 }
00258 else
00259 {
00260 #define MAX_PID_COUNT 128
00261 pid_t procs[MAX_PID_COUNT];
00262 int lpc;
00263
00264
00265 rsu_inout->proc_count =
00266 rk_resource_set_get_proclist(rs, procs, MAX_PID_COUNT);
00267 rsu_inout->active_cpu_usage = 0;
00268
00269 for( lpc = 0;
00270 (lpc < rsu_inout->proc_count) && (retval == 0);
00271 lpc++ )
00272 {
00273 int index = -1, file = -1, cached;
00274 char scratch[1024];
00275
00276
00277 if( (pc_inout == NULL) ||
00278 (index = rk_resource_set_proc_cache_search(
00279 pc_inout, procs[lpc])) == -1 )
00280 {
00281
00282 snprintf(scratch,
00283 sizeof(scratch),
00284 "/proc/%d/stat",
00285 procs[lpc]);
00286 if( (file = open(scratch, O_RDONLY)) == -1 )
00287 {
00288 cached = 0;
00289 retval = errno;
00290 }
00291
00292 else if( (pc_inout == NULL) ||
00293 (index = rk_resource_set_proc_cache_add(
00294 pc_inout,
00295 procs[lpc])) == -1 )
00296 {
00297 cached = 0;
00298 }
00299 else
00300 {
00301 pc_inout->data[index].fd = file;
00302 cached = 1;
00303 }
00304 }
00305 else
00306 {
00307 file = pc_inout->data[index].fd;
00308 if( lseek(file, 0, SEEK_SET) == -1 )
00309 {
00310 perror("lseek");
00311 ensure(0);
00312 }
00313 cached = 1;
00314 }
00315
00316 if( file != -1 )
00317 {
00318 unsigned long long usage = 0;
00319 struct timeval utime, stime;
00320 off_t off = 0;
00321 int rc;
00322
00323 memset(&utime, 0, sizeof(utime));
00324 memset(&stime, 0, sizeof(stime));
00325
00326 while( (rc = read(file,
00327 &scratch[off],
00328 sizeof(scratch) - off)) > 0 )
00329 {
00330 off += rc;
00331 if( scratch[off - 1] == '\n' ) break;
00332 }
00333 if( rc == -1 )
00334 {
00335 retval = errno;
00336 }
00337 else
00338 {
00339 int index, saved_index, space_count = 0, len;
00340
00341 scratch[off] = '\0';
00342 len = strlen(scratch);
00343
00344
00345
00346
00347
00348
00349 saved_index = len - 1;
00350 for( index = len - 1; index > (len - 20); index-- )
00351 {
00352 if( scratch[index] == '\n' )
00353 saved_index = index;
00354 }
00355
00356 index = saved_index;
00357 for( ; space_count < 4; index-- )
00358 {
00359 if( isspace(scratch[index]) )
00360 {
00361 space_count += 1;
00362 }
00363 }
00364 if( sscanf(&scratch[index],
00365 "%ld %ld %ld %ld",
00366 &utime.tv_sec,
00367 &utime.tv_usec,
00368 &stime.tv_sec,
00369 &stime.tv_usec) != 4 )
00370 {
00371 fprintf(stderr,
00372 "BEGIN oscratch\n%s\nEND\n",
00373 scratch);
00374 fprintf(stderr, "scratch %s\n", &scratch[index]);
00375 retval = ENOSYS;
00376 }
00377 }
00378
00379 usage += utime.tv_sec * 1000000;
00380 usage += utime.tv_usec;
00381 usage += stime.tv_sec * 1000000;
00382 usage += stime.tv_usec;
00383 INSTR_rk_proc_usage(&INSTR_rk_proc_usage_point, usage);
00384 rsu_inout->active_cpu_usage += usage;
00385 if( index >= 0 )
00386 {
00387 pc_inout->data[index].cpu_usage = usage;
00388 }
00389 if( !cached )
00390 {
00391 close(file);
00392 }
00393 }
00394 }
00395
00396
00397
00398
00399 if( (pc_inout != NULL) &&
00400 (pc_inout->used > rsu_inout->proc_count) )
00401 {
00402 rsu_inout->inactive_cpu_usage +=
00403 rk_resource_set_proc_cache_intersect(pc_inout,
00404 procs,
00405 rsu_inout->proc_count);
00406 }
00407 }
00408 return( retval );
00409 }
00410
00411 void rk_resource_set_proc_cache_release(rk_resource_set_proc_cache_t pc)
00412 {
00413 int lpc;
00414
00415 require(pc != NULL);
00416 require(pc->data != NULL);
00417 require(pc->used <= pc->length);
00418
00419 for( lpc = 0; lpc < pc->used; lpc++ )
00420 {
00421 close(pc->data[lpc].fd);
00422 pc->data[lpc].fd = -1;
00423 }
00424 pc->used = 0;
00425 pc = NULL;
00426 }