|
PAPI
5.0.1.0
|
00001 00015 #include <stdio.h> 00016 #include <string.h> 00017 #include <stdlib.h> 00018 #include <inttypes.h> 00019 00020 /* Headers required by PAPI */ 00021 #include "papi.h" 00022 #include "papi_internal.h" 00023 #include "papi_vector.h" 00024 #include "papi_memory.h" /* defines papi_malloc(), etc. */ 00025 00027 /* This is artificially low to allow testing of multiplexing */ 00028 #define EXAMPLE_MAX_SIMULTANEOUS_COUNTERS 3 00029 #define EXAMPLE_MAX_MULTIPLEX_COUNTERS 4 00030 00031 /* Declare our vector in advance */ 00032 /* This allows us to modify the component info */ 00033 papi_vector_t _example_vector; 00034 00036 typedef struct example_register 00037 { 00038 unsigned int selector; 00041 } example_register_t; 00042 00044 /* The contents of this structure will vary based on */ 00045 /* your component, however having name and description */ 00046 /* fields are probably useful. */ 00047 typedef struct example_native_event_entry 00048 { 00049 example_register_t resources; 00050 char name[PAPI_MAX_STR_LEN]; 00051 char description[PAPI_MAX_STR_LEN]; 00052 int writable; 00053 /* any other counter parameters go here */ 00054 } example_native_event_entry_t; 00055 00059 typedef struct example_reg_alloc 00060 { 00061 example_register_t ra_bits; 00062 } example_reg_alloc_t; 00063 00069 typedef struct example_control_state 00070 { 00071 int num_events; 00072 int domain; 00073 int multiplexed; 00074 int overflow; 00075 int inherit; 00076 int which_counter[EXAMPLE_MAX_SIMULTANEOUS_COUNTERS]; 00077 long long counter[EXAMPLE_MAX_MULTIPLEX_COUNTERS]; 00078 } example_control_state_t; 00079 00081 typedef struct example_context 00082 { 00083 long long autoinc_value; 00084 } example_context_t; 00085 00087 static example_native_event_entry_t *example_native_table; 00088 00090 static int num_events = 0; 00091 00092 00093 /*************************************************************************/ 00094 /* Below is the actual "hardware implementation" of our example counters */ 00095 /*************************************************************************/ 00096 00097 #define EXAMPLE_ZERO_REG 0 00098 #define EXAMPLE_CONSTANT_REG 1 00099 #define EXAMPLE_AUTOINC_REG 2 00100 #define EXAMPLE_GLOBAL_AUTOINC_REG 3 00101 00102 #define EXAMPLE_TOTAL_EVENTS 4 00103 00104 static long long example_global_autoinc_value = 0; 00105 00107 static void 00108 example_hardware_reset( example_context_t *ctx ) 00109 { 00110 /* reset per-thread count */ 00111 ctx->autoinc_value=0; 00112 /* reset global count */ 00113 example_global_autoinc_value = 0; 00114 00115 } 00116 00118 /* You might replace this with code that accesses */ 00119 /* hardware or reads values from the operatings system. */ 00120 static long long 00121 example_hardware_read( int which_one, example_context_t *ctx ) 00122 { 00123 long long old_value; 00124 00125 switch ( which_one ) { 00126 case EXAMPLE_ZERO_REG: 00127 return 0; 00128 case EXAMPLE_CONSTANT_REG: 00129 return 42; 00130 case EXAMPLE_AUTOINC_REG: 00131 old_value = ctx->autoinc_value; 00132 ctx->autoinc_value++; 00133 return old_value; 00134 case EXAMPLE_GLOBAL_AUTOINC_REG: 00135 old_value = example_global_autoinc_value; 00136 example_global_autoinc_value++; 00137 return old_value; 00138 default: 00139 fprintf(stderr,"Invalid counter read %x\n",which_one ); 00140 return -1; 00141 } 00142 00143 return 0; 00144 } 00145 00147 static int 00148 example_hardware_write( int which_one, 00149 example_context_t *ctx, 00150 long long value) 00151 { 00152 00153 switch ( which_one ) { 00154 case EXAMPLE_ZERO_REG: 00155 case EXAMPLE_CONSTANT_REG: 00156 return PAPI_OK; /* can't be written */ 00157 case EXAMPLE_AUTOINC_REG: 00158 ctx->autoinc_value=value; 00159 return PAPI_OK; 00160 case EXAMPLE_GLOBAL_AUTOINC_REG: 00161 example_global_autoinc_value=value; 00162 return PAPI_OK; 00163 default: 00164 perror( "Invalid counter write" ); 00165 return -1; 00166 } 00167 00168 return 0; 00169 } 00170 00171 static int 00172 detect_example(void) { 00173 00174 return PAPI_OK; 00175 } 00176 00177 /********************************************************************/ 00178 /* Below are the functions required by the PAPI component interface */ 00179 /********************************************************************/ 00180 00181 00186 int 00187 _example_init_component( int cidx ) 00188 { 00189 00190 SUBDBG( "_example_init_component..." ); 00191 00192 00193 /* First, detect that our hardware is available */ 00194 if (detect_example()!=PAPI_OK) { 00195 return PAPI_ECMP; 00196 } 00197 00198 /* we know in advance how many events we want */ 00199 /* for actual hardware this might have to be determined dynamically */ 00200 num_events = EXAMPLE_TOTAL_EVENTS; 00201 00202 /* Allocate memory for the our native event table */ 00203 example_native_table = 00204 ( example_native_event_entry_t * ) 00205 papi_calloc( sizeof(example_native_event_entry_t),num_events); 00206 if ( example_native_table == NULL ) { 00207 PAPIERROR( "malloc():Could not get memory for events table" ); 00208 return PAPI_ENOMEM; 00209 } 00210 00211 /* fill in the event table parameters */ 00212 /* for complicated components this will be done dynamically */ 00213 /* or by using an external library */ 00214 00215 strcpy( example_native_table[0].name, "EXAMPLE_ZERO" ); 00216 strcpy( example_native_table[0].description, 00217 "This is an example counter, that always returns 0" ); 00218 example_native_table[0].writable = 0; 00219 00220 strcpy( example_native_table[1].name, "EXAMPLE_CONSTANT" ); 00221 strcpy( example_native_table[1].description, 00222 "This is an example counter, that always returns a constant value of 42" ); 00223 example_native_table[1].writable = 0; 00224 00225 strcpy( example_native_table[2].name, "EXAMPLE_AUTOINC" ); 00226 strcpy( example_native_table[2].description, 00227 "This is an example counter, that reports a per-thread auto-incrementing value" ); 00228 example_native_table[2].writable = 1; 00229 00230 strcpy( example_native_table[3].name, "EXAMPLE_GLOBAL_AUTOINC" ); 00231 strcpy( example_native_table[3].description, 00232 "This is an example counter, that reports a global auto-incrementing value" ); 00233 example_native_table[3].writable = 1; 00234 00235 /* Export the total number of events available */ 00236 _example_vector.cmp_info.num_native_events = num_events; 00237 00238 /* Export the component id */ 00239 _example_vector.cmp_info.CmpIdx = cidx; 00240 00241 00242 00243 return PAPI_OK; 00244 } 00245 00247 int 00248 _example_init_thread( hwd_context_t *ctx ) 00249 { 00250 00251 example_context_t *example_context = (example_context_t *)ctx; 00252 00253 example_context->autoinc_value=0; 00254 00255 SUBDBG( "_example_init_thread %p...", ctx ); 00256 00257 return PAPI_OK; 00258 } 00259 00260 00261 00267 int 00268 _example_init_control_state( hwd_control_state_t * ctl ) 00269 { 00270 SUBDBG( "example_init_control_state... %p\n", ctl ); 00271 00272 example_control_state_t *example_ctl = ( example_control_state_t * ) ctl; 00273 memset( example_ctl, 0, sizeof ( example_control_state_t ) ); 00274 00275 return PAPI_OK; 00276 } 00277 00278 00280 int 00281 _example_update_control_state( hwd_control_state_t *ctl, 00282 NativeInfo_t *native, 00283 int count, 00284 hwd_context_t *ctx ) 00285 { 00286 00287 (void) ctx; 00288 int i, index; 00289 00290 example_control_state_t *example_ctl = ( example_control_state_t * ) ctl; 00291 00292 SUBDBG( "_example_update_control_state %p %p...", ctl, ctx ); 00293 00294 /* if no events, return */ 00295 if (count==0) return PAPI_OK; 00296 00297 for( i = 0; i < count; i++ ) { 00298 index = native[i].ni_event; 00299 00300 /* Map counter #i to Measure Event "index" */ 00301 example_ctl->which_counter[i]=index; 00302 00303 /* We have no constraints on event position, so any event */ 00304 /* can be in any slot. */ 00305 native[i].ni_position = i; 00306 } 00307 00308 example_ctl->num_events=count; 00309 00310 return PAPI_OK; 00311 } 00312 00314 int 00315 _example_start( hwd_context_t *ctx, hwd_control_state_t *ctl ) 00316 { 00317 00318 (void) ctx; 00319 (void) ctl; 00320 00321 SUBDBG( "example_start %p %p...", ctx, ctl ); 00322 00323 /* anything that would need to be set at counter start time */ 00324 00325 /* reset counters? */ 00326 /* For hardware that cannot reset counters, store initial */ 00327 /* counter state to the ctl and subtract it off at read time */ 00328 00329 /* start the counting ?*/ 00330 00331 return PAPI_OK; 00332 } 00333 00334 00336 int 00337 _example_stop( hwd_context_t *ctx, hwd_control_state_t *ctl ) 00338 { 00339 00340 (void) ctx; 00341 (void) ctl; 00342 00343 SUBDBG( "example_stop %p %p...", ctx, ctl ); 00344 00345 /* anything that would need to be done at counter stop time */ 00346 00347 00348 00349 return PAPI_OK; 00350 } 00351 00352 00354 /* flags field is never set? */ 00355 int 00356 _example_read( hwd_context_t *ctx, hwd_control_state_t *ctl, 00357 long long **events, int flags ) 00358 { 00359 00360 (void) flags; 00361 00362 example_context_t *example_ctx = (example_context_t *) ctx; 00363 example_control_state_t *example_ctl = ( example_control_state_t *) ctl; 00364 00365 SUBDBG( "example_read... %p %d", ctx, flags ); 00366 00367 int i; 00368 00369 /* Read counters into expected slot */ 00370 for(i=0;i<example_ctl->num_events;i++) { 00371 example_ctl->counter[i] = 00372 example_hardware_read( example_ctl->which_counter[i], 00373 example_ctx ); 00374 } 00375 00376 /* return pointer to the values we read */ 00377 *events = example_ctl->counter; 00378 00379 return PAPI_OK; 00380 } 00381 00383 /* otherwise, the updated state is written to ESI->hw_start */ 00384 int 00385 _example_write( hwd_context_t *ctx, hwd_control_state_t *ctl, 00386 long long *events ) 00387 { 00388 00389 example_context_t *example_ctx = (example_context_t *) ctx; 00390 example_control_state_t *example_ctl = ( example_control_state_t *) ctl; 00391 00392 int i; 00393 00394 SUBDBG( "example_write... %p %p", ctx, ctl ); 00395 00396 /* Write counters into expected slot */ 00397 for(i=0;i<example_ctl->num_events;i++) { 00398 example_hardware_write( example_ctl->which_counter[i], 00399 example_ctx, 00400 events[i] ); 00401 } 00402 00403 return PAPI_OK; 00404 } 00405 00406 00408 /* If the eventset is not currently running, then the saved value in the */ 00409 /* EventSet is set to zero without calling this routine. */ 00410 int 00411 _example_reset( hwd_context_t *ctx, hwd_control_state_t *ctl ) 00412 { 00413 example_context_t *event_ctx = (example_context_t *)ctx; 00414 (void) ctl; 00415 00416 SUBDBG( "example_reset ctx=%p ctrl=%p...", ctx, ctl ); 00417 00418 /* Reset the hardware */ 00419 example_hardware_reset( event_ctx ); 00420 00421 return PAPI_OK; 00422 } 00423 00425 int 00426 _example_shutdown_component(void) 00427 { 00428 00429 SUBDBG( "example_shutdown_component..." ); 00430 00431 /* Free anything we allocated */ 00432 00433 papi_free(example_native_table); 00434 00435 return PAPI_OK; 00436 } 00437 00439 int 00440 _example_shutdown_thread( hwd_context_t *ctx ) 00441 { 00442 00443 (void) ctx; 00444 00445 SUBDBG( "example_shutdown_thread... %p", ctx ); 00446 00447 /* Last chance to clean up thread */ 00448 00449 return PAPI_OK; 00450 } 00451 00452 00453 00460 int 00461 _example_ctl( hwd_context_t *ctx, int code, _papi_int_option_t *option ) 00462 { 00463 00464 (void) ctx; 00465 (void) code; 00466 (void) option; 00467 00468 SUBDBG( "example_ctl..." ); 00469 00470 return PAPI_OK; 00471 } 00472 00482 int 00483 _example_set_domain( hwd_control_state_t * cntrl, int domain ) 00484 { 00485 (void) cntrl; 00486 00487 int found = 0; 00488 SUBDBG( "example_set_domain..." ); 00489 00490 if ( PAPI_DOM_USER & domain ) { 00491 SUBDBG( " PAPI_DOM_USER " ); 00492 found = 1; 00493 } 00494 if ( PAPI_DOM_KERNEL & domain ) { 00495 SUBDBG( " PAPI_DOM_KERNEL " ); 00496 found = 1; 00497 } 00498 if ( PAPI_DOM_OTHER & domain ) { 00499 SUBDBG( " PAPI_DOM_OTHER " ); 00500 found = 1; 00501 } 00502 if ( PAPI_DOM_ALL & domain ) { 00503 SUBDBG( " PAPI_DOM_ALL " ); 00504 found = 1; 00505 } 00506 if ( !found ) 00507 return ( PAPI_EINVAL ); 00508 00509 return PAPI_OK; 00510 } 00511 00512 00513 /**************************************************************/ 00514 /* Naming functions, used to translate event numbers to names */ 00515 /**************************************************************/ 00516 00517 00524 int 00525 _example_ntv_enum_events( unsigned int *EventCode, int modifier ) 00526 { 00527 int index; 00528 00529 00530 switch ( modifier ) { 00531 00532 /* return EventCode of first event */ 00533 case PAPI_ENUM_FIRST: 00534 /* return the first event that we support */ 00535 00536 *EventCode = 0; 00537 return PAPI_OK; 00538 00539 /* return EventCode of next available event */ 00540 case PAPI_ENUM_EVENTS: 00541 index = *EventCode; 00542 00543 /* Make sure we have at least 1 more event after us */ 00544 if ( index < num_events - 1 ) { 00545 00546 /* This assumes a non-sparse mapping of the events */ 00547 *EventCode = *EventCode + 1; 00548 return PAPI_OK; 00549 } else { 00550 return PAPI_ENOEVNT; 00551 } 00552 break; 00553 00554 default: 00555 return PAPI_EINVAL; 00556 } 00557 00558 return PAPI_EINVAL; 00559 } 00560 00566 int 00567 _example_ntv_code_to_name( unsigned int EventCode, char *name, int len ) 00568 { 00569 int index; 00570 00571 index = EventCode; 00572 00573 /* Make sure we are in range */ 00574 if (index >= 0 && index < num_events) { 00575 strncpy( name, example_native_table[index].name, len ); 00576 return PAPI_OK; 00577 } 00578 00579 return PAPI_ENOEVNT; 00580 } 00581 00587 int 00588 _example_ntv_code_to_descr( unsigned int EventCode, char *descr, int len ) 00589 { 00590 int index; 00591 index = EventCode; 00592 00593 /* make sure event is in range */ 00594 if (index >= 0 && index < num_events) { 00595 strncpy( descr, example_native_table[index].description, len ); 00596 return PAPI_OK; 00597 } 00598 00599 return PAPI_ENOEVNT; 00600 } 00601 00603 papi_vector_t _example_vector = { 00604 .cmp_info = { 00605 /* default component information */ 00606 /* (unspecified values are initialized to 0) */ 00607 /* we explicitly set them to zero in this example */ 00608 /* to show what settings are available */ 00609 00610 .name = "example", 00611 .short_name = "example", 00612 .description = "A simple example component", 00613 .version = "1.15", 00614 .support_version = "n/a", 00615 .kernel_version = "n/a", 00616 .num_cntrs = EXAMPLE_MAX_SIMULTANEOUS_COUNTERS, 00617 .num_mpx_cntrs = EXAMPLE_MAX_SIMULTANEOUS_COUNTERS, 00618 .default_domain = PAPI_DOM_USER, 00619 .available_domains = PAPI_DOM_USER, 00620 .default_granularity = PAPI_GRN_THR, 00621 .available_granularities = PAPI_GRN_THR, 00622 .hardware_intr_sig = PAPI_INT_SIGNAL, 00623 00624 /* component specific cmp_info initializations */ 00625 }, 00626 00627 /* sizes of framework-opaque component-private structures */ 00628 .size = { 00629 /* once per thread */ 00630 .context = sizeof ( example_context_t ), 00631 /* once per eventset */ 00632 .control_state = sizeof ( example_control_state_t ), 00633 /* ?? */ 00634 .reg_value = sizeof ( example_register_t ), 00635 /* ?? */ 00636 .reg_alloc = sizeof ( example_reg_alloc_t ), 00637 }, 00638 00639 /* function pointers */ 00640 /* by default they are set to NULL */ 00641 00642 /* Used for general PAPI interactions */ 00643 .start = _example_start, 00644 .stop = _example_stop, 00645 .read = _example_read, 00646 .reset = _example_reset, 00647 .write = _example_write, 00648 .init_component = _example_init_component, 00649 .init_thread = _example_init_thread, 00650 .init_control_state = _example_init_control_state, 00651 .update_control_state = _example_update_control_state, 00652 .ctl = _example_ctl, 00653 .shutdown_thread = _example_shutdown_thread, 00654 .shutdown_component = _example_shutdown_component, 00655 .set_domain = _example_set_domain, 00656 /* .cleanup_eventset = NULL, */ 00657 /* called in add_native_events() */ 00658 /* .allocate_registers = NULL, */ 00659 00660 /* Used for overflow/profiling */ 00661 /* .dispatch_timer = NULL, */ 00662 /* .get_overflow_address = NULL, */ 00663 /* .stop_profiling = NULL, */ 00664 /* .set_overflow = NULL, */ 00665 /* .set_profile = NULL, */ 00666 00667 /* ??? */ 00668 /* .user = NULL, */ 00669 00670 /* Name Mapping Functions */ 00671 .ntv_enum_events = _example_ntv_enum_events, 00672 .ntv_code_to_name = _example_ntv_code_to_name, 00673 .ntv_code_to_descr = _example_ntv_code_to_descr, 00674 /* if .ntv_name_to_code not available, PAPI emulates */ 00675 /* it by enumerating all events and looking manually */ 00676 .ntv_name_to_code = NULL, 00677 00678 00679 /* These are only used by _papi_hwi_get_native_event_info() */ 00680 /* Which currently only uses the info for printing native */ 00681 /* event info, not for any sort of internal use. */ 00682 /* .ntv_code_to_bits = NULL, */ 00683 00684 }; 00685