PAPI  5.0.1.0
linux-net.c
Go to the documentation of this file.
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: */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines