PAPI 7.1.0.0
Loading...
Searching...
No Matches
linux-io.c
Go to the documentation of this file.
1
15#include <stdio.h>
16#include <string.h>
17#include <stdlib.h>
18#include <inttypes.h>
19
20/* Headers required by PAPI */
21#include "papi.h"
22#include "papi_internal.h"
23#include "papi_vector.h"
24#include "papi_memory.h" /* defines papi_malloc(), etc. */
25
26/* Declare our vector in advance */
27/* This allows us to modify the component info */
29
30// Maximum expected characters per line in file.
31#define FILE_LINE_SIZE 256
32// Maximum expected events in file. ARBITRARY VALUE,
33// set as needed, just avoiding malloc() and free().
34#define IO_COUNTERS 64
35// File name to access.
36#define IO_FILENAME "/proc/self/io"
37
38// The following macro follows if a string function has an error. It should
39// never happen; but it is necessary to prevent compiler warnings. We print
40// something just in case there is programmer error in invoking the function.
41#define HANDLE_STRING_ERROR {fprintf(stderr,"%s:%i unexpected string function error.\n",__FILE__,__LINE__); exit(-1);}
42
44typedef struct IO_native_event_entry
45{
46 char name[PAPI_MAX_STR_LEN]; // Name of the counter.
47 char desc[PAPI_MAX_STR_LEN]; // Description of the counter.
48 int fileIdx; // Line in file.
50
51//-----------------------------------------------------------------------------
52// Holds control flags. There's one of these per event-set. Use this to hold
53// data specific to the EventSet.
54//-----------------------------------------------------------------------------
55typedef struct _io_control_state
56{
58 long long EventSetVal[IO_COUNTERS];
59 long long EventSetReport[IO_COUNTERS];
60 int EventSetIdx[IO_COUNTERS];
62
63//-----------------------------------------------------------------------------
64// Holds per-thread information.
65//-----------------------------------------------------------------------------
66typedef struct _io_context
67{
69 FILE *pFile;
70 char line[FILE_LINE_SIZE];
72
73// ----------------------- GLOBALS ----------------------------
74// We have to have a global table of events, to support event enumeration.
75// We can have different file pointers for each thread, but all files must
76// match the file found during _init_component().
77static int gEventCount;
79
80// Code to just count events in file, fills in a context.
81// This may be a dummy from init_component.
83{
84 myCtx->EventCount = 0;
85 myCtx->pFile = fopen (IO_FILENAME,"r");
86 if (myCtx->pFile == NULL) {
88 "Failed to open target file '%s'.", IO_FILENAME);
91 return PAPI_ENOSUPP;
92 }
93
94 // Just count the lines, basic vetting for ability to parse.
95 while (1) {
96 char *res;
97 // fgets guarantees z-terminator, reads at most FILE_LINE_SIZE-1 bytes.
98 res = fgets(myCtx->line, FILE_LINE_SIZE, myCtx->pFile);
99 if (res == NULL) break;
100 // If the read filled the whole buffer, line is too long.
101 if (strlen(myCtx->line) == (FILE_LINE_SIZE-1)) {
102 fclose(myCtx->pFile);
104 "File '%s' line %i too long.", IO_FILENAME, myCtx->EventCount+1);
107 return PAPI_ENOSUPP;
108 }
109
110 char dummy[FILE_LINE_SIZE] = {0};
111 long long tmplong = 0LL;
112 int nf = sscanf( myCtx->line, "%s %lld\n", dummy, &tmplong);
113 if (nf != 2 || strlen(dummy)<2 || dummy[strlen(dummy)-1] != ':') {
114 fclose(myCtx->pFile);
116 "File '%s' line %i bad format.", IO_FILENAME, myCtx->EventCount+1);
119 return PAPI_ENOSUPP;
120 }
121
122 myCtx->EventCount++;
123 } // END READING.
124
125 // NOTE: We intentionally leave file open; up to caller to close
126 // or rewind and continue.
127 return PAPI_OK;
128} // END ROUTINE.
129
130
131// Code to read values; returns PAPI_OK or an error.
132// We presume the number of counters and order of them
133// will not change from our initialization read.
134static int
136{
137 ctx->pFile = fopen(IO_FILENAME, "r");
138 if (ctx->pFile == NULL) return(PAPI_ENOCNTR); /* No counters */
139
140 /* Read each line */
141 int idx;
142 for (idx=0; idx<gEventCount; idx++) {
143 if (fgets(ctx->line, FILE_LINE_SIZE-1, ctx->pFile)) {
144 char dummy[FILE_LINE_SIZE] = {0};
145 long long tmplong = 0LL;
146 int nf = sscanf(ctx->line, "%s %lld\n", dummy, &tmplong);
147 if (nf != 2 || strlen(dummy)<2 || dummy[strlen(dummy)-1] != ':') {
148 return PAPI_ENOCNTR;
149 }
150
151 ctl->EventSetVal[idx] = tmplong;
152 } else { /* Did not read ALL counters. */
153 return(PAPI_EMISC);
154 }
155 }
156
157 fclose(ctx->pFile);
158 return(PAPI_OK);
159} // END FUNCTION.
160
161/********************************************************************/
162/* Below are the functions required by the PAPI component interface */
163/********************************************************************/
164
169static int
171{
172 _io_context_t myCtx;
173 int ret, fileIdx;
174 SUBDBG( "_io_init_component..." );
175
176 ret = io_count_events(&myCtx);
177 if (ret != PAPI_OK) {
179 "Failed counting events.");
180 _io_vector.cmp_info.disabled_reason[PAPI_MAX_STR_LEN-1]=0; // force null termination.
182 goto fn_fail;
183 }
184
185 rewind(myCtx.pFile);
186
187 if (myCtx.EventCount > IO_COUNTERS) {
189 "File '%s' has %i events, exceeds counter limit of %i.", IO_FILENAME, myCtx.EventCount, IO_COUNTERS);
192 fclose(myCtx.pFile);
193 ret = PAPI_ENOSUPP;
194 goto fn_fail;
195 }
196
197 // Must be same for all threads, now.
198 gEventCount = myCtx.EventCount;
199 /* Allocate memory for the native event table */
203 if ( io_native_table == NULL ) {
205 "Failed to allocate %lu bytes for _io_native_table.", gEventCount*sizeof(IO_native_event_entry_t));
208 fclose(myCtx.pFile);
209 ret = PAPI_ENOMEM;
210 goto fn_fail;
211 }
212
213 for (fileIdx = 0; fileIdx < gEventCount; fileIdx++) {
214 (void) fgets(myCtx.line, FILE_LINE_SIZE, myCtx.pFile);
215 char name[FILE_LINE_SIZE] = {0};
216 long long tmplong = 0LL;
217 // No check for error here, we would have caught it in io_count_events().
218 (void) sscanf(myCtx.line, "%s %lld\n", name, &tmplong);
219 name[strlen(name)-1]=0; // null terminate over ':' we found.
220 strncpy(io_native_table[fileIdx].name, name, PAPI_MAX_STR_LEN-1);
221 io_native_table[fileIdx].fileIdx=fileIdx;
222 io_native_table[fileIdx].desc[0]=0; // flag for successful copy.
223 if (strcmp("rchar", name) == 0) {
224 strcpy(io_native_table[fileIdx].desc, "Characters read.");
225 }
226 if (strcmp("wchar", name) == 0) {
227 strcpy(io_native_table[fileIdx].desc, "Characters written.");
228 }
229 if (strcmp("syscr", name) == 0) {
230 strcpy(io_native_table[fileIdx].desc, "Characters read by system calls.");
231 }
232 if (strcmp("syscw", name) == 0) {
233 strcpy(io_native_table[fileIdx].desc, "Characters written by system calls.");
234 }
235 if (strcmp("read_bytes", name) == 0) {
236 strcpy(io_native_table[fileIdx].desc, "Binary bytes read.");
237 }
238 if (strcmp("write_bytes", name) == 0) {
239 strcpy(io_native_table[fileIdx].desc, "Binary bytes written.");
240 }
241 if (strcmp("cancelled_write_bytes", name) == 0) {
242 strcpy(io_native_table[fileIdx].desc, "Binary write bytes cancelled.");
243 }
244
245 // If none of the above found, generic description.
246 if (io_native_table[fileIdx].desc[0] == 0) {
247 strcpy(io_native_table[fileIdx].desc, "No description available.");
248 }
249 } // END READING.
250
251 fclose(myCtx.pFile);
252 // Export the total number of events available, at least on the init thread.
256
257 /* Export the component id */
259 fn_exit:
260 _papi_hwd[cidx]->cmp_info.disabled = ret;
261 return ret;
262 fn_fail:
263 goto fn_exit;
264} // END ROUTINE.
265
266// This is called whenever a thread is initialized.
267// WARNING: This can be called BEFORE init_component.
268// When it is, shutdown_thread is never called, but
269// this is the default context used in calls.
270static int
272{
273 _io_context_t* myCtx = (_io_context_t*) ctx;
274 int ret;
275 ret = io_count_events(myCtx);
276 if (ret != PAPI_OK) return(ret);
277
278 // File mismatch on event count kills it.
279 if (gEventCount > 0 && myCtx->EventCount != gEventCount) {
280 fclose(myCtx->pFile);
281 myCtx->pFile = NULL;
282 return PAPI_ENOSUPP;
283 }
284
285 fclose(myCtx->pFile);
286 return PAPI_OK;
287} // END of init thread.
288
289// Our control state holds arrays for reading/arranging Event values.
290// We just ensure it is all zeros.
291static int
293{
294 _io_control_state_t* control = ( _io_control_state_t* ) ctl;
295 memset(control, 0, sizeof(_io_control_state_t));
296 return PAPI_OK;
297} // END.
298
299
300// Triggered by eventset operations like add or remove.
301// We store the order of the events, and the number.
302static int
305 int count,
306 hwd_context_t *ctx )
307{
308 (void) ctx;
310
311 int i, index;
312
313 myCtl->EventSetCount = count;
314
315 /* if no events, return */
316 if (count==0) return PAPI_OK;
317
318 for( i = 0; i < count; i++ ) {
319 index = native[i].ni_event;
320 myCtl->EventSetIdx[i] = index;
321
322 /* We have no constraints on event position, so any event */
323 /* can be in any slot. */
324 native[i].ni_position = i;
325 }
326
327 return PAPI_OK;
328} // END ROUTINE.
329
331static int
333{
334 (void) ctl;
335 (void) ctx;
336 SUBDBG( "io_start %p %p...", ctx, ctl );
337 return PAPI_OK;
338}
339
340
342static int
344{
345 (void) ctx;
346 (void) ctl;
347 SUBDBG( "io_stop %p %p...", ctx, ctl );
348 // Don't do anything, can't stop the counters.
349
350 return PAPI_OK;
351}
352
353
354// Triggered by PAPI_read(). We read all the events, then
355// pick out the ones the user actually requested, in their
356// given order.
357static int
359 long long **events, int flags )
360{
361 // Prevent 'unused' warnings from compiler.
362 (void) flags;
363 _io_context_t *myCtx = (_io_context_t*) ctx;
365 int i;
366 SUBDBG( "io_read... %p %d", ctx, flags );
367
368 /* Read all counters into EventSetVal */
369 io_hardware_read(myCtx, myCtl);
370 for (i=0; i<myCtl->EventSetCount; i++) {
371 myCtl->EventSetReport[i]=myCtl->EventSetVal[myCtl->EventSetIdx[i]];
372 }
373
374 /* return pointer to the values we read */
375 *events = myCtl->EventSetReport;
376
377 return PAPI_OK;
378}
379
381/* otherwise, the updated state is written to ESI->hw_start */
382static int
384 long long *events )
385{
386 (void) ctx; // unused
387 (void) ctl; // unused
388 (void) events; // unused
389
390 return PAPI_OK;
391}
392
393
395/* If the eventset is not currently running, then the saved value in the */
396/* EventSet is set to zero without calling this routine. */
397/* We don't do anything for an io reset. */
398static int
400{
401 (void) ctx; // unused
402 (void) ctl;
403 SUBDBG( "io_reset...");
404 return PAPI_OK;
405}
406
407// Triggered by PAPI_shutdown().
408static int
410{
411 SUBDBG( "io_shutdown_component..." );
412 return PAPI_OK;
413}
414
415// Shutdown thread; close files.
416static int
418{
419 (void) ctx;
420 SUBDBG( "io_shutdown_thread... %p", ctx );
421 return PAPI_OK;
422}
423
430static int
431_io_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option )
432{
433 (void) ctx;
434 (void) code;
435 (void) option;
436 SUBDBG( "io_ctl..." );
437 return PAPI_OK;
438}
439
449static int
451{
452 (void) cntrl;
453
454 int found = 0;
455 SUBDBG( "io_set_domain..." );
456
457 if ( PAPI_DOM_USER & domain ) {
458 SUBDBG( " PAPI_DOM_USER " );
459 found = 1;
460 }
461 if ( PAPI_DOM_KERNEL & domain ) {
462 SUBDBG( " PAPI_DOM_KERNEL " );
463 found = 1;
464 }
465 if ( PAPI_DOM_OTHER & domain ) {
466 SUBDBG( " PAPI_DOM_OTHER " );
467 found = 1;
468 }
469 if ( PAPI_DOM_ALL & domain ) {
470 SUBDBG( " PAPI_DOM_ALL " );
471 found = 1;
472 }
473 if ( !found )
474 return ( PAPI_EINVAL );
475
476 return PAPI_OK;
477}
478
479
480/**************************************************************/
481/* Naming functions, used to translate event numbers to names */
482/**************************************************************/
483
484
491static int
492_io_ntv_enum_events( unsigned int *EventCode, int modifier )
493{
494 int index;
495
496 switch ( modifier ) {
497
498 /* return EventCode of first event */
499 case PAPI_ENUM_FIRST:
500 *EventCode = 0;
501 return PAPI_OK;
502
503 /* return EventCode of next available event */
504 case PAPI_ENUM_EVENTS:
505 index = *EventCode;
506
507 /* Make sure we have at least 1 more event after us */
508 if ( index < (gEventCount-1) ) {
509 *EventCode = *EventCode + 1;
510 return PAPI_OK;
511 } else {
512 return PAPI_ENOEVNT;
513 }
514 break;
515
516 default:
517 return PAPI_EINVAL;
518 }
519
520 return PAPI_EINVAL;
521} // END ROUTINE
522
528static int
529_io_ntv_code_to_name( unsigned int EventCode, char *name, int len )
530{
531 int index;
532 index = EventCode;
533
534 /* Make sure we are in range */
535 if (index >= 0 && index < gEventCount) {
536 strncpy(name, io_native_table[index].name, len );
537 return PAPI_OK;
538 }
539
540 return PAPI_ENOEVNT;
541} // END ROUTINE.
542
548static int
549_io_ntv_code_to_descr( unsigned int EventCode, char *descr, int len )
550{
551 int index;
552 index = EventCode;
553
554 /* make sure event is in range */
555 if (index >= 0 && index < gEventCount) {
556 strncpy( descr, io_native_table[index].desc, len );
557 return PAPI_OK;
558 }
559
560 return PAPI_ENOEVNT;
561}
562
565 .cmp_info = {
566 /* default component information */
567 /* (unspecified values are initialized to 0) */
568 /* we explicitly set them to zero in this example */
569 /* to show what settings are available */
570
571 .name = "io",
572 .short_name = "io",
573 .description = "A component to read /proc/self/io",
574 .version = "1.0",
575 .support_version = "n/a",
576 .kernel_version = "n/a",
577 .num_cntrs = 512,
578 .num_mpx_cntrs = 512,
579 .default_domain = PAPI_DOM_USER,
580 .available_domains = PAPI_DOM_USER,
581 .default_granularity = PAPI_GRN_THR,
582 .available_granularities = PAPI_GRN_THR,
583 .hardware_intr_sig = PAPI_INT_SIGNAL,
584
585 /* component specific cmp_info initializations */
586 },
587
588 /* sizes of framework-opaque component-private structures */
589 .size = {
590 /* once per thread */
591 .context = sizeof(_io_context_t),
592 /* once per eventset */
593 .control_state = sizeof(_io_control_state_t),
594 .reg_value = 1, /* unused */
595 .reg_alloc = 1, /* unused */
596 },
597
598 /* function pointers */
599 /* by default they are set to NULL */
600
601 /* Used for general PAPI interactions */
602 .start = _io_start,
603 .stop = _io_stop,
604 .read = _io_read,
605 .reset = _io_reset,
606 .write = _io_write,
607 .init_component = _io_init_component,
608 .init_thread = _io_init_thread,
609 .init_control_state = _io_init_control_state,
610 .update_control_state = _io_update_control_state,
611 .ctl = _io_ctl,
612 .shutdown_thread = _io_shutdown_thread,
613 .shutdown_component = _io_shutdown_component,
614 .set_domain = _io_set_domain,
615 /* .cleanup_eventset = NULL, */
616 /* called in add_native_events() */
617 /* .allocate_registers = NULL, */
618
619 /* Used for overflow/profiling */
620 /* .dispatch_timer = NULL, */
621 /* .get_overflow_address = NULL, */
622 /* .stop_profiling = NULL, */
623 /* .set_overflow = NULL, */
624 /* .set_profile = NULL, */
625
626 /* ??? */
627 /* .user = NULL, */
628
629 /* Name Mapping Functions */
630 .ntv_enum_events = _io_ntv_enum_events,
631 .ntv_code_to_name = _io_ntv_code_to_name,
632 .ntv_code_to_descr = _io_ntv_code_to_descr,
633 /* if .ntv_name_to_code not available, PAPI emulates */
634 /* it by enumerating all events and looking manually */
635 .ntv_name_to_code = NULL,
636
637
638 /* These are only used by _papi_hwi_get_native_event_info() */
639 /* Which currently only uses the info for printing native */
640 /* event info, not for any sort of internal use. */
641 /* .ntv_code_to_bits = NULL, */
642
643};
644
int i
static long count
struct papi_vectors * _papi_hwd[]
void dummy(void *array)
Definition: do_loops.c:306
#define PAPI_DOM_USER
Definition: f90papi.h:174
#define PAPI_ENUM_EVENTS
Definition: f90papi.h:224
#define PAPI_DOM_OTHER
Definition: f90papi.h:21
#define PAPI_OK
Definition: f90papi.h:73
#define PAPI_ENUM_FIRST
Definition: f90papi.h:85
#define PAPI_DOM_KERNEL
Definition: f90papi.h:254
#define PAPI_ENOEVNT
Definition: f90papi.h:139
#define PAPI_ENOCNTR
Definition: f90papi.h:215
#define PAPI_EINVAL
Definition: f90papi.h:115
#define PAPI_ENOSUPP
Definition: f90papi.h:244
#define PAPI_MAX_STR_LEN
Definition: f90papi.h:77
#define PAPI_EMISC
Definition: f90papi.h:122
#define PAPI_ENOMEM
Definition: f90papi.h:16
#define PAPI_GRN_THR
Definition: f90papi.h:265
#define PAPI_DOM_ALL
Definition: f90papi.h:261
char events[MAX_EVENTS][BUFSIZ]
static int io_hardware_read(_io_context_t *ctx, _io_control_state_t *ctl)
Definition: linux-io.c:135
static int _io_read(hwd_context_t *ctx, hwd_control_state_t *ctl, long long **events, int flags)
Definition: linux-io.c:358
static int _io_update_control_state(hwd_control_state_t *ctl, NativeInfo_t *native, int count, hwd_context_t *ctx)
Definition: linux-io.c:303
papi_vector_t _io_vector
Definition: linux-io.c:28
static int _io_start(hwd_context_t *ctx, hwd_control_state_t *ctl)
Definition: linux-io.c:332
static int _io_ctl(hwd_context_t *ctx, int code, _papi_int_option_t *option)
Definition: linux-io.c:431
static int _io_set_domain(hwd_control_state_t *cntrl, int domain)
Definition: linux-io.c:450
static int _io_shutdown_component(void)
Definition: linux-io.c:409
static int _io_ntv_code_to_name(unsigned int EventCode, char *name, int len)
Definition: linux-io.c:529
static int _io_stop(hwd_context_t *ctx, hwd_control_state_t *ctl)
Definition: linux-io.c:343
static int _io_init_component(int cidx)
Definition: linux-io.c:170
static int _io_shutdown_thread(hwd_context_t *ctx)
Definition: linux-io.c:417
#define IO_FILENAME
Definition: linux-io.c:36
static int _io_ntv_code_to_descr(unsigned int EventCode, char *descr, int len)
Definition: linux-io.c:549
static int _io_init_control_state(hwd_control_state_t *ctl)
Definition: linux-io.c:292
static int gEventCount
Definition: linux-io.c:77
static IO_native_event_entry_t * io_native_table
Definition: linux-io.c:78
static int _io_ntv_enum_events(unsigned int *EventCode, int modifier)
Definition: linux-io.c:492
#define IO_COUNTERS
Definition: linux-io.c:34
static int io_count_events(_io_context_t *myCtx)
Definition: linux-io.c:82
static int _io_reset(hwd_context_t *ctx, hwd_control_state_t *ctl)
Definition: linux-io.c:399
static int _io_init_thread(hwd_context_t *ctx)
Definition: linux-io.c:271
#define FILE_LINE_SIZE
Definition: linux-io.c:31
static int _io_write(hwd_context_t *ctx, hwd_control_state_t *ctl, long long *events)
Definition: linux-io.c:383
#define HANDLE_STRING_ERROR
Definition: linux-io.c:41
Return codes and api definitions.
#define SUBDBG(format, args...)
Definition: papi_debug.h:64
int fclose(FILE *__stream)
#define PAPI_INT_SIGNAL
Definition: papi_internal.h:52
#define papi_calloc(a, b)
Definition: papi_memory.h:37
static int native
static int cidx
const char * name
Definition: rocs.c:225
Definition: linux-io.c:45
int fileIdx
Definition: linux-io.c:48
char desc[PAPI_MAX_STR_LEN]
Definition: linux-io.c:47
char name[PAPI_MAX_STR_LEN]
Definition: papi.h:627
char disabled_reason[PAPI_HUGE_STR_LEN]
Definition: papi.h:634
char line[FILE_LINE_SIZE]
Definition: linux-io.c:70
FILE * pFile
Definition: linux-io.c:69
int EventCount
Definition: linux-io.c:68
long long EventSetReport[IO_COUNTERS]
Definition: linux-io.c:59
int EventSetIdx[IO_COUNTERS]
Definition: linux-io.c:60
long long EventSetVal[IO_COUNTERS]
Definition: linux-io.c:58
PAPI_component_info_t cmp_info
Definition: papi_vector.h:20
char * descr