|
PAPI
5.0.1.0
|
00001 00021 #include <stdlib.h> 00022 #include <ctype.h> 00023 #include <string.h> 00024 #include <net/if.h> 00025 00026 /* Headers required by PAPI */ 00027 #include "papi.h" 00028 #include "papi_internal.h" 00029 #include "papi_vector.h" 00030 #include "papi_memory.h" 00031 00032 #include "linux-net.h" 00033 00034 00035 papi_vector_t _net_vector; 00036 00037 /********************************************************************* 00038 * Private 00039 ********************************************************************/ 00040 00041 /* Network stats refresh latency in usec (default: 1 sec) */ 00042 #define NET_REFRESH_LATENCY 1000000 00043 00044 #define NET_PROC_FILE "/proc/net/dev" 00045 00046 /* /proc/net/dev line size 00047 * interface name + 8 RX counters + 8 TX counters + separators 00048 */ 00049 #define NET_PROC_MAX_LINE (IFNAMSIZ + 16 * (20 + 1) + 16) 00050 00051 #define NET_INVALID_RESULT -1 00052 00053 00054 static NET_native_event_entry_t * _net_native_events; 00055 00056 static int num_events = 0; 00057 static int is_initialized = 0; 00058 00059 static long long _net_register_start[NET_MAX_COUNTERS]; 00060 static long long _net_register_current[NET_MAX_COUNTERS]; 00061 00062 /* temporary event */ 00063 struct temp_event { 00064 char name[PAPI_MAX_STR_LEN]; 00065 char description[PAPI_MAX_STR_LEN]; 00066 struct temp_event *next; 00067 }; 00068 static struct temp_event* root = NULL; 00069 00070 /* /proc/net/dev: network counters by interface */ 00071 #define NET_INTERFACE_COUNTERS 16 00072 00073 static const struct net_counters { 00074 char *name; 00075 char *description; 00076 } _net_counter_info[NET_INTERFACE_COUNTERS] = { 00077 /* Receive */ 00078 { "rx:bytes", "receive bytes"}, 00079 { "rx:packets", "receive packets"}, 00080 { "rx:errors", "receive errors"}, 00081 { "rx:dropped", "receive dropped"}, 00082 { "rx:fifo", "receive fifo"}, 00083 { "rx:frame", "receive frame"}, 00084 { "rx:compressed", "receive compressed"}, 00085 { "rx:multicast", "receive multicast"}, 00086 /* Transmit */ 00087 { "tx:bytes", "transmit bytes"}, 00088 { "tx:packets", "transmit packets"}, 00089 { "tx:errors", "transmit errors"}, 00090 { "tx:dropped", "transmit dropped"}, 00091 { "tx:fifo", "transmit fifo"}, 00092 { "tx:colls", "transmit colls"}, 00093 { "tx:carrier", "transmit carrier"}, 00094 { "tx:compressed", "transmit compressed"}, 00095 }; 00096 00097 00098 /********************************************************************* 00099 *** BEGIN FUNCTIONS USED INTERNALLY SPECIFIC TO THIS COMPONENT **** 00100 ********************************************************************/ 00101 00102 /* 00103 * find all network interfaces listed in /proc/net/dev 00104 */ 00105 static int 00106 generateNetEventList( void ) 00107 { 00108 FILE *fin; 00109 char line[NET_PROC_MAX_LINE]; 00110 char *retval, *ifname; 00111 int count = 0; 00112 struct temp_event *temp; 00113 struct temp_event *last = NULL; 00114 int i, j; 00115 00116 fin = fopen(NET_PROC_FILE, "r"); 00117 if (fin == NULL) { 00118 SUBDBG("Can't find %s, are you sure the /proc file-system is mounted?\n", 00119 NET_PROC_FILE); 00120 return 0; 00121 } 00122 00123 /* skip the 2 header lines */ 00124 for (i=0; i<2; i++) { 00125 retval = fgets (line, NET_PROC_MAX_LINE, fin); 00126 if (retval == NULL) { 00127 fclose(fin); 00128 SUBDBG("Not enough lines in %s\n", NET_PROC_FILE); 00129 return 0; 00130 } 00131 } 00132 00133 while ((fgets (line, NET_PROC_MAX_LINE, fin)) == line) { 00134 00135 /* split the interface name from the 16 counters */ 00136 retval = strstr(line, ":"); 00137 if (retval == NULL) { 00138 SUBDBG("Wrong line format <%s>\n", line); 00139 continue; 00140 } 00141 00142 *retval = '\0'; 00143 ifname = line; 00144 while (isspace(*ifname)) { ifname++; } 00145 00146 for (j=0; j<NET_INTERFACE_COUNTERS; j++) { 00147 00148 /* keep the interface name around */ 00149 temp = (struct temp_event *)papi_malloc(sizeof(struct temp_event)); 00150 if (!temp) { 00151 PAPIERROR("out of memory!"); 00152 fclose(fin); 00153 return PAPI_ENOMEM; 00154 } 00155 temp->next = NULL; 00156 00157 if (root == NULL) { 00158 root = temp; 00159 } else if (last) { 00160 last->next = temp; 00161 } else { 00162 free(temp); 00163 fclose(fin); 00164 PAPIERROR("This shouldn't be possible\n"); 00165 return PAPI_ECMP; 00166 } 00167 last = temp; 00168 00169 snprintf(temp->name, PAPI_MAX_STR_LEN, "%s:%s", 00170 ifname, _net_counter_info[j].name); 00171 snprintf(temp->description, PAPI_MAX_STR_LEN, "%s %s", 00172 ifname, _net_counter_info[j].description); 00173 00174 count++; 00175 } 00176 } 00177 00178 fclose(fin); 00179 00180 return count; 00181 } 00182 00183 00184 static int 00185 getInterfaceBaseIndex(const char *ifname) 00186 { 00187 int i; 00188 00189 for ( i=0; i<num_events; i+=NET_INTERFACE_COUNTERS ) { 00190 if (strncmp(_net_native_events[i].name, ifname, strlen(ifname)) == 0) { 00191 return i; 00192 } 00193 } 00194 00195 return -1; /* Not found */ 00196 } 00197 00198 00199 static int 00200 read_net_counters( long long *values ) 00201 { 00202 FILE *fin; 00203 char line[NET_PROC_MAX_LINE]; 00204 char *retval, *ifname, *data; 00205 int i, nf, if_bidx; 00206 00207 fin = fopen(NET_PROC_FILE, "r"); 00208 if (fin == NULL) { 00209 SUBDBG("Can't find %s, are you sure the /proc file-system is mounted?\n", 00210 NET_PROC_FILE); 00211 return NET_INVALID_RESULT; 00212 } 00213 00214 /* skip the 2 header lines */ 00215 for (i=0; i<2; i++) { 00216 retval = fgets (line, NET_PROC_MAX_LINE, fin); 00217 if (retval == NULL) { 00218 SUBDBG("Not enough lines in %s\n", NET_PROC_FILE); 00219 fclose(fin); 00220 return 0; 00221 } 00222 } 00223 00224 while ((fgets (line, NET_PROC_MAX_LINE, fin)) == line) { 00225 00226 /* split the interface name from its 16 counters */ 00227 retval = strstr(line, ":"); 00228 if (retval == NULL) { 00229 SUBDBG("Wrong line format <%s>\n", line); 00230 continue; 00231 } 00232 00233 *retval = '\0'; 00234 data = retval + 1; 00235 ifname = line; 00236 while (isspace(*ifname)) { ifname++; } 00237 00238 if_bidx = getInterfaceBaseIndex(ifname); 00239 if (if_bidx < 0) { 00240 SUBDBG("Interface <%s> not found\n", ifname); 00241 } else { 00242 nf = sscanf( data, 00243 "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", 00244 &values[if_bidx + 0], &values[if_bidx + 1], 00245 &values[if_bidx + 2], &values[if_bidx + 3], 00246 &values[if_bidx + 4], &values[if_bidx + 5], 00247 &values[if_bidx + 6], &values[if_bidx + 7], 00248 &values[if_bidx + 8], &values[if_bidx + 9], 00249 &values[if_bidx + 10], &values[if_bidx + 11], 00250 &values[if_bidx + 12], &values[if_bidx + 13], 00251 &values[if_bidx + 14], &values[if_bidx + 15]); 00252 00253 SUBDBG("\nRead " 00254 "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", 00255 values[if_bidx + 0], values[if_bidx + 1], 00256 values[if_bidx + 2], values[if_bidx + 3], 00257 values[if_bidx + 4], values[if_bidx + 5], 00258 values[if_bidx + 6], values[if_bidx + 7], 00259 values[if_bidx + 8], values[if_bidx + 9], 00260 values[if_bidx + 10], values[if_bidx + 11], 00261 values[if_bidx + 12], values[if_bidx + 13], 00262 values[if_bidx + 14], values[if_bidx + 15]); 00263 00264 if ( nf != NET_INTERFACE_COUNTERS ) { 00265 /* This shouldn't happen */ 00266 SUBDBG("/proc line with wrong number of fields\n"); 00267 } 00268 } 00269 00270 } 00271 00272 fclose(fin); 00273 00274 return 0; 00275 } 00276 00277 00278 /********************************************************************* 00279 *************** BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS ********* 00280 *********************************************************************/ 00281 00282 /* 00283 * This is called whenever a thread is initialized 00284 */ 00285 int 00286 _net_init_thread( hwd_context_t *ctx ) 00287 { 00288 ( void ) ctx; 00289 00290 return PAPI_OK; 00291 } 00292 00293 00294 /* Initialize hardware counters, setup the function vector table 00295 * and get hardware information, this routine is called when the 00296 * PAPI process is initialized (IE PAPI_library_init) 00297 */ 00298 int 00299 _net_init_component( int cidx ) 00300 { 00301 int i = 0; 00302 struct temp_event *t, *last; 00303 00304 if ( is_initialized ) 00305 return PAPI_OK; 00306 00307 memset(_net_register_start, 0, 00308 NET_MAX_COUNTERS*sizeof(_net_register_start[0])); 00309 memset(_net_register_current, 0, 00310 NET_MAX_COUNTERS*sizeof(_net_register_current[0])); 00311 00312 is_initialized = 1; 00313 00314 /* The network interfaces are listed in /proc/net/dev */ 00315 num_events = generateNetEventList(); 00316 00317 if ( num_events < 0 ) /* PAPI errors */ 00318 return num_events; 00319 00320 if ( num_events == 0 ) /* No network interfaces found */ 00321 return PAPI_OK; 00322 00323 t = root; 00324 _net_native_events = (NET_native_event_entry_t*) 00325 papi_malloc(sizeof(NET_native_event_entry_t) * num_events); 00326 do { 00327 strncpy(_net_native_events[i].name, t->name, PAPI_MAX_STR_LEN); 00328 strncpy(_net_native_events[i].description, t->description, PAPI_MAX_STR_LEN); 00329 _net_native_events[i].resources.selector = i + 1; 00330 last = t; 00331 t = t->next; 00332 papi_free(last); 00333 i++; 00334 } while (t != NULL); 00335 root = NULL; 00336 00337 /* Export the total number of events available */ 00338 _net_vector.cmp_info.num_native_events = num_events; 00339 00340 /* Export the component id */ 00341 _net_vector.cmp_info.CmpIdx = cidx; 00342 00343 return PAPI_OK; 00344 } 00345 00346 00347 /* 00348 * Control of counters (Reading/Writing/Starting/Stopping/Setup) 00349 * functions 00350 */ 00351 int 00352 _net_init_control_state( hwd_control_state_t *ctl ) 00353 { 00354 ( void ) ctl; 00355 00356 return PAPI_OK; 00357 } 00358 00359 00360 int 00361 _net_start( hwd_context_t *ctx, hwd_control_state_t *ctl ) 00362 { 00363 ( void ) ctx; 00364 00365 NET_control_state_t *net_ctl = (NET_control_state_t *) ctl; 00366 long long now = PAPI_get_real_usec(); 00367 00368 read_net_counters(_net_register_start); 00369 memcpy(_net_register_current, _net_register_start, 00370 NET_MAX_COUNTERS * sizeof(_net_register_start[0])); 00371 00372 /* set initial values to 0 */ 00373 memset(net_ctl->values, 0, NET_MAX_COUNTERS*sizeof(net_ctl->values[0])); 00374 00375 /* Set last access time for caching purposes */ 00376 net_ctl->lastupdate = now; 00377 00378 return PAPI_OK; 00379 } 00380 00381 00382 int 00383 _net_read( hwd_context_t *ctx, hwd_control_state_t *ctl, 00384 long long ** events, int flags ) 00385 { 00386 (void) flags; 00387 (void) ctx; 00388 00389 NET_control_state_t *net_ctl = (NET_control_state_t *) ctl; 00390 long long now = PAPI_get_real_usec(); 00391 int i; 00392 00393 /* Caching 00394 * Only read new values from /proc if enough time has passed 00395 * since the last read. 00396 */ 00397 if ( now - net_ctl->lastupdate > NET_REFRESH_LATENCY ) { 00398 read_net_counters(_net_register_current); 00399 for ( i=0; i<NET_MAX_COUNTERS; i++ ) { 00400 net_ctl->values[i] = _net_register_current[i] - _net_register_start[i]; 00401 } 00402 net_ctl->lastupdate = now; 00403 } 00404 *events = net_ctl->values; 00405 00406 return PAPI_OK; 00407 } 00408 00409 00410 int 00411 _net_stop( hwd_context_t *ctx, hwd_control_state_t *ctl ) 00412 { 00413 (void) ctx; 00414 00415 NET_control_state_t *net_ctl = (NET_control_state_t *) ctl; 00416 long long now = PAPI_get_real_usec(); 00417 int i; 00418 00419 read_net_counters(_net_register_current); 00420 for ( i=0; i<NET_MAX_COUNTERS; i++ ) { 00421 net_ctl->values[i] = _net_register_current[i] - _net_register_start[i]; 00422 } 00423 net_ctl->lastupdate = now; 00424 00425 return PAPI_OK; 00426 } 00427 00428 00429 /* 00430 * Thread shutdown 00431 */ 00432 int 00433 _net_shutdown_thread( hwd_context_t *ctx ) 00434 { 00435 ( void ) ctx; 00436 00437 return PAPI_OK; 00438 } 00439 00440 00441 /* 00442 * Clean up what was setup in net_init_component(). 00443 */ 00444 int 00445 _net_shutdown_component( void ) 00446 { 00447 if ( is_initialized ) { 00448 is_initialized = 0; 00449 papi_free(_net_native_events); 00450 _net_native_events = NULL; 00451 } 00452 00453 return PAPI_OK; 00454 } 00455 00456 00457 /* This function sets various options in the component 00458 * The valid codes being passed in are PAPI_SET_DEFDOM, 00459 * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL and 00460 * PAPI_SET_INHERIT 00461 */ 00462 int 00463 _net_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option ) 00464 { 00465 ( void ) ctx; 00466 ( void ) code; 00467 ( void ) option; 00468 00469 return PAPI_OK; 00470 } 00471 00472 00473 int 00474 _net_update_control_state( hwd_control_state_t *ctl, 00475 NativeInfo_t *native, int count, hwd_context_t *ctx ) 00476 { 00477 ( void ) ctx; 00478 ( void ) ctl; 00479 00480 int i, index; 00481 00482 for ( i = 0; i < count; i++ ) { 00483 index = native[i].ni_event; 00484 native[i].ni_position = _net_native_events[index].resources.selector - 1; 00485 } 00486 00487 return PAPI_OK; 00488 } 00489 00490 00491 /* 00492 * This function has to set the bits needed to count different domains 00493 * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER 00494 * By default return PAPI_EINVAL if none of those are specified 00495 * and PAPI_OK with success 00496 * PAPI_DOM_USER is only user context is counted 00497 * PAPI_DOM_KERNEL is only the Kernel/OS context is counted 00498 * PAPI_DOM_OTHER is Exception/transient mode (like user TLB misses) 00499 * PAPI_DOM_ALL is all of the domains 00500 */ 00501 int 00502 _net_set_domain( hwd_control_state_t *ctl, int domain ) 00503 { 00504 ( void ) ctl; 00505 00506 int found = 0; 00507 00508 if ( PAPI_DOM_USER & domain ) found = 1; 00509 if ( PAPI_DOM_KERNEL & domain ) found = 1; 00510 if ( PAPI_DOM_OTHER & domain ) found = 1; 00511 00512 if ( !found ) 00513 return PAPI_EINVAL; 00514 00515 return PAPI_OK; 00516 } 00517 00518 00519 int 00520 _net_reset( hwd_context_t *ctx, hwd_control_state_t *ctl ) 00521 { 00522 ( void ) ctx; 00523 ( void ) ctl; 00524 00525 return PAPI_OK; 00526 } 00527 00528 00529 /* 00530 * Native Event functions 00531 */ 00532 int 00533 _net_ntv_enum_events( unsigned int *EventCode, int modifier ) 00534 { 00535 int index; 00536 00537 switch ( modifier ) { 00538 case PAPI_ENUM_FIRST: 00539 if (num_events==0) { 00540 return PAPI_ENOEVNT; 00541 } 00542 *EventCode = 0; 00543 return PAPI_OK; 00544 break; 00545 00546 case PAPI_ENUM_EVENTS: 00547 index = *EventCode; 00548 if ( index < num_events - 1 ) { 00549 *EventCode = *EventCode + 1; 00550 return PAPI_OK; 00551 } else { 00552 return PAPI_ENOEVNT; 00553 } 00554 break; 00555 00556 default: 00557 return PAPI_EINVAL; 00558 break; 00559 } 00560 return PAPI_EINVAL; 00561 } 00562 00563 00564 /* 00565 * 00566 */ 00567 int 00568 _net_ntv_name_to_code( char *name, unsigned int *EventCode ) 00569 { 00570 int i; 00571 00572 for ( i=0; i<num_events; i++) { 00573 if (strcmp(name, _net_native_events[i].name) == 0) { 00574 *EventCode = i; 00575 00576 return PAPI_OK; 00577 } 00578 } 00579 00580 return PAPI_ENOEVNT; 00581 } 00582 00583 00584 /* 00585 * 00586 */ 00587 int 00588 _net_ntv_code_to_name( unsigned int EventCode, char *name, int len ) 00589 { 00590 int index = EventCode; 00591 00592 if ( index >= 0 && index < num_events ) { 00593 strncpy( name, _net_native_events[index].name, len ); 00594 return PAPI_OK; 00595 } 00596 00597 return PAPI_ENOEVNT; 00598 } 00599 00600 00601 /* 00602 * 00603 */ 00604 int 00605 _net_ntv_code_to_descr( unsigned int EventCode, char *name, int len ) 00606 { 00607 int index = EventCode; 00608 00609 if ( index >= 0 && index < num_events ) { 00610 strncpy( name, _net_native_events[index].description, len ); 00611 return PAPI_OK; 00612 } 00613 00614 return PAPI_ENOEVNT; 00615 } 00616 00617 00618 /* 00619 * 00620 */ 00621 int 00622 _net_ntv_code_to_bits( unsigned int EventCode, hwd_register_t *bits ) 00623 { 00624 int index = EventCode; 00625 00626 if ( index >= 0 && index < num_events ) { 00627 memcpy( ( NET_register_t * ) bits, 00628 &( _net_native_events[index].resources ), 00629 sizeof ( NET_register_t ) ); 00630 return PAPI_OK; 00631 } 00632 00633 return PAPI_ENOEVNT; 00634 } 00635 00636 00637 /* 00638 * 00639 */ 00640 papi_vector_t _net_vector = { 00641 .cmp_info = { 00642 /* default component information (unspecified values are initialized to 0) */ 00643 .name = "net", 00644 .short_name = "net", 00645 .version = "4.2.1", 00646 .description = "Linux network driver statistics", 00647 .num_mpx_cntrs = NET_MAX_COUNTERS, 00648 .num_cntrs = NET_MAX_COUNTERS, 00649 .default_domain = PAPI_DOM_USER, 00650 //.available_domains = PAPI_DOM_USER, 00651 .default_granularity = PAPI_GRN_THR, 00652 .available_granularities = PAPI_GRN_THR, 00653 .hardware_intr_sig = PAPI_INT_SIGNAL, 00654 00655 /* component specific cmp_info initializations */ 00656 .fast_real_timer = 0, 00657 .fast_virtual_timer = 0, 00658 .attach = 0, 00659 .attach_must_ptrace = 0, 00660 .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL, 00661 }, 00662 00663 /* sizes of framework-opaque component-private structures */ 00664 .size = { 00665 .context = sizeof ( NET_context_t ), 00666 .control_state = sizeof ( NET_control_state_t ), 00667 .reg_value = sizeof ( NET_register_t ), 00668 .reg_alloc = sizeof ( NET_reg_alloc_t ), 00669 }, 00670 00671 /* function pointers in this component */ 00672 .init_thread = _net_init_thread, 00673 .init_component = _net_init_component, 00674 .init_control_state = _net_init_control_state, 00675 .start = _net_start, 00676 .stop = _net_stop, 00677 .read = _net_read, 00678 .shutdown_thread = _net_shutdown_thread, 00679 .shutdown_component = _net_shutdown_component, 00680 .ctl = _net_ctl, 00681 00682 .update_control_state = _net_update_control_state, 00683 .set_domain = _net_set_domain, 00684 .reset = _net_reset, 00685 00686 .ntv_enum_events = _net_ntv_enum_events, 00687 .ntv_name_to_code = _net_ntv_name_to_code, 00688 .ntv_code_to_name = _net_ntv_code_to_name, 00689 .ntv_code_to_descr = _net_ntv_code_to_descr, 00690 .ntv_code_to_bits = _net_ntv_code_to_bits, 00691 }; 00692 00693 /* vim:set ts=4 sw=4 sts=4 et: */