PAPI  5.4.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
linux-net.c
Go to the documentation of this file.
1 
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <net/if.h>
25 
26 /* Headers required by PAPI */
27 #include "papi.h"
28 #include "papi_internal.h"
29 #include "papi_vector.h"
30 #include "papi_memory.h"
31 
32 #include "linux-net.h"
33 
34 
36 
37 /*********************************************************************
38  * Private
39  ********************************************************************/
40 
41 /* Network stats refresh latency in usec (default: 1 sec) */
42 #define NET_REFRESH_LATENCY 1000000
43 
44 #define NET_PROC_FILE "/proc/net/dev"
45 
46 /* /proc/net/dev line size
47  * interface name + 8 RX counters + 8 TX counters + separators
48  */
49 #define NET_PROC_MAX_LINE (IFNAMSIZ + 16 * (20 + 1) + 16)
50 
51 #define NET_INVALID_RESULT -1
52 
53 
55 
56 static int num_events = 0;
57 static int is_initialized = 0;
58 
61 
62 /* temporary event */
63 struct temp_event {
64  char name[PAPI_MAX_STR_LEN];
66  struct temp_event *next;
67 };
68 static struct temp_event* root = NULL;
69 
70 /* /proc/net/dev: network counters by interface */
71 #define NET_INTERFACE_COUNTERS 16
72 
73 static const struct net_counters {
74  char *name;
75  char *description;
77  /* Receive */
78  { "rx:bytes", "receive bytes"},
79  { "rx:packets", "receive packets"},
80  { "rx:errors", "receive errors"},
81  { "rx:dropped", "receive dropped"},
82  { "rx:fifo", "receive fifo"},
83  { "rx:frame", "receive frame"},
84  { "rx:compressed", "receive compressed"},
85  { "rx:multicast", "receive multicast"},
86  /* Transmit */
87  { "tx:bytes", "transmit bytes"},
88  { "tx:packets", "transmit packets"},
89  { "tx:errors", "transmit errors"},
90  { "tx:dropped", "transmit dropped"},
91  { "tx:fifo", "transmit fifo"},
92  { "tx:colls", "transmit colls"},
93  { "tx:carrier", "transmit carrier"},
94  { "tx:compressed", "transmit compressed"},
95 };
96 
97 
98 /*********************************************************************
99  *** BEGIN FUNCTIONS USED INTERNALLY SPECIFIC TO THIS COMPONENT ****
100  ********************************************************************/
101 
102 /*
103  * find all network interfaces listed in /proc/net/dev
104  */
105 static int
107 {
108  FILE *fin;
109  char line[NET_PROC_MAX_LINE];
110  char *retval, *ifname;
111  int count = 0;
112  struct temp_event *temp;
113  struct temp_event *last = NULL;
114  int i, j;
115 
116  fin = fopen(NET_PROC_FILE, "r");
117  if (fin == NULL) {
118  SUBDBG("Can't find %s, are you sure the /proc file-system is mounted?\n",
119  NET_PROC_FILE);
120  return 0;
121  }
122 
123  /* skip the 2 header lines */
124  for (i=0; i<2; i++) {
125  retval = fgets (line, NET_PROC_MAX_LINE, fin);
126  if (retval == NULL) {
127  fclose(fin);
128  SUBDBG("Not enough lines in %s\n", NET_PROC_FILE);
129  return 0;
130  }
131  }
132 
133  while ((fgets (line, NET_PROC_MAX_LINE, fin)) == line) {
134 
135  /* split the interface name from the 16 counters */
136  retval = strstr(line, ":");
137  if (retval == NULL) {
138  SUBDBG("Wrong line format <%s>\n", line);
139  continue;
140  }
141 
142  *retval = '\0';
143  ifname = line;
144  while (isspace(*ifname)) { ifname++; }
145 
146  for (j=0; j<NET_INTERFACE_COUNTERS; j++) {
147 
148  /* keep the interface name around */
149  temp = (struct temp_event *)papi_malloc(sizeof(struct temp_event));
150  if (!temp) {
151  PAPIERROR("out of memory!");
152  fclose(fin);
153  return PAPI_ENOMEM;
154  }
155  temp->next = NULL;
156 
157  if (root == NULL) {
158  root = temp;
159  } else if (last) {
160  last->next = temp;
161  } else {
162  free(temp);
163  fclose(fin);
164  PAPIERROR("This shouldn't be possible\n");
165  return PAPI_ECMP;
166  }
167  last = temp;
168 
169  snprintf(temp->name, PAPI_MAX_STR_LEN, "%s:%s",
170  ifname, _net_counter_info[j].name);
171  snprintf(temp->description, PAPI_MAX_STR_LEN, "%s %s",
172  ifname, _net_counter_info[j].description);
173 
174  count++;
175  }
176  }
177 
178  fclose(fin);
179 
180  return count;
181 }
182 
183 
184 static int
185 getInterfaceBaseIndex(const char *ifname)
186 {
187  int i;
188 
189  for ( i=0; i<num_events; i+=NET_INTERFACE_COUNTERS ) {
190  if (strncmp(_net_native_events[i].name, ifname, strlen(ifname)) == 0) {
191  return i;
192  }
193  }
194 
195  return -1; /* Not found */
196 }
197 
198 
199 static int
201 {
202  FILE *fin;
203  char line[NET_PROC_MAX_LINE];
204  char *retval, *ifname, *data;
205  int i, nf, if_bidx;
206 
207  fin = fopen(NET_PROC_FILE, "r");
208  if (fin == NULL) {
209  SUBDBG("Can't find %s, are you sure the /proc file-system is mounted?\n",
210  NET_PROC_FILE);
211  return NET_INVALID_RESULT;
212  }
213 
214  /* skip the 2 header lines */
215  for (i=0; i<2; i++) {
216  retval = fgets (line, NET_PROC_MAX_LINE, fin);
217  if (retval == NULL) {
218  SUBDBG("Not enough lines in %s\n", NET_PROC_FILE);
219  fclose(fin);
220  return 0;
221  }
222  }
223 
224  while ((fgets (line, NET_PROC_MAX_LINE, fin)) == line) {
225 
226  /* split the interface name from its 16 counters */
227  retval = strstr(line, ":");
228  if (retval == NULL) {
229  SUBDBG("Wrong line format <%s>\n", line);
230  continue;
231  }
232 
233  *retval = '\0';
234  data = retval + 1;
235  ifname = line;
236  while (isspace(*ifname)) { ifname++; }
237 
238  if_bidx = getInterfaceBaseIndex(ifname);
239  if (if_bidx < 0) {
240  SUBDBG("Interface <%s> not found\n", ifname);
241  } else {
242  nf = sscanf( data,
243  "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld\n",
244  &values[if_bidx + 0], &values[if_bidx + 1],
245  &values[if_bidx + 2], &values[if_bidx + 3],
246  &values[if_bidx + 4], &values[if_bidx + 5],
247  &values[if_bidx + 6], &values[if_bidx + 7],
248  &values[if_bidx + 8], &values[if_bidx + 9],
249  &values[if_bidx + 10], &values[if_bidx + 11],
250  &values[if_bidx + 12], &values[if_bidx + 13],
251  &values[if_bidx + 14], &values[if_bidx + 15]);
252 
253  SUBDBG("\nRead "
254  "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld\n",
255  values[if_bidx + 0], values[if_bidx + 1],
256  values[if_bidx + 2], values[if_bidx + 3],
257  values[if_bidx + 4], values[if_bidx + 5],
258  values[if_bidx + 6], values[if_bidx + 7],
259  values[if_bidx + 8], values[if_bidx + 9],
260  values[if_bidx + 10], values[if_bidx + 11],
261  values[if_bidx + 12], values[if_bidx + 13],
262  values[if_bidx + 14], values[if_bidx + 15]);
263 
264  if ( nf != NET_INTERFACE_COUNTERS ) {
265  /* This shouldn't happen */
266  SUBDBG("/proc line with wrong number of fields\n");
267  }
268  }
269 
270  }
271 
272  fclose(fin);
273 
274  return 0;
275 }
276 
277 
278 /*********************************************************************
279  *************** BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS *********
280  *********************************************************************/
281 
282 /*
283  * This is called whenever a thread is initialized
284  */
285 int
287 {
288  ( void ) ctx;
289 
290  return PAPI_OK;
291 }
292 
293 
294 /* Initialize hardware counters, setup the function vector table
295  * and get hardware information, this routine is called when the
296  * PAPI process is initialized (IE PAPI_library_init)
297  */
298 int
300 {
301  int i = 0;
302  struct temp_event *t, *last;
303 
304  if ( is_initialized )
305  return PAPI_OK;
306 
311 
312  is_initialized = 1;
313 
314  /* The network interfaces are listed in /proc/net/dev */
316 
317  if ( num_events < 0 ) /* PAPI errors */
318  return num_events;
319 
320  if ( num_events == 0 ) /* No network interfaces found */
321  return PAPI_OK;
322 
323  t = root;
324  _net_native_events = (NET_native_event_entry_t*)
326  do {
327  strncpy(_net_native_events[i].name, t->name, PAPI_MAX_STR_LEN-1);
328  _net_native_events[i].name[PAPI_MAX_STR_LEN-1] = '\0';
329  strncpy(_net_native_events[i].description, t->description, PAPI_MAX_STR_LEN-1);
330  _net_native_events[i].description[PAPI_MAX_STR_LEN-1] = '\0';
331  _net_native_events[i].resources.selector = i + 1;
332  last = t;
333  t = t->next;
334  papi_free(last);
335  i++;
336  } while (t != NULL);
337  root = NULL;
338 
339  /* Export the total number of events available */
340  _net_vector.cmp_info.num_native_events = num_events;
341 
342  /* Export the component id */
343  _net_vector.cmp_info.CmpIdx = cidx;
344 
345  return PAPI_OK;
346 }
347 
348 
349 /*
350  * Control of counters (Reading/Writing/Starting/Stopping/Setup)
351  * functions
352  */
353 int
355 {
356  ( void ) ctl;
357 
358  return PAPI_OK;
359 }
360 
361 
362 int
364 {
365  ( void ) ctx;
366 
367  NET_control_state_t *net_ctl = (NET_control_state_t *) ctl;
368  long long now = PAPI_get_real_usec();
369 
373 
374  /* set initial values to 0 */
375  memset(net_ctl->values, 0, NET_MAX_COUNTERS*sizeof(net_ctl->values[0]));
376 
377  /* Set last access time for caching purposes */
378  net_ctl->lastupdate = now;
379 
380  return PAPI_OK;
381 }
382 
383 
384 int
386  long long ** events, int flags )
387 {
388  (void) flags;
389  (void) ctx;
390 
391  NET_control_state_t *net_ctl = (NET_control_state_t *) ctl;
392  long long now = PAPI_get_real_usec();
393  int i;
394 
395  /* Caching
396  * Only read new values from /proc if enough time has passed
397  * since the last read.
398  */
399  if ( now - net_ctl->lastupdate > NET_REFRESH_LATENCY ) {
401  for ( i=0; i<NET_MAX_COUNTERS; i++ ) {
403  }
404  net_ctl->lastupdate = now;
405  }
406  *events = net_ctl->values;
407 
408  return PAPI_OK;
409 }
410 
411 
412 int
414 {
415  (void) ctx;
416 
417  NET_control_state_t *net_ctl = (NET_control_state_t *) ctl;
418  long long now = PAPI_get_real_usec();
419  int i;
420 
422  for ( i=0; i<NET_MAX_COUNTERS; i++ ) {
424  }
425  net_ctl->lastupdate = now;
426 
427  return PAPI_OK;
428 }
429 
430 
431 /*
432  * Thread shutdown
433  */
434 int
436 {
437  ( void ) ctx;
438 
439  return PAPI_OK;
440 }
441 
442 
443 /*
444  * Clean up what was setup in net_init_component().
445  */
446 int
448 {
449  if ( is_initialized )
450  {
451  is_initialized = 0;
452  if (_net_native_events != NULL)
453  {
454  papi_free(_net_native_events);
455  _net_native_events = NULL;
456  }
457  }
458 
459  return PAPI_OK;
460 }
461 
462 
463 /* This function sets various options in the component
464  * The valid codes being passed in are PAPI_SET_DEFDOM,
465  * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL and
466  * PAPI_SET_INHERIT
467  */
468 int
469 _net_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option )
470 {
471  ( void ) ctx;
472  ( void ) code;
473  ( void ) option;
474 
475  return PAPI_OK;
476 }
477 
478 
479 int
481  NativeInfo_t *native, int count, hwd_context_t *ctx )
482 {
483  ( void ) ctx;
484  ( void ) ctl;
485 
486  int i, index;
487 
488  for ( i = 0; i < count; i++ ) {
489  index = native[i].ni_event;
490  native[i].ni_position = _net_native_events[index].resources.selector - 1;
491  }
492 
493  return PAPI_OK;
494 }
495 
496 
497 /*
498  * This function has to set the bits needed to count different domains
499  * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER
500  * By default return PAPI_EINVAL if none of those are specified
501  * and PAPI_OK with success
502  * PAPI_DOM_USER is only user context is counted
503  * PAPI_DOM_KERNEL is only the Kernel/OS context is counted
504  * PAPI_DOM_OTHER is Exception/transient mode (like user TLB misses)
505  * PAPI_DOM_ALL is all of the domains
506  */
507 int
509 {
510  ( void ) ctl;
511  if ( PAPI_DOM_ALL != domain )
512  return PAPI_EINVAL;
513 
514  return PAPI_OK;
515 }
516 
517 
518 int
520 {
521  ( void ) ctx;
522  ( void ) ctl;
523 
524  return PAPI_OK;
525 }
526 
527 
528 /*
529  * Native Event functions
530  */
531 int
532 _net_ntv_enum_events( unsigned int *EventCode, int modifier )
533 {
534  int index;
535 
536  switch ( modifier ) {
537  case PAPI_ENUM_FIRST:
538  if (num_events==0) {
539  return PAPI_ENOEVNT;
540  }
541  *EventCode = 0;
542  return PAPI_OK;
543  break;
544 
545  case PAPI_ENUM_EVENTS:
546  index = *EventCode;
547  if ( index < num_events - 1 ) {
548  *EventCode = *EventCode + 1;
549  return PAPI_OK;
550  } else {
551  return PAPI_ENOEVNT;
552  }
553  break;
554 
555  default:
556  return PAPI_EINVAL;
557  break;
558  }
559  return PAPI_EINVAL;
560 }
561 
562 
563 /*
564  *
565  */
566 int
567 _net_ntv_name_to_code( char *name, unsigned int *EventCode )
568 {
569  int i;
570 
571  for ( i=0; i<num_events; i++) {
572  if (strcmp(name, _net_native_events[i].name) == 0) {
573  *EventCode = i;
574 
575  return PAPI_OK;
576  }
577  }
578 
579  return PAPI_ENOEVNT;
580 }
581 
582 
583 /*
584  *
585  */
586 int
587 _net_ntv_code_to_name( unsigned int EventCode, char *name, int len )
588 {
589  int index = EventCode;
590 
591  if ( index >= 0 && index < num_events ) {
592  strncpy( name, _net_native_events[index].name, len );
593  return PAPI_OK;
594  }
595 
596  return PAPI_ENOEVNT;
597 }
598 
599 
600 /*
601  *
602  */
603 int
604 _net_ntv_code_to_descr( unsigned int EventCode, char *name, int len )
605 {
606  int index = EventCode;
607 
608  if ( index >= 0 && index < num_events ) {
609  strncpy( name, _net_native_events[index].description, len );
610  return PAPI_OK;
611  }
612 
613  return PAPI_ENOEVNT;
614 }
615 
616 
617 /*
618  *
619  */
620 int
621 _net_ntv_code_to_bits( unsigned int EventCode, hwd_register_t *bits )
622 {
623  int index = EventCode;
624 
625  if ( index >= 0 && index < num_events ) {
626  memcpy( ( NET_register_t * ) bits,
627  &( _net_native_events[index].resources ),
628  sizeof ( NET_register_t ) );
629  return PAPI_OK;
630  }
631 
632  return PAPI_ENOEVNT;
633 }
634 
635 
636 /*
637  *
638  */
639 papi_vector_t _net_vector = {
640  .cmp_info = {
641  /* default component information (unspecified values are initialized to 0) */
642  .name = "net",
643  .short_name = "net",
644  .version = "4.2.1",
645  .description = "Linux network driver statistics",
646  .num_mpx_cntrs = NET_MAX_COUNTERS,
647  .num_cntrs = NET_MAX_COUNTERS,
648  .default_domain = PAPI_DOM_ALL,
649  .available_domains = PAPI_DOM_ALL,
650  .default_granularity = PAPI_GRN_SYS,
651  .available_granularities = PAPI_GRN_SYS,
652  .hardware_intr_sig = PAPI_INT_SIGNAL,
653 
654  /* component specific cmp_info initializations */
655  .fast_real_timer = 0,
656  .fast_virtual_timer = 0,
657  .attach = 0,
658  .attach_must_ptrace = 0,
659  },
660 
661  /* sizes of framework-opaque component-private structures */
662  .size = {
663  .context = sizeof ( NET_context_t ),
664  .control_state = sizeof ( NET_control_state_t ),
665  .reg_value = sizeof ( NET_register_t ),
666  .reg_alloc = sizeof ( NET_reg_alloc_t ),
667  },
668 
669  /* function pointers in this component */
670  .init_thread = _net_init_thread,
671  .init_component = _net_init_component,
672  .init_control_state = _net_init_control_state,
673  .start = _net_start,
674  .stop = _net_stop,
675  .read = _net_read,
676  .shutdown_thread = _net_shutdown_thread,
677  .shutdown_component = _net_shutdown_component,
678  .ctl = _net_ctl,
679 
680  .update_control_state = _net_update_control_state,
681  .set_domain = _net_set_domain,
682  .reset = _net_reset,
683 
684  .ntv_enum_events = _net_ntv_enum_events,
685  .ntv_name_to_code = _net_ntv_name_to_code,
686  .ntv_code_to_name = _net_ntv_code_to_name,
687  .ntv_code_to_descr = _net_ntv_code_to_descr,
688  .ntv_code_to_bits = _net_ntv_code_to_bits,
689 };
690 
691 /* vim:set ts=4 sw=4 sts=4 et: */
char name[PAPI_MAX_STR_LEN]
Definition: papi.h:626
#define PAPI_ENOEVNT
Definition: papi.h:258
memset(eventId, 0, size)
int _net_ntv_name_to_code(char *name, unsigned int *EventCode)
Definition: linux-net.c:567
long long flags
Definition: iozone.c:12330
int _net_init_control_state(hwd_control_state_t *ctl)
Definition: linux-net.c:354
long long values[NET_MAX_COUNTERS]
Definition: linux-net.h:68
#define papi_free(a)
Definition: papi_memory.h:35
static long long _net_register_start[NET_MAX_COUNTERS]
Definition: linux-net.c:59
#define papi_malloc(a)
Definition: papi_memory.h:34
static int num_events
static struct net_counters _net_counter_info[NET_INTERFACE_COUNTERS]
char name[PAPI_MAX_STR_LEN]
Definition: linux-net.h:55
papi_vector_t _net_vector
Definition: linux-net.c:35
#define PAPI_DOM_ALL
Definition: papi.h:301
return PAPI_OK
Definition: linux-nvml.c:458
int count
Definition: iozone.c:22422
int _net_ctl(hwd_context_t *ctx, int code, _papi_int_option_t *option)
Definition: linux-net.c:469
fclose(thread_wqfd)
void
Definition: iozone.c:18627
return PAPI_EINVAL
Definition: linux-nvml.c:408
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
#define NET_INVALID_RESULT
Definition: linux-net.c:51
int _net_init_component(int cidx)
Definition: linux-net.c:299
Return codes and api definitions.
int _net_shutdown_thread(hwd_context_t *ctx)
Definition: linux-net.c:435
static int is_initialized
Definition: linux-net.c:57
struct temp_event * next
net component This file contains the source code for a component that enables PAPI-C to access networ...
char * name
Definition: linux-net.c:74
char events[MAX_EVENTS][BUFSIZ]
char name[PAPI_MAX_STR_LEN]
t
Definition: iozone.c:23562
int _net_ntv_enum_events(unsigned int *EventCode, int modifier)
Definition: linux-net.c:532
Definition: linux-net.h:52
int _net_update_control_state(hwd_control_state_t *ctl, NativeInfo_t *native, int count, hwd_context_t *ctx)
Definition: linux-net.c:480
int i
Definition: fileop.c:140
int _net_read(hwd_context_t *ctx, hwd_control_state_t *ctl, long long **events, int flags)
Definition: linux-net.c:385
int _net_shutdown_component(void)
Definition: linux-net.c:447
#define NET_MAX_COUNTERS
Definition: linux-net.h:34
free(dummyfile[xx])
static int cidx
Definition: event_info.c:40
int _net_set_domain(hwd_control_state_t *ctl, int domain)
Definition: linux-net.c:508
static int native
Definition: event_info.c:39
unsigned int selector
Definition: linux-net.h:40
char description[PAPI_MAX_STR_LEN]
#define SUBDBG(format, args...)
Definition: papi_debug.h:63
int _net_ntv_code_to_bits(unsigned int EventCode, hwd_register_t *bits)
Definition: linux-net.c:621
void PAPIERROR(char *format,...)
#define PAPI_ECMP
Definition: papi.h:254
static NET_native_event_entry_t * _net_native_events
Definition: linux-net.c:54
int _net_reset(hwd_context_t *ctx, hwd_control_state_t *ctl)
Definition: linux-net.c:519
static struct temp_event * last
#define PAPI_INT_SIGNAL
Definition: papi_internal.h:53
int _net_ntv_code_to_descr(unsigned int EventCode, char *name, int len)
Definition: linux-net.c:604
static int generateNetEventList(void)
Definition: linux-net.c:106
NET_register_t resources
Definition: linux-net.h:54
int _net_stop(hwd_context_t *ctx, hwd_control_state_t *ctl)
Definition: linux-net.c:413
#define PAPI_ENOMEM
Definition: papi.h:252
#define NET_PROC_FILE
Definition: linux-net.c:44
#define NET_PROC_MAX_LINE
Definition: linux-net.c:49
int _net_init_thread(hwd_context_t *ctx)
Definition: linux-net.c:286
#define NET_INTERFACE_COUNTERS
Definition: linux-net.c:71
long long lastupdate
Definition: linux-net.h:69
static struct temp_event * root
Definition: linux-net.c:68
long long PAPI_get_real_usec(void)
Definition: papi.c:6190
sscanf(mnc->m_child_port,"%d",&mc.m_child_port)
int _net_start(hwd_context_t *ctx, hwd_control_state_t *ctl)
Definition: linux-net.c:363
char * name
Definition: iozone.c:23648
#define NET_REFRESH_LATENCY
Definition: linux-net.c:42
int temp
Definition: iozone.c:22158
#define PAPI_MAX_STR_LEN
Definition: papi.h:463
int _net_ntv_code_to_name(unsigned int EventCode, char *name, int len)
Definition: linux-net.c:587
static int read_net_counters(long long *values)
Definition: linux-net.c:200
char * description
Definition: linux-net.c:75
static int getInterfaceBaseIndex(const char *ifname)
Definition: linux-net.c:185
#define PAPI_GRN_SYS
Definition: papi.h:364
long j
Definition: iozone.c:19135
char description[PAPI_MAX_STR_LEN]
Definition: linux-net.h:56
static long long values[NUM_EVENTS]
Definition: init_fini.c:10
ssize_t retval
Definition: libasync.c:338
static long long _net_register_current[NET_MAX_COUNTERS]
Definition: linux-net.c:60