|
PAPI
5.0.1.0
|
00001 /******************************************************************************* 00002 * >>>>>> "Development of a PAPI Backend for the Sun Niagara 2 Processor" <<<<<< 00003 * ----------------------------------------------------------------------------- 00004 * 00005 * Fabian Gorsler <fabian.gorsler@smail.inf.h-bonn-rhein-sieg.de> 00006 * 00007 * Hochschule Bonn-Rhein-Sieg, Sankt Augustin, Germany 00008 * University of Applied Sciences 00009 * 00010 * ----------------------------------------------------------------------------- 00011 * 00012 * File: solaris-niagara2.c 00013 * Author: fg215045 00014 * 00015 * Description: This source file is the implementation of a PAPI 00016 * component for the Sun Niagara 2 processor (aka UltraSPARC T2) 00017 * running on Solaris 10 with libcpc 2. 00018 * The machine for implementing this component was courtesy of RWTH 00019 * Aachen University, Germany. Thanks to the HPC-Team at RWTH! 00020 * 00021 * Conventions used: 00022 * - __cpc_*: Functions, variables, etc. related to libcpc handling 00023 * - __sol_*: Functions, variables, etc. related to Solaris handling 00024 * - __int_*: Functions, variables, etc. related to extensions of libcpc 00025 * - _niagara*: Functions, variables, etc. needed by PAPI hardware dependent 00026 * layer, i.e. the component itself 00027 * 00028 * 00029 * ***** Feel free to convert this header to the PAPI default ***** 00030 * 00031 * ----------------------------------------------------------------------------- 00032 * Created on April 23, 2009, 7:31 PM 00033 ******************************************************************************/ 00034 00035 #include "papi.h" 00036 #include "papi_internal.h" 00037 #include "papi_vector.h" 00038 #include "solaris-niagara2.h" 00039 #include "papi_memory.h" 00040 00041 #include <libcpc.h> 00042 #include <procfs.h> 00043 #include <sys/types.h> 00044 #include <sys/stat.h> 00045 #include <fcntl.h> 00046 #include <unistd.h> 00047 #include <stdio.h> 00048 #include <stdlib.h> 00049 #include <strings.h> 00050 #include <sys/lwp.h> 00051 #include <limits.h> 00052 #include <sys/processor.h> 00053 #include <sys/types.h> 00054 #include <sys/time.h> 00055 #include <stdarg.h> 00056 #include <libgen.h> 00057 #include <ucontext.h> 00058 #include <sys/regset.h> 00059 #include <sys/utsname.h> 00060 00061 #include "solaris-common.h" 00062 #include "solaris-memory.h" 00063 00064 #define hwd_control_state_t _niagara2_control_state_t 00065 #define hwd_context_t _niagara2_context_t 00066 #define hwd_register_t _niagara2_register_t 00067 00068 extern caddr_t _start, _end, _etext, _edata; 00069 extern papi_vector_t _niagara2_vector; 00070 00071 /* Synthetic events */ 00072 int __int_setup_synthetic_event( int, hwd_control_state_t *, void * ); 00073 uint64_t __int_get_synthetic_event( int, hwd_control_state_t *, void * ); 00074 void __int_walk_synthetic_events_action_count( void ); 00075 void __int_walk_synthetic_events_action_store( void ); 00076 00077 /* Simple error handlers for convenience */ 00078 #define __CHECK_ERR_DFLT(retval) \ 00079 if(retval != 0){ SUBDBG("RETVAL: %d\n", retval); return PAPI_ECMP;} 00080 00081 #define __CHECK_ERR_NULL(retval) \ 00082 if(retval == NULL){ SUBDBG("RETVAL: NULL\n"); return PAPI_ECMP;} 00083 00084 #define __CHECK_ERR_PAPI(retval) \ 00085 if(retval != PAPI_OK){ SUBDBG("RETVAL: %d\n", retval); return PAPI_ECMP;} 00086 00087 #define __CHECK_ERR_INVA(retval) \ 00088 if(retval != 0){ SUBDBG("RETVAL: %d\n", retval); return PAPI_EINVAL;} 00089 00090 #define __CHECK_ERR_NEGV(retval) \ 00091 if(retval < 0){ SUBDBG("RETVAL: %d\n", retval); return PAPI_ECMP;} 00092 00093 // PAPI defined variables 00094 extern papi_mdi_t _papi_hwi_system_info; 00095 00096 // The instance of libcpc 00097 static cpc_t *cpc = NULL; 00098 00099 typedef struct __t2_store 00100 { 00101 // Number of counters for a processing unit 00102 int npic; 00103 int *pic_ntv_count; 00104 int syn_evt_count; 00105 } __t2_store_t; 00106 00107 static __t2_store_t __t2_store; 00108 static char **__t2_ntv_events; 00109 00110 // Variables copied from the old component 00111 static int pid; 00112 00113 // Data types for utility functions 00114 00115 typedef struct __sol_processor_information 00116 { 00117 int total; 00118 int clock; 00119 } __sol_processor_information_t; 00120 00121 typedef struct __t2_pst_table 00122 { 00123 int papi_pst; 00124 char *ntv_event[MAX_COUNTERS]; 00125 int ntv_ctrs; 00126 int ntv_opcode; 00127 } __t2_pst_table_t; 00128 00129 #define SYNTHETIC_EVENTS_SUPPORTED 1 00130 00131 /* This table structure holds all preset events */ 00132 static __t2_pst_table_t __t2_table[] = { 00133 /* Presets defined by generic_events(3CPC) */ 00134 {PAPI_L1_DCM, 00135 {"DC_miss", NULL}, 1, NOT_DERIVED}, 00136 {PAPI_L1_ICM, 00137 {"IC_miss", NULL}, 1, NOT_DERIVED}, 00138 {PAPI_L2_ICM, 00139 {"L2_imiss", NULL}, 1, NOT_DERIVED}, 00140 {PAPI_TLB_DM, 00141 {"DTLB_miss", NULL}, 1, NOT_DERIVED}, 00142 {PAPI_TLB_IM, 00143 {"ITLB_miss", NULL}, 1, NOT_DERIVED}, 00144 {PAPI_TLB_TL, 00145 {"TLB_miss", NULL}, 1, NOT_DERIVED}, 00146 {PAPI_L2_LDM, 00147 {"L2_dmiss_ld", NULL}, 1, NOT_DERIVED}, 00148 {PAPI_BR_TKN, 00149 {"Br_taken", NULL}, 1, NOT_DERIVED}, 00150 {PAPI_TOT_INS, 00151 {"Instr_cnt", NULL}, 1, NOT_DERIVED}, 00152 {PAPI_LD_INS, 00153 {"Instr_ld", NULL}, 1, NOT_DERIVED}, 00154 {PAPI_SR_INS, 00155 {"Instr_st", NULL}, 1, NOT_DERIVED}, 00156 {PAPI_BR_INS, 00157 {"Br_completed", NULL}, 1, NOT_DERIVED}, 00158 /* Presets additionally found, should be checked twice */ 00159 {PAPI_BR_MSP, 00160 {"Br_taken", NULL}, 1, NOT_DERIVED}, 00161 {PAPI_FP_INS, 00162 {"Instr_FGU_arithmetic", NULL}, 1, NOT_DERIVED}, 00163 {PAPI_RES_STL, 00164 {"Idle_strands", NULL}, 1, NOT_DERIVED}, 00165 {PAPI_SYC_INS, 00166 {"Atomics", NULL}, 1, NOT_DERIVED}, 00167 {PAPI_L2_ICR, 00168 {"CPU_ifetch_to_PCX", NULL}, 1, NOT_DERIVED}, 00169 {PAPI_L1_TCR, 00170 {"CPU_ld_to_PCX", NULL}, 1, NOT_DERIVED}, 00171 {PAPI_L2_TCW, 00172 {"CPU_st_to_PCX", NULL}, 1, NOT_DERIVED}, 00173 /* Derived presets found, should be checked twice */ 00174 {PAPI_L1_TCM, 00175 {"IC_miss", "DC_miss"}, 2, DERIVED_ADD}, 00176 {PAPI_BR_CN, 00177 {"Br_completed", "Br_taken"}, 2, DERIVED_ADD}, 00178 {PAPI_BR_PRC, 00179 {"Br_completed", "Br_taken"}, 2, DERIVED_SUB}, 00180 {PAPI_LST_INS, 00181 {"Instr_st", "Instr_ld"}, 2, DERIVED_ADD}, 00182 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00183 /* This preset does exist in order to support multiplexing */ 00184 {PAPI_TOT_CYC, 00185 {"_syn_cycles_elapsed", "DC_miss"}, 1, NOT_DERIVED}, 00186 #endif 00187 {0, 00188 {NULL, NULL}, 0, 0}, 00189 }; 00190 00191 hwi_search_t *preset_table; 00192 00193 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00194 enum 00195 { 00196 SYNTHETIC_CYCLES_ELAPSED = 1, 00197 SYNTHETIC_RETURN_ONE, 00198 SYNTHETIC_RETURN_TWO, 00199 } __int_synthetic_enum; 00200 #endif 00201 00202 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00203 typedef struct __int_synthetic_table 00204 { 00205 int code; 00206 char *name; 00207 } __int_syn_table_t; 00208 #endif 00209 00210 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00211 static __int_syn_table_t __int_syn_table[] = { 00212 {SYNTHETIC_CYCLES_ELAPSED, "_syn_cycles_elapsed"}, 00213 {SYNTHETIC_RETURN_ONE, "_syn_return_one"}, 00214 {SYNTHETIC_RETURN_TWO, "_syn_return_two"}, 00215 {-1, NULL}, 00216 }; 00217 #endif 00218 00222 00223 /* DESCRIPTION: 00224 * ----------------------------------------------------------------------------- 00225 * Functions in this section are related to the PAPI hardware dependend layer, 00226 * also known as "HWD". In this case the HWD layer is the interface from PAPI 00227 * to libcpc 2/Solaris 10. 00228 ******************************************************************************/ 00229 00230 int 00231 _niagara2_set_domain( hwd_control_state_t * ctrl, int domain ) 00232 { 00233 int i; 00234 00235 #ifdef DEBUG 00236 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00237 __LINE__ ); 00238 #endif 00239 00240 /* Clean and set the new flag for each counter */ 00241 00242 for ( i = 0; i < MAX_COUNTERS; i++ ) { 00243 #ifdef DEBUG 00244 SUBDBG( " -> %s: Setting flags for PIC#%d, old value: %p\n", 00245 __func__, i, ctrl->flags[i] ); 00246 #endif 00247 00248 ctrl->flags[i] &= ~( CPC_COUNTING_DOMAINS ); 00249 00250 #ifdef DEBUG 00251 SUBDBG( " -> %s: +++ cleaned value: %p\n", 00252 __func__, ctrl->flags[i] ); 00253 #endif 00254 00255 ctrl->flags[i] |= __cpc_domain_translator( domain ); 00256 00257 #ifdef DEBUG 00258 SUBDBG( " -> %s: +++ new value: %p\n", 00259 __func__, ctrl->flags[i] ); 00260 #endif 00261 } 00262 00263 /* Recreate the set */ 00264 __CHECK_ERR_PAPI( __cpc_recreate_set( ctrl ) ); 00265 00266 #ifdef DEBUG 00267 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00268 __LINE__ ); 00269 #endif 00270 00271 return PAPI_OK; 00272 } 00273 00274 int 00275 _niagara2_ctl( hwd_context_t * ctx, int code, _papi_int_option_t * option ) 00276 { 00277 #ifdef DEBUG 00278 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00279 __LINE__ ); 00280 SUBDBG( " -> %s: Option #%d requested\n", __func__, code ); 00281 #endif 00282 00283 /* Only these options are handled which are handled in PAPI_set_opt, as many 00284 of the left out options are not settable, like PAPI_MAX_CPUS. */ 00285 00286 switch ( code ) { 00287 case PAPI_DEFDOM: 00288 /* From papi.h: Domain for all new eventsets. Takes non-NULL option 00289 pointer. */ 00290 00291 _niagara2_vector.cmp_info.default_domain = option->domain.domain; 00292 00293 return PAPI_OK; 00294 case PAPI_DOMAIN: 00295 /* From papi.h: Domain for an eventset */ 00296 00297 return _niagara2_set_domain( ctx, option->domain.domain ); 00298 case PAPI_DEFGRN: 00299 /* From papi.h: Granularity for all new eventsets */ 00300 00301 _niagara2_vector.cmp_info.default_granularity = 00302 option->granularity.granularity; 00303 00304 return PAPI_OK; 00305 case PAPI_GRANUL: 00306 /* From papi.h: Granularity for an eventset */ 00307 00308 /* Only supported granularity is PAPI_GRN_THREAD */ 00309 00310 return PAPI_OK; 00311 case PAPI_DEF_MPX_NS: 00312 /* From papi.h: Multiplexing/overflowing interval in ns, same as 00313 PAPI_DEF_ITIMER_NS */ 00314 00315 /* From the old component */ 00316 option->itimer.ns = __sol_get_itimer_ns( option->itimer.ns ); 00317 00318 #ifdef DEBUG 00319 SUBDBG( " -> %s: PAPI_DEF_MPX_NS, option->itimer.ns=%d\n", 00320 __func__, option->itimer.ns ); 00321 #endif 00322 00323 return PAPI_OK; 00324 case PAPI_DEF_ITIMER: // IN THE OLD COMPONENT // USED 00325 /* From papi.h: Option to set the type of itimer used in both software 00326 multiplexing, overflowing and profiling */ 00327 00328 /* These tests are taken from the old component. For Solaris 10 the 00329 same rules apply as documented in getitimer(2). */ 00330 00331 if ( ( option->itimer.itimer_num == ITIMER_REAL ) && 00332 ( option->itimer.itimer_sig != SIGALRM ) ) { 00333 #ifdef DEBUG 00334 SUBDBG( " -> %s: PAPI_DEF_ITIMER, ITIMER_REAL needs SIGALRM\n", 00335 __func__ ); 00336 #endif 00337 00338 return PAPI_EINVAL; 00339 } 00340 00341 00342 if ( ( option->itimer.itimer_num == ITIMER_VIRTUAL ) && 00343 ( option->itimer.itimer_sig != SIGVTALRM ) ) { 00344 #ifdef DEBUG 00345 SUBDBG( " -> %s: PAPI_DEF_ITIMER, ITIMER_VIRTUAL needs SIGVTALRM\n", 00346 __func__ ); 00347 #endif 00348 00349 return PAPI_EINVAL; 00350 } 00351 00352 00353 if ( ( option->itimer.itimer_num == ITIMER_PROF ) && 00354 ( option->itimer.itimer_sig != SIGPROF ) ) { 00355 #ifdef DEBUG 00356 SUBDBG( " -> %s: PAPI_DEF_ITIMER, ITIMER_PROF needs SIGPROF\n", 00357 __func__ ); 00358 #endif 00359 00360 return PAPI_EINVAL; 00361 } 00362 00363 00364 /* As in the old component defined, timer values below 0 are NOT 00365 filtered out, but timer values greater than 0 are rounded, either to 00366 a value which is at least itimer_res_ns or padded to a multiple of 00367 itimer_res_ns. */ 00368 00369 if ( option->itimer.ns > 0 ) { 00370 option->itimer.ns = __sol_get_itimer_ns( option->itimer.ns ); 00371 00372 #ifdef DEBUG 00373 SUBDBG( " -> %s: PAPI_DEF_ITIMER, option->itimer.ns=%d\n", 00374 __func__, option->itimer.ns ); 00375 #endif 00376 } 00377 00378 return PAPI_OK; 00379 case PAPI_DEF_ITIMER_NS: // IN THE OLD COMPONENT // USED 00380 /* From papi.h: Multiplexing/overflowing interval in ns, same as 00381 PAPI_DEF_MPX_NS */ 00382 00383 /* From the old component */ 00384 option->itimer.ns = __sol_get_itimer_ns( option->itimer.ns ); 00385 00386 #ifdef DEBUG 00387 SUBDBG( " -> %s: PAPI_DEF_ITIMER_NS, option->itimer.ns=%d\n", 00388 __func__, option->itimer.ns ); 00389 #endif 00390 00391 return PAPI_OK; 00392 } 00393 00394 #ifdef DEBUG 00395 SUBDBG( " -> %s: Option not found\n", __func__ ); 00396 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00397 __LINE__ ); 00398 #endif 00399 00400 /* This place should never be reached */ 00401 return PAPI_EINVAL; 00402 } 00403 00404 void 00405 _niagara2_dispatch_timer( int signal, siginfo_t * si, void *info ) 00406 { 00407 EventSetInfo_t *ESI = NULL; 00408 ThreadInfo_t *thread = NULL; 00409 int overflow_vector = 0; 00410 hwd_control_state_t *ctrl = NULL; 00411 long_long results[MAX_COUNTERS]; 00412 int i; 00413 // Hint from perf_events.c 00414 int cidx = _niagara2_vector.cmp_info.CmpIdx; 00415 00416 00417 #ifdef DEBUG 00418 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00419 __LINE__ ); 00420 SUBDBG( " -> %s: Overflow handler called by signal #%d\n", __func__, 00421 signal ); 00422 #endif 00423 00424 /* From the old component */ 00425 thread = _papi_hwi_lookup_thread( 0 ); 00426 ESI = ( EventSetInfo_t * ) thread->running_eventset[cidx]; 00427 00428 /* From the old component, modified */ 00429 // 00430 if ( ESI == NULL || ESI->master != thread || ESI->ctl_state == NULL || 00431 ( ( ESI->state & PAPI_OVERFLOWING ) == 0 ) ) { 00432 #ifdef DEBUG 00433 SUBDBG( " -> %s: Problems with ESI, not necessarily serious\n", 00434 __func__ ); 00435 00436 if ( ESI == NULL ) { 00437 SUBDBG( " -> %s: +++ ESI is NULL\n", __func__ ); 00438 } 00439 00440 if ( ESI->master != thread ) { 00441 SUBDBG( " -> %s: +++ Thread mismatch, ESI->master=%x thread=%x\n", 00442 __func__, ESI->master, thread ); 00443 } 00444 00445 if ( ESI->ctl_state == NULL ) { 00446 SUBDBG( " -> %s: +++ Counter state invalid\n", __func__ ); 00447 } 00448 00449 if ( ( ( ESI->state & PAPI_OVERFLOWING ) == 0 ) ) { 00450 SUBDBG 00451 ( " -> %s: +++ Overflow flag missing, ESI->overflow.flags=%x\n", 00452 __func__, ESI->overflow.flags ); 00453 } 00454 #endif 00455 00456 return; 00457 } 00458 #ifdef DEBUG 00459 printf( " -> %s: Preconditions valid, trying to read counters\n", 00460 __func__ ); 00461 #endif 00462 00463 ctrl = ESI->ctl_state; 00464 00465 if ( _niagara2_read 00466 ( ctrl, ctrl, ( long_long ** ) & results, NOT_A_PAPI_HWD_READ ) 00467 != PAPI_OK ) { 00468 /* Failure */ 00469 00470 #ifdef DEBUG 00471 printf( "%s: Failed to read counters\n", __func__ ); 00472 #endif 00473 00474 return; 00475 } else { 00476 /* Success */ 00477 00478 #ifdef DEBUG 00479 SUBDBG( " -> %s: Counters read\n", __func__ ); 00480 #endif 00481 00482 /* Iterate over all available counters in order to detect which counter 00483 overflowed (counter value should be 0 if an hw overflow happened), 00484 store the position in the overflow_vector, calculte the offset and 00485 shift (value range signed long long vs. unsigned long long). */ 00486 for ( i = 0; i < ctrl->count; i++ ) { 00487 if ( results[i] >= 0 ) { 00488 #ifdef DEBUG 00489 SUBDBG( " -> %s: Overflow detected at PIC #%d\n", __func__, i ); 00490 #endif 00491 00492 /* Set the bit in the overflow_vector */ 00493 overflow_vector = overflow_vector | ( 1 << i ); 00494 00495 /* hoose which method to use depending on the overflow signal. */ 00496 if ( signal == SIGEMT ) { 00497 /* Store the counter value, but only if we have a real * 00498 hardware overflow counting with libcpc/SIGEMT. */ 00499 ctrl->preset[i] = UINT64_MAX - ctrl->threshold[i]; 00500 ctrl->hangover[i] += ctrl->threshold[i]; 00501 } else { 00502 /* Push the value back, this time PAPI does the work. This is 00503 software overflow handling. */ 00504 cpc_request_preset( cpc, ctrl->idx[i], ctrl->result[i] ); 00505 } 00506 } else { 00507 #ifdef DEBUG 00508 SUBDBG( " -> %s: No overflow detected at PIC #%d, value=%ld\n", 00509 __func__, i, results[i] ); 00510 #endif 00511 00512 /* Save the results read from the counter as we can not store the 00513 temporary value in hardware or libcpc. */ 00514 if ( signal == SIGEMT ) { 00515 ctrl->preset[i] += results[i]; 00516 ctrl->hangover[i] = results[i]; 00517 } 00518 } 00519 } 00520 00521 #ifdef DEBUG 00522 SUBDBG( " -> %s: Restarting set to push values back\n", __func__ ); 00523 #endif 00524 00525 /* Push all values back to the counter as preset */ 00526 cpc_set_restart( cpc, ctrl->set ); 00527 } 00528 00529 #ifdef DEBUG 00530 SUBDBG( " -> %s: Passing overflow to PAPI with overflow_vector=%p\n", 00531 __func__, overflow_vector ); 00532 #endif 00533 00534 { 00535 /* hw is used as pointer in the dispatching routine of PAPI and might be 00536 changed. For safety it is not a pseudo pointer to NULL. */ 00537 int hw; 00538 00539 if ( signal == SIGEMT ) { 00540 /* This is a hardware overflow */ 00541 hw = 1; 00542 _papi_hwi_dispatch_overflow_signal( ctrl, ( caddr_t ) 00543 _niagara2_get_overflow_address 00544 ( info ), &hw, overflow_vector, 00545 1, &thread, ESI->CmpIdx ); 00546 } else { 00547 /* This is a software overflow */ 00548 hw = 0; 00549 _papi_hwi_dispatch_overflow_signal( ctrl, ( caddr_t ) 00550 _niagara2_get_overflow_address 00551 ( info ), &hw, overflow_vector, 00552 1, &thread, ESI->CmpIdx ); 00553 } 00554 } 00555 00556 #ifdef DEBUG 00557 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00558 __LINE__ ); 00559 #endif 00560 } 00561 00562 static inline void * 00563 _niagara2_get_overflow_address( void *context ) 00564 { 00565 ucontext_t *ctx = ( ucontext_t * ) context; 00566 00567 #ifdef DEBUG 00568 SUBDBG( "ENTERING/LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00569 __LINE__ ); 00570 #endif 00571 00572 return ( void * ) ctx->uc_mcontext.gregs[REG_PC]; 00573 } 00574 00575 00581 int 00582 _niagara2_init_control_state( hwd_control_state_t * ctrl ) 00583 { 00584 int i; 00585 00586 #ifdef DEBUG 00587 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00588 __LINE__ ); 00589 #endif 00590 00591 // cpc_seterrhndlr(cpc, myapp_errfn); 00592 00593 /* Clear the buffer */ 00594 if ( ctrl->counter_buffer != NULL ) { 00595 #ifdef DEBUG 00596 SUBDBG( " -> %s: Cleaning buffer\n", __func__ ); 00597 #endif 00598 00599 cpc_buf_destroy( cpc, ctrl->counter_buffer ); 00600 ctrl->counter_buffer = NULL; 00601 } 00602 00603 /* Clear the set */ 00604 if ( ctrl->set != NULL ) { 00605 #ifdef DEBUG 00606 SUBDBG( " -> %s: Cleaning set\n", __func__ ); 00607 #endif 00608 00609 cpc_set_destroy( cpc, ctrl->set ); 00610 ctrl->set = NULL; 00611 } 00612 00613 /* Indicate this idx has no request associated, this counter is unused. */ 00614 for ( i = 0; i < MAX_COUNTERS; i++ ) { 00615 #ifdef DEBUG 00616 SUBDBG( " -> %s: Cleaning counter state #%d\n", __func__, i ); 00617 #endif 00618 00619 /* Indicate missing setup values */ 00620 ctrl->idx[i] = EVENT_NOT_SET; 00621 ctrl->code[i].event_code = EVENT_NOT_SET; 00622 00623 /* No flags yet set, this is for overflow and binding */ 00624 ctrl->flags[i] = 0; 00625 00626 /* Preset value for counting results */ 00627 ctrl->preset[i] = DEFAULT_CNTR_PRESET; 00628 00629 /* Needed for overflow handling, will be set later */ 00630 ctrl->threshold[i] = 0; 00631 ctrl->hangover[i] = 0; 00632 00633 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00634 ctrl->syn_hangover[i] = 0; 00635 #endif 00636 } 00637 00638 /* No counters active in this set */ 00639 ctrl->count = 0; 00640 00641 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00642 ctrl->syn_count = 0; 00643 #endif 00644 00645 #ifdef DEBUG 00646 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00647 __LINE__ ); 00648 #endif 00649 00650 return PAPI_OK; 00651 } 00652 00653 int 00654 _niagara2_init_component( int cidx ) 00655 { 00656 #ifdef DEBUG 00657 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00658 __LINE__ ); 00659 #endif 00660 00661 /* Create an instance of libcpc */ 00662 #ifdef DEBUG 00663 SUBDBG( " -> %s: Trying to initalize libcpc\n", __func__ ); 00664 #endif 00665 cpc = cpc_open( CPC_VER_CURRENT ); 00666 __CHECK_ERR_NULL( cpc ); 00667 00668 #ifdef DEBUG 00669 SUBDBG( " -> %s: Registering libcpc error handler\n", __func__ ); 00670 #endif 00671 cpc_seterrhndlr( cpc, __cpc_error_handler ); 00672 00673 #ifdef DEBUG 00674 SUBDBG( " -> %s: Detecting supported PICs", __func__ ); 00675 #endif 00676 __t2_store.npic = cpc_npic( cpc ); 00677 00678 #ifdef DEBUG 00679 SUBDBG( " -> %s: Storing component index, cidx=%d\n", __func__, cidx ); 00680 #endif 00681 _niagara2_vector.cmp_info.CmpIdx = cidx; 00682 00683 #ifdef DEBUG 00684 SUBDBG( " -> %s: Gathering system information for PAPI\n", __func__ ); 00685 #endif 00686 /* Store system info in central data structure */ 00687 __CHECK_ERR_PAPI( _niagara2_get_system_info( &_papi_hwi_system_info ) ); 00688 00689 #ifdef DEBUG 00690 SUBDBG( " -> %s: Initializing locks\n", __func__ ); 00691 #endif 00692 /* Set up the lock after initialization */ 00693 _niagara2_lock_init( ); 00694 00695 // Copied from the old component, _papi_init_component() 00696 SUBDBG( "Found %d %s %s CPUs at %d Mhz.\n", 00697 _papi_hwi_system_info.hw_info.totalcpus, 00698 _papi_hwi_system_info.hw_info.vendor_string, 00699 _papi_hwi_system_info.hw_info.model_string, 00700 _papi_hwi_system_info.hw_info.cpu_max_mhz ); 00701 00702 /* Build native event table */ 00703 #ifdef DEBUG 00704 SUBDBG( " -> %s: Building native event table\n", __func__ ); 00705 #endif 00706 __CHECK_ERR_PAPI( __cpc_build_ntv_table( ) ); 00707 00708 /* Build preset event table */ 00709 #ifdef DEBUG 00710 SUBDBG( " -> %s: Building PAPI preset table\n", __func__ ); 00711 #endif 00712 __CHECK_ERR_PAPI( __cpc_build_pst_table( ) ); 00713 00714 /* Register presets and finish event related setup */ 00715 #ifdef DEBUG 00716 SUBDBG( " -> %s: Registering presets in PAPI\n", __func__ ); 00717 #endif 00718 __CHECK_ERR_PAPI( _papi_hwi_setup_all_presets( preset_table, NULL ) ); 00719 00720 #ifdef DEBUG 00721 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00722 __LINE__ ); 00723 #endif 00724 00725 /* Everything is ok */ 00726 return PAPI_OK; 00727 } 00728 00729 static void 00730 _niagara2_lock_init( void ) 00731 { 00732 #ifdef DEBUG 00733 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00734 __LINE__ ); 00735 #endif 00736 00737 /* Copied from old component, lock_init() */ 00738 memset( lock, 0x0, sizeof ( rwlock_t ) * PAPI_MAX_LOCK ); 00739 00740 #ifdef DEBUG 00741 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00742 __LINE__ ); 00743 #endif 00744 } 00745 00746 int 00747 _niagara2_ntv_code_to_bits( unsigned int EventCode, hwd_register_t * bits ) 00748 { 00749 int event_code = EventCode & PAPI_NATIVE_AND_MASK; 00750 00751 #ifdef DEBUG 00752 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00753 __LINE__ ); 00754 #endif 00755 00756 if ( event_code >= 0 && 00757 event_code <= _niagara2_vector.cmp_info.num_native_events ) { 00758 return PAPI_ENOEVNT; 00759 } 00760 00761 bits->event_code = event_code; 00762 00763 #ifdef DEBUG 00764 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00765 __LINE__ ); 00766 #endif 00767 00768 return PAPI_OK; 00769 } 00770 00771 int 00772 _niagara2_ntv_code_to_descr( unsigned int EventCode, char *ntv_descr, int len ) 00773 { 00774 #ifdef DEBUG 00775 SUBDBG( "ENTERING/LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00776 __LINE__ ); 00777 #endif 00778 00779 /* libcpc offers no descriptions, just a link to the reference manual */ 00780 return _niagara2_ntv_code_to_name( EventCode, ntv_descr, len ); 00781 } 00782 00783 int 00784 _niagara2_ntv_code_to_name( unsigned int EventCode, char *ntv_name, int len ) 00785 { 00786 int event_code = EventCode & PAPI_NATIVE_AND_MASK; 00787 00788 #ifdef DEBUG 00789 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00790 __LINE__ ); 00791 #endif 00792 00793 if ( event_code >= 0 && 00794 event_code <= _niagara2_vector.cmp_info.num_native_events ) { 00795 strlcpy( ntv_name, __t2_ntv_events[event_code], len ); 00796 00797 if ( strlen( __t2_ntv_events[event_code] ) > len - 1 ) { 00798 #ifdef DEBUG 00799 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00800 __LINE__ ); 00801 #endif 00802 00803 /* It's not a real error, but at least a hint */ 00804 return PAPI_EBUF; 00805 } 00806 #ifdef DEBUG 00807 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00808 __LINE__ ); 00809 #endif 00810 00811 return PAPI_OK; 00812 } 00813 #ifdef DEBUG 00814 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00815 __LINE__ ); 00816 #endif 00817 00818 return PAPI_ENOEVNT; 00819 } 00820 00821 int 00822 _niagara2_ntv_enum_events( unsigned int *EventCode, int modifier ) 00823 { 00824 /* This code is very similar to the code from the old component. */ 00825 00826 int event_code = *EventCode & PAPI_NATIVE_AND_MASK; 00827 00828 #ifdef DEBUG 00829 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00830 __LINE__ ); 00831 #endif 00832 00833 if ( modifier == PAPI_ENUM_FIRST ) { 00834 *EventCode = PAPI_NATIVE_MASK + 1; 00835 00836 #ifdef DEBUG 00837 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00838 __LINE__ ); 00839 #endif 00840 00841 return PAPI_OK; 00842 } 00843 00844 /* The table needs to be shifted by one position (starting index 1), as PAPI 00845 expects native event codes not to be 0 (papi_internal.c:744). */ 00846 00847 if ( event_code >= 1 && 00848 event_code <= _niagara2_vector.cmp_info.num_native_events - 1 ) { 00849 *EventCode = *EventCode + 1; 00850 00851 #ifdef DEBUG 00852 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00853 __LINE__ ); 00854 #endif 00855 00856 return PAPI_OK; 00857 } 00858 #ifdef DEBUG 00859 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00860 __LINE__ ); 00861 #endif 00862 00863 // If nothing found report an error 00864 return PAPI_ENOEVNT; 00865 } 00866 00867 int 00868 _niagara2_read( hwd_context_t * ctx, hwd_control_state_t * ctrl, 00869 long_long ** events, int flags ) 00870 { 00871 int i; 00872 00873 #ifdef DEBUG 00874 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00875 __LINE__ ); 00876 SUBDBG( " -> %s: called with flags=%p\n", __func__, flags ); 00877 #endif 00878 00879 /* Take a new sample from the PIC to the buffer */ 00880 __CHECK_ERR_DFLT( cpc_set_sample( cpc, ctrl->set, ctrl->counter_buffer ) ); 00881 00882 /* Copy the buffer values from all active counters */ 00883 for ( i = 0; i < ctrl->count; i++ ) { 00884 /* Retrieve the counting results of libcpc */ 00885 __CHECK_ERR_DFLT( cpc_buf_get( cpc, ctrl->counter_buffer, ctrl->idx[i], 00886 &ctrl->result[i] ) ); 00887 00888 /* As libcpc uses uint64_t and PAPI uses int64_t, we need to normalize 00889 the result back to a value that PAPI can handle, otherwise the result 00890 is not usable as its in the negative range of int64_t and the result 00891 becomes useless for PAPI. */ 00892 if ( ctrl->threshold[i] > 0 ) { 00893 #ifdef DEBUG 00894 SUBDBG( " -> %s: Normalizing result on PIC#%d to %lld\n", 00895 __func__, i, ctrl->result[i] ); 00896 #endif /* DEBUG */ 00897 00898 /* This shifts the retrieved value back to the PAPI value range */ 00899 ctrl->result[i] = ctrl->result[i] - 00900 ( UINT64_MAX - ctrl->threshold[i] ) - 1; 00901 00902 /* Needed if called internally if a PIC didn't really overflow, but 00903 was programmed in the same set. */ 00904 if ( flags != NOT_A_PAPI_HWD_READ ) { 00905 ctrl->result[i] = ctrl->hangover[i]; 00906 } 00907 #ifdef DEBUG 00908 SUBDBG( " -> %s: Overflow scaling on PIC#%d:\n", __func__, i ); 00909 SUBDBG( " -> %s: +++ ctrl->result[%d]=%llu\n", 00910 __func__, i, ctrl->result[i] ); 00911 SUBDBG( " -> %s: +++ ctrl->threshold[%d]=%lld\n", 00912 __func__, i, ctrl->threshold[i] ); 00913 SUBDBG( " -> %s: +++ ctrl->hangover[%d]=%lld\n", 00914 __func__, i, ctrl->hangover[i] ); 00915 #endif 00916 } 00917 #ifdef DEBUG 00918 SUBDBG( " -> %s: +++ ctrl->result[%d]=%llu\n", 00919 __func__, i, ctrl->result[i] ); 00920 #endif 00921 } 00922 00923 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00924 { 00925 int i; 00926 const int syn_barrier = _niagara2_vector.cmp_info.num_native_events 00927 - __t2_store.syn_evt_count; 00928 00929 for ( i = 0; i < ctrl->count; i++ ) { 00930 if ( ctrl->code[i].event_code >= syn_barrier ) { 00931 ctrl->result[i] = 00932 __int_get_synthetic_event( ctrl->code[i].event_code 00933 - syn_barrier, ctrl, &i ); 00934 } 00935 } 00936 } 00937 #endif 00938 00939 /* Pass the address of the results back to the calling function */ 00940 *events = ( long_long * ) & ctrl->result[0]; 00941 00942 #ifdef DEBUG 00943 SUBDBG( "LEAVING: %s\n", "_papi_read" ); 00944 #endif 00945 00946 return PAPI_OK; 00947 } 00948 00949 int 00950 _niagara2_reset( hwd_context_t * ctx, hwd_control_state_t * ctrl ) 00951 { 00952 #ifdef DEBUG 00953 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00954 __LINE__ ); 00955 #endif 00956 00957 /* This does a restart of the whole set, setting the internal counters back 00958 to the value passed as preset of the last call of cpc_set_add_request or 00959 cpc_request_preset. */ 00960 cpc_set_restart( cpc, ctrl->set ); 00961 00962 #ifdef SYNTHETIC_EVENTS_SUPPORTED 00963 { 00964 const int syn_barrier = _niagara2_vector.cmp_info.num_native_events 00965 - __t2_store.syn_evt_count; 00966 int i; 00967 00968 if ( ctrl->syn_count > 0 ) { 00969 for ( i = 0; i < MAX_COUNTERS; i++ ) { 00970 if ( ctrl->code[i].event_code >= syn_barrier ) { 00971 00972 ctrl->syn_hangover[i] += 00973 __int_get_synthetic_event( ctrl->code[i].event_code - 00974 syn_barrier, ctrl, &i ); 00975 } 00976 } 00977 } 00978 } 00979 #endif 00980 00981 #ifdef DEBUG 00982 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00983 __LINE__ ); 00984 #endif 00985 00986 return PAPI_OK; 00987 } 00988 00989 int 00990 _niagara2_set_profile( EventSetInfo_t * ESI, int EventIndex, int threshold ) 00991 { 00992 /* Seems not to be used. */ 00993 00994 #ifdef DEBUG 00995 SUBDBG( "ENTERING/LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 00996 __LINE__ ); 00997 #endif 00998 00999 return PAPI_ENOSUPP; 01000 } 01001 01002 int 01003 _niagara2_set_overflow( EventSetInfo_t * ESI, int EventIndex, int threshold ) 01004 { 01005 hwd_control_state_t *ctrl = ESI->ctl_state; 01006 struct sigaction sigact; 01007 01008 #ifdef DEBUG 01009 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01010 __LINE__ ); 01011 SUBDBG( " -> %s: Overflow handling for 0x%x on PIC#%d requested\n", 01012 __func__, ctrl, EventIndex ); 01013 SUBDBG( " -> %s: ESI->overflow.flags=%#x\n\n", __func__, ctrl, 01014 ESI->overflow.flags ); 01015 #endif 01016 01017 /* If threshold > 0, then activate hardware overflow handling, otherwise 01018 disable it. */ 01019 if ( threshold > 0 ) { 01020 #ifdef DEBUG 01021 SUBDBG( " -> %s: Activating overflow handling\n", __func__ ); 01022 #endif 01023 01024 ctrl->preset[EventIndex] = UINT64_MAX - threshold; 01025 ctrl->threshold[EventIndex] = threshold; 01026 01027 /* If SIGEMT is not yet enabled, enable it. In libcpc this means to re- 01028 recreate the used set. In order not to break PAPI operations only the 01029 event referred by EventIndex will be updated to use SIGEMT. */ 01030 if ( !( ctrl->flags[EventIndex] & CPC_OVF_NOTIFY_EMT ) ) { 01031 #ifdef DEBUG 01032 SUBDBG( " -> %s: Need to activate SIGEMT on PIC %d\n", 01033 __func__, EventIndex ); 01034 #endif 01035 01036 /* Enable overflow handling */ 01037 if ( __cpc_enable_sigemt( ctrl, EventIndex ) != PAPI_OK ) { 01038 #ifdef DEBUG 01039 SUBDBG( " -> %s: Activating SIGEMT failed for PIC %d\n", 01040 __func__, EventIndex ); 01041 #endif 01042 01043 return PAPI_ESYS; 01044 } 01045 } 01046 #ifdef DEBUG 01047 SUBDBG( " -> %s: SIGEMT activated, will install signal handler\n", 01048 __func__ ); 01049 #endif 01050 01051 // FIXME: Not really sure that this construct is working 01052 return _papi_hwi_start_signal( SIGEMT, 1, 0 ); 01053 01054 } else { 01055 #ifdef DEBUG 01056 SUBDBG( " -> %s: Disabling overflow handling\n", __func__ ); 01057 #endif 01058 01059 /* Resetting values which were used for overflow handling */ 01060 ctrl->preset[EventIndex] = DEFAULT_CNTR_PRESET; 01061 ctrl->flags[EventIndex] &= ~( CPC_OVF_NOTIFY_EMT ); 01062 ctrl->threshold[EventIndex] = 0; 01063 ctrl->hangover[EventIndex] = 0; 01064 01065 #ifdef DEBUG 01066 SUBDBG( " -> %s:ctrl->preset[%d]=%d, ctrl->flags[%d]=%p\n", 01067 __func__, EventIndex, ctrl->preset[EventIndex], 01068 EventIndex, ctrl->flags[EventIndex] ); 01069 #endif 01070 01071 /* Recreate the undelying set and disable the signal handler */ 01072 __CHECK_ERR_PAPI( __cpc_recreate_set( ctrl ) ); 01073 __CHECK_ERR_PAPI( _papi_hwi_stop_signal( SIGEMT ) ); 01074 } 01075 01076 01077 01078 #ifdef DEBUG 01079 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01080 __LINE__ ); 01081 #endif 01082 01083 return PAPI_OK; 01084 } 01085 01086 int 01087 _niagara2_shutdown( hwd_context_t * ctx ) 01088 { 01089 #ifdef DEBUG 01090 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01091 __LINE__ ); 01092 #endif 01093 01094 cpc_buf_destroy( cpc, ctx->counter_buffer ); 01095 cpc_set_destroy( cpc, ctx->set ); 01096 01097 #ifdef DEBUG 01098 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01099 __LINE__ ); 01100 #endif 01101 01102 return PAPI_OK; 01103 } 01104 01105 int 01106 _niagara2_shutdown_global( void ) 01107 { 01108 #ifdef DEBUG 01109 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01110 __LINE__ ); 01111 #endif 01112 01113 /* Free allocated memory */ 01114 01115 // papi_calloc in __cpc_build_ntv_table 01116 papi_free( __t2_store.pic_ntv_count ); 01117 // papi_calloc in __cpc_build_ntv_table 01118 papi_free( __t2_ntv_events ); 01119 // papi_calloc in __cpc_build_pst_table 01120 papi_free( preset_table ); 01121 01122 /* Shutdown libcpc */ 01123 01124 // cpc_open in _papi_init_component 01125 cpc_close( cpc ); 01126 01127 #ifdef DEBUG 01128 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01129 __LINE__ ); 01130 #endif 01131 01132 return PAPI_OK; 01133 } 01134 01135 int 01136 _niagara2_start( hwd_context_t * ctx, hwd_control_state_t * ctrl ) 01137 { 01138 int retval; 01139 01140 #ifdef DEBUG 01141 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01142 __LINE__ ); 01143 SUBDBG( " -> %s: Starting EventSet %p\n", __func__, ctrl ); 01144 #endif 01145 01146 01147 #ifdef SYNTHETIC_EVENTS_SUPPORTED 01148 { 01149 #ifdef DEBUG 01150 SUBDBG( " -> %s: Event count: ctrl->count=%d, ctrl->syn_count=%d\n", 01151 __func__, ctrl->count, ctrl->syn_count ); 01152 #endif 01153 01154 if ( ctrl->count > 0 && ctrl->count == ctrl->syn_count ) { 01155 ctrl->idx[0] = cpc_set_add_request( cpc, ctrl->set, "Instr_cnt", 01156 ctrl->preset[0], ctrl->flags[0], 01157 0, NULL ); 01158 ctrl->counter_buffer = cpc_buf_create( cpc, ctrl->set ); 01159 } 01160 } 01161 #endif 01162 01163 #ifdef DEBUG 01164 { 01165 int i; 01166 01167 for ( i = 0; i < MAX_COUNTERS; i++ ) { 01168 SUBDBG( " -> %s: Flags for PIC#%d: ctrl->flags[%d]=%d\n", __func__, 01169 i, i, ctrl->flags[i] ); 01170 } 01171 } 01172 #endif 01173 01174 __CHECK_ERR_DFLT( cpc_bind_curlwp( cpc, ctrl->set, CPC_BIND_LWP_INHERIT ) ); 01175 01176 /* Ensure the set is working properly */ 01177 retval = cpc_set_sample( cpc, ctrl->set, ctrl->counter_buffer ); 01178 01179 if ( retval != 0 ) { 01180 printf( "%s: cpc_set_sample failed, return=%d, errno=%d\n", 01181 __func__, retval, errno ); 01182 return PAPI_ECMP; 01183 } 01184 #ifdef DEBUG 01185 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01186 __LINE__ ); 01187 #endif 01188 01189 return PAPI_OK; 01190 } 01191 01192 int 01193 _niagara2_stop( hwd_context_t * ctx, hwd_control_state_t * ctrl ) 01194 { 01195 #ifdef DEBUG 01196 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01197 __LINE__ ); 01198 #endif 01199 01200 __CHECK_ERR_DFLT( cpc_unbind( cpc, ctrl->set ) ); 01201 01202 #ifdef DEBUG 01203 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01204 __LINE__ ); 01205 #endif 01206 01207 return PAPI_OK; 01208 } 01209 01210 int 01211 _niagara2_update_control_state( hwd_control_state_t * ctrl, 01212 NativeInfo_t * native, int count, 01213 hwd_context_t * ctx ) 01214 { 01215 int i; 01216 01217 #ifdef DEBUG 01218 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01219 __LINE__ ); 01220 #endif 01221 01222 /* Delete everything as we can't change an existing set */ 01223 if ( ctrl->counter_buffer != NULL ) { 01224 __CHECK_ERR_DFLT( cpc_buf_destroy( cpc, ctrl->counter_buffer ) ); 01225 } 01226 01227 if ( ctrl->set != NULL ) { 01228 __CHECK_ERR_DFLT( cpc_set_destroy( cpc, ctrl->set ) ); 01229 } 01230 01231 for ( i = 0; i < MAX_COUNTERS; i++ ) { 01232 ctrl->idx[i] = EVENT_NOT_SET; 01233 } 01234 01235 /* New setup */ 01236 01237 ctrl->set = cpc_set_create( cpc ); 01238 __CHECK_ERR_NULL( ctrl->set ); 01239 01240 ctrl->count = count; 01241 ctrl->syn_count = 0; 01242 01243 for ( i = 0; i < count; i++ ) { 01244 /* Store the active event */ 01245 ctrl->code[i].event_code = native[i].ni_event & PAPI_NATIVE_AND_MASK; 01246 01247 ctrl->flags[i] = __cpc_domain_translator( PAPI_DOM_USER ); 01248 ctrl->preset[i] = DEFAULT_CNTR_PRESET; 01249 01250 #ifdef DEBUG 01251 SUBDBG 01252 ( " -> %s: EventSet@0x%p/PIC#%d - ntv request >>%s<< (%d), flags=%#x\n", 01253 __func__, ctrl, i, __t2_ntv_events[ctrl->code[i].event_code], 01254 ctrl->code[i].event_code, ctrl->flags[i] ); 01255 #endif 01256 01257 /* Store the counter position (???) */ 01258 native[i].ni_position = i; 01259 01260 #ifdef SYNTHETIC_EVENTS_SUPPORTED 01261 { 01262 int syn_code = ctrl->code[i].event_code - 01263 ( _niagara2_vector.cmp_info.num_native_events 01264 - __t2_store.syn_evt_count ) - 1; 01265 01266 /* Check if the event code is bigger than the CPC provided events. */ 01267 if ( syn_code >= 0 ) { 01268 #ifdef DEBUG 01269 SUBDBG 01270 ( " -> %s: Adding synthetic event 0x%x (%s) on position %d\n", 01271 __func__, native[i].ni_event, 01272 __t2_ntv_events[ctrl->code[i].event_code], i ); 01273 #endif 01274 01275 /* Call the setup routine */ 01276 __int_setup_synthetic_event( syn_code, ctrl, NULL ); 01277 01278 /* Clean the hangover count as this event is new */ 01279 ctrl->syn_hangover[i] = 0; 01280 01281 /* Register this event as being synthetic, as an event set only 01282 based on synthetic events can not be actived through libcpc */ 01283 ctrl->syn_count++; 01284 01285 /* Jump to next iteration */ 01286 continue; 01287 } 01288 } 01289 #endif 01290 01291 #ifdef DEBUG 01292 SUBDBG( " -> %s: Adding native event 0x%x (%s) on position %d\n", 01293 __func__, native[i].ni_event, 01294 __t2_ntv_events[ctrl->code[i].event_code], i ); 01295 #endif 01296 01297 /* Pass the event as request to libcpc */ 01298 ctrl->idx[i] = cpc_set_add_request( cpc, ctrl->set, 01299 __t2_ntv_events[ctrl->code[i]. 01300 event_code], 01301 ctrl->preset[i], ctrl->flags[i], 0, 01302 NULL ); 01303 __CHECK_ERR_NEGV( ctrl->idx[i] ); 01304 } 01305 01306 #ifdef DEBUG 01307 if ( i == 0 ) { 01308 SUBDBG( " -> %s: nothing added\n", __func__ ); 01309 } 01310 #endif 01311 01312 ctrl->counter_buffer = cpc_buf_create( cpc, ctrl->set ); 01313 __CHECK_ERR_NULL( ctrl->counter_buffer ); 01314 01315 /* Finished the new setup */ 01316 01317 /* Linking to context (same data type by typedef!) */ 01318 ctx = ctrl; 01319 01320 #ifdef DEBUG 01321 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01322 __LINE__ ); 01323 #endif 01324 01325 return PAPI_OK; 01326 } 01327 01328 int 01329 _niagara2_update_shlib_info( papi_mdi_t *mdi ) 01330 { 01331 char *file = "/proc/self/map"; 01332 char *resolve_pattern = "/proc/self/path/%s"; 01333 01334 char lastobject[PRMAPSZ]; 01335 char link[PAPI_HUGE_STR_LEN]; 01336 char path[PAPI_HUGE_STR_LEN]; 01337 01338 prmap_t mapping; 01339 01340 int fd, count = 0, total = 0, position = -1, first = 1; 01341 caddr_t t_min, t_max, d_min, d_max; 01342 01343 PAPI_address_map_t *pam, *cur; 01344 01345 #ifdef DEBUG 01346 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01347 __LINE__ ); 01348 #endif 01349 01350 fd = open( file, O_RDONLY ); 01351 01352 if ( fd == -1 ) { 01353 return PAPI_ESYS; 01354 } 01355 01356 memset( lastobject, 0, PRMAPSZ ); 01357 01358 #ifdef DEBUG 01359 SUBDBG( " -> %s: Preprocessing memory maps from procfs\n", __func__ ); 01360 #endif 01361 01362 /* Search through the list of mappings in order to identify a) how many 01363 mappings are available and b) how many unique mappings are available. */ 01364 while ( read( fd, &mapping, sizeof ( prmap_t ) ) > 0 ) { 01365 #ifdef DEBUG 01366 SUBDBG( " -> %s: Found a new memory map entry\n", __func__ ); 01367 #endif 01368 /* Another entry found, just the total count of entries. */ 01369 total++; 01370 01371 /* Is the mapping accessible and not anonymous? */ 01372 if ( mapping.pr_mflags & ( MA_READ | MA_WRITE | MA_EXEC ) && 01373 !( mapping.pr_mflags & MA_ANON ) ) { 01374 /* Test if a new library has been found. If a new library has been 01375 found a new entry needs to be counted. */ 01376 if ( strcmp( lastobject, mapping.pr_mapname ) != 0 ) { 01377 strncpy( lastobject, mapping.pr_mapname, PRMAPSZ ); 01378 count++; 01379 01380 #ifdef DEBUG 01381 SUBDBG( " -> %s: Memory mapping entry valid for %s\n", __func__, 01382 mapping.pr_mapname ); 01383 #endif 01384 } 01385 } 01386 } 01387 #ifdef DEBUG 01388 SUBDBG( " -> %s: Preprocessing done, starting to analyze\n", __func__ ); 01389 #endif 01390 01391 01392 /* Start from the beginning, now fill in the found mappings */ 01393 if ( lseek( fd, 0, SEEK_SET ) == -1 ) { 01394 return PAPI_ESYS; 01395 } 01396 01397 memset( lastobject, 0, PRMAPSZ ); 01398 01399 /* Allocate memory */ 01400 pam = 01401 ( PAPI_address_map_t * ) papi_calloc( count, 01402 sizeof ( PAPI_address_map_t ) ); 01403 01404 while ( read( fd, &mapping, sizeof ( prmap_t ) ) > 0 ) { 01405 01406 if ( mapping.pr_mflags & MA_ANON ) { 01407 #ifdef DEBUG 01408 SUBDBG 01409 ( " -> %s: Anonymous mapping (MA_ANON) found for %s, skipping\n", 01410 __func__, mapping.pr_mapname ); 01411 #endif 01412 continue; 01413 } 01414 01415 /* Check for a new entry */ 01416 if ( strcmp( mapping.pr_mapname, lastobject ) != 0 ) { 01417 #ifdef DEBUG 01418 SUBDBG( " -> %s: Analyzing mapping for %s\n", __func__, 01419 mapping.pr_mapname ); 01420 #endif 01421 cur = &( pam[++position] ); 01422 strncpy( lastobject, mapping.pr_mapname, PRMAPSZ ); 01423 snprintf( link, PAPI_HUGE_STR_LEN, resolve_pattern, lastobject ); 01424 memset( path, 0, PAPI_HUGE_STR_LEN ); 01425 readlink( link, path, PAPI_HUGE_STR_LEN ); 01426 strncpy( cur->name, path, PAPI_HUGE_STR_LEN ); 01427 #ifdef DEBUG 01428 SUBDBG( " -> %s: Resolved name for %s: %s\n", __func__, 01429 mapping.pr_mapname, cur->name ); 01430 #endif 01431 } 01432 01433 if ( mapping.pr_mflags & MA_READ ) { 01434 /* Data (MA_WRITE) or text (MA_READ) segment? */ 01435 if ( mapping.pr_mflags & MA_WRITE ) { 01436 cur->data_start = ( caddr_t ) mapping.pr_vaddr; 01437 cur->data_end = 01438 ( caddr_t ) ( mapping.pr_vaddr + mapping.pr_size ); 01439 01440 if ( strcmp 01441 ( cur->name, 01442 _papi_hwi_system_info.exe_info.fullname ) == 0 ) { 01443 _papi_hwi_system_info.exe_info.address_info.data_start = 01444 cur->data_start; 01445 _papi_hwi_system_info.exe_info.address_info.data_end = 01446 cur->data_end; 01447 } 01448 01449 if ( first ) 01450 d_min = cur->data_start; 01451 if ( first ) 01452 d_max = cur->data_end; 01453 01454 if ( cur->data_start < d_min ) { 01455 d_min = cur->data_start; 01456 } 01457 01458 if ( cur->data_end > d_max ) { 01459 d_max = cur->data_end; 01460 } 01461 } else if ( mapping.pr_mflags & MA_EXEC ) { 01462 cur->text_start = ( caddr_t ) mapping.pr_vaddr; 01463 cur->text_end = 01464 ( caddr_t ) ( mapping.pr_vaddr + mapping.pr_size ); 01465 01466 if ( strcmp 01467 ( cur->name, 01468 _papi_hwi_system_info.exe_info.fullname ) == 0 ) { 01469 _papi_hwi_system_info.exe_info.address_info.text_start = 01470 cur->text_start; 01471 _papi_hwi_system_info.exe_info.address_info.text_end = 01472 cur->text_end; 01473 } 01474 01475 if ( first ) 01476 t_min = cur->text_start; 01477 if ( first ) 01478 t_max = cur->text_end; 01479 01480 if ( cur->text_start < t_min ) { 01481 t_min = cur->text_start; 01482 } 01483 01484 if ( cur->text_end > t_max ) { 01485 t_max = cur->text_end; 01486 } 01487 } 01488 } 01489 01490 first = 0; 01491 } 01492 01493 close( fd ); 01494 01495 /* During the walk of shared objects the upper and lower bound of the 01496 segments could be discovered. The bounds are stored in the PAPI info 01497 structure. The information is important for the profiling functions of 01498 PAPI. */ 01499 01500 /* This variant would pass the addresses of all text and data segments 01501 _papi_hwi_system_info.exe_info.address_info.text_start = t_min; 01502 _papi_hwi_system_info.exe_info.address_info.text_end = t_max; 01503 _papi_hwi_system_info.exe_info.address_info.data_start = d_min; 01504 _papi_hwi_system_info.exe_info.address_info.data_end = d_max; 01505 */ 01506 01507 #ifdef DEBUG 01508 SUBDBG( " -> %s: Analysis of memory maps done, results:\n", __func__ ); 01509 SUBDBG( " -> %s: text_start=%x, text_end=%x, text_size=%lld\n", __func__, 01510 _papi_hwi_system_info.exe_info.address_info.text_start, 01511 _papi_hwi_system_info.exe_info.address_info.text_end, 01512 _papi_hwi_system_info.exe_info.address_info.text_end 01513 - _papi_hwi_system_info.exe_info.address_info.text_start ); 01514 SUBDBG( " -> %s: data_start=%x, data_end=%x, data_size=%lld\n", __func__, 01515 _papi_hwi_system_info.exe_info.address_info.data_start, 01516 _papi_hwi_system_info.exe_info.address_info.data_end, 01517 _papi_hwi_system_info.exe_info.address_info.data_end 01518 - _papi_hwi_system_info.exe_info.address_info.data_start ); 01519 #endif 01520 01521 /* Store the map read and the total count of shlibs found */ 01522 _papi_hwi_system_info.shlib_info.map = pam; 01523 _papi_hwi_system_info.shlib_info.count = count; 01524 01525 #ifdef DEBUG 01526 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01527 __LINE__ ); 01528 #endif 01529 01530 return PAPI_OK; 01531 } 01532 01533 01537 01538 /* DESCRIPTION: 01539 * ----------------------------------------------------------------------------- 01540 * The following functions are for accessing libcpc 2 and Solaris related stuff 01541 * needed for PAPI. 01542 ******************************************************************************/ 01543 01544 static inline int 01545 __cpc_build_ntv_table( void ) 01546 { 01547 int i, tmp; 01548 01549 #ifdef DEBUG 01550 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01551 __LINE__ ); 01552 #endif 01553 01554 __t2_store.pic_ntv_count = papi_calloc( __t2_store.npic, sizeof ( int ) ); 01555 __CHECK_ERR_NULL( __t2_store.pic_ntv_count ); 01556 01557 #ifdef DEBUG 01558 SUBDBG( " -> %s: Checking PICs for functionality\n", __func__ ); 01559 #endif 01560 01561 for ( i = 0; i < __t2_store.npic; i++ ) { 01562 cpc_walk_events_pic( cpc, i, NULL, __cpc_walk_events_pic_action_count ); 01563 01564 #ifdef DEBUG 01565 SUBDBG( " -> %s: Found %d events on PIC#%d\n", __func__, 01566 __t2_store.pic_ntv_count[i], i ); 01567 #endif 01568 } 01569 01570 tmp = __t2_store.pic_ntv_count[0]; 01571 01572 /* There should be at least one counter... */ 01573 if ( tmp == 0 ) { 01574 #ifdef DEBUG 01575 SUBDBG( " -> %s: PIC#0 has 0 events\n", __func__ ); 01576 #endif 01577 01578 return PAPI_ECMP; 01579 } 01580 01581 /* Check if all PICs have the same number of counters */ 01582 for ( i = 0; i < __t2_store.npic; i++ ) { 01583 if ( __t2_store.pic_ntv_count[i] != tmp ) { 01584 #ifdef DEBUG 01585 SUBDBG( " -> %s: PIC#%d has %d events, should have %d\n", 01586 __func__, i, __t2_store.pic_ntv_count[i], tmp ); 01587 #endif 01588 01589 return PAPI_ECMP; 01590 } 01591 } 01592 01593 /* Count synthetic events which add functionality to libcpc */ 01594 #ifdef SYNTHETIC_EVENTS_SUPPORTED 01595 __t2_store.syn_evt_count = 0; 01596 __int_walk_synthetic_events_action_count( ); 01597 #endif 01598 01599 /* Store the count of events available in central data structure */ 01600 #ifndef SYNTHETIC_EVENTS_SUPPORTED 01601 _niagara2_vector.cmp_info.num_native_events = __t2_store.pic_ntv_count[0]; 01602 #else 01603 _niagara2_vector.cmp_info.num_native_events = 01604 __t2_store.pic_ntv_count[0] + __t2_store.syn_evt_count; 01605 #endif 01606 01607 01608 /* Allocate memory for storing all events found, including the first empty 01609 slot */ 01610 __t2_ntv_events = 01611 papi_calloc( _niagara2_vector.cmp_info.num_native_events + 1, 01612 sizeof ( char * ) ); 01613 01614 __t2_ntv_events[0] = "THIS IS A BUG!"; 01615 01616 tmp = 1; 01617 cpc_walk_events_pic( cpc, 0, ( void * ) &tmp, 01618 __cpc_walk_events_pic_action_store ); 01619 01620 #ifdef SYNTHETIC_EVENTS_SUPPORTED 01621 __int_walk_synthetic_events_action_store( ); 01622 #endif 01623 01624 #ifdef DEBUG 01625 for ( i = 1; i < __t2_store.pic_ntv_count[0]; i++ ) { 01626 SUBDBG( " -> %s: Event #%d: %s\n", __func__, i, __t2_ntv_events[i] ); 01627 } 01628 #endif 01629 01630 #ifdef DEBUG 01631 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01632 __LINE__ ); 01633 #endif 01634 01635 return PAPI_OK; 01636 } 01637 01638 /* Return event code for event_name */ 01639 01640 static inline int 01641 __cpc_search_ntv_event( char *event_name, int *event_code ) 01642 { 01643 int i; 01644 01645 for ( i = 0; i < _niagara2_vector.cmp_info.num_native_events; i++ ) { 01646 if ( strcmp( event_name, __t2_ntv_events[i] ) == 0 ) { 01647 *event_code = i; 01648 return PAPI_OK; 01649 } 01650 } 01651 01652 return PAPI_ENOEVNT; 01653 } 01654 01655 static inline int 01656 __cpc_build_pst_table( void ) 01657 { 01658 int num_psts, i, j, event_code, pst_events; 01659 hwi_search_t tmp; 01660 01661 #ifdef DEBUG 01662 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01663 __LINE__ ); 01664 #endif 01665 01666 num_psts = 0; 01667 01668 while ( __t2_table[num_psts].papi_pst != 0 ) { 01669 num_psts++; 01670 } 01671 01672 #ifdef DEBUG 01673 SUBDBG( " -> %s: Found %d presets\n", __func__, num_psts ); 01674 #endif 01675 01676 preset_table = papi_calloc( num_psts + 1, sizeof ( hwi_search_t ) ); 01677 __CHECK_ERR_NULL( preset_table ); 01678 01679 pst_events = 0; 01680 01681 for ( i = 0; i < num_psts; i++ ) { 01682 memset( &tmp, PAPI_NULL, sizeof ( tmp ) ); 01683 01684 /* Mark counters as unused. If they are needed, they will be overwritten 01685 later. See papi_preset.c:51 for more details. */ 01686 for ( j = 0; j < PAPI_EVENTS_IN_DERIVED_EVENT; j++ ) { 01687 tmp.data.native[j] = PAPI_NULL; 01688 } 01689 01690 tmp.event_code = __t2_table[i].papi_pst; 01691 tmp.data.derived = __t2_table[i].ntv_opcode; 01692 tmp.data.operation[0] = '\0'; 01693 01694 switch ( __t2_table[i].ntv_opcode ) { 01695 case DERIVED_ADD: 01696 tmp.data.operation[0] = '+'; 01697 break; 01698 case DERIVED_SUB: 01699 tmp.data.operation[0] = '-'; 01700 break; 01701 } 01702 01703 for ( j = 0; j < __t2_table[i].ntv_ctrs; j++ ) { 01704 if ( __cpc_search_ntv_event 01705 ( __t2_table[i].ntv_event[j], &event_code ) 01706 >= PAPI_OK ) { 01707 tmp.data.native[j] = event_code; 01708 } else { 01709 continue; 01710 } 01711 } 01712 01713 #ifdef DEBUG 01714 SUBDBG( " -> %s: pst row %d - event_code=%d\n", 01715 __func__, i, tmp.event_code ); 01716 SUBDBG( " -> %s: pst row %d - data.derived=%d, data.operation=%c\n", 01717 __func__, i, tmp.data.derived, tmp.data.operation[0] ); 01718 SUBDBG( " -> %s: pst row %d - native event codes:\n", __func__, i ); 01719 { 01720 int d_i; 01721 01722 for ( d_i = 0; d_i < PAPI_EVENTS_IN_DERIVED_EVENT; d_i++ ) { 01723 SUBDBG( " -> %s: pst row %d - +++ data.native[%d]=%d\n", 01724 __func__, i, d_i, tmp.data.native[d_i] ); 01725 } 01726 } 01727 #endif 01728 01729 memcpy( &preset_table[i], &tmp, sizeof ( tmp ) ); 01730 01731 pst_events++; 01732 } 01733 01734 // Check! 01735 memset( &preset_table[num_psts], 0, sizeof ( hwi_search_t ) ); 01736 01737 _niagara2_vector.cmp_info.num_preset_events = pst_events; 01738 01739 #ifdef DEBUG 01740 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01741 __LINE__ ); 01742 #endif 01743 01744 return PAPI_OK; 01745 } 01746 01747 static inline int 01748 __cpc_recreate_set( hwd_control_state_t * ctrl ) 01749 { 01750 #ifdef SYNTHETIC_EVENTS_SUPPORTED 01751 const int syn_barrier = _niagara2_vector.cmp_info.num_native_events 01752 - __t2_store.syn_evt_count; 01753 #endif 01754 01755 int i; 01756 01757 #ifdef DEBUG 01758 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01759 __LINE__ ); 01760 #endif 01761 01762 /* Destroy the old buffer and the old set if they exist, we need to do a full 01763 recreate as changing flags or events through libcpc is not possible */ 01764 if ( ctrl->counter_buffer != NULL ) { 01765 __CHECK_ERR_DFLT( cpc_buf_destroy( cpc, ctrl->counter_buffer ) ); 01766 } 01767 01768 if ( ctrl->set != NULL ) { 01769 __CHECK_ERR_DFLT( cpc_set_destroy( cpc, ctrl->set ) ); 01770 } 01771 01772 /* Create a new set */ 01773 ctrl->set = cpc_set_create( cpc ); 01774 __CHECK_ERR_NULL( ctrl->set ); 01775 01776 for ( i = 0; i < ctrl->count; i++ ) { 01777 #ifdef DEBUG 01778 SUBDBG( " -> %s: Adding native event 0x%x (%s) on position %d\n", 01779 __func__, ctrl->code[i].event_code, 01780 __t2_ntv_events[ctrl->code[i].event_code], i ); 01781 SUBDBG( " -> %s: Event setup: ctrl->code[%d].event_code=0x%x\n", 01782 __func__, i, ctrl->code[i].event_code ); 01783 SUBDBG( " -> %s: Event setup: ctrl->preset[%d]=%d\n", 01784 __func__, i, ctrl->preset[i] ); 01785 SUBDBG( " -> %s: Event setup: ctrl->flags[%d]=0x%x\n", 01786 __func__, i, ctrl->flags[i] ); 01787 #endif 01788 01789 #ifdef SYNTHETIC_EVENTS_SUPPORTED 01790 /* Ensure that synthetic events are skipped */ 01791 if ( ctrl->code[i].event_code >= syn_barrier ) { 01792 #ifdef DEBUG 01793 SUBDBG( " -> %s: Skipping counter %d, synthetic event found\n", 01794 __func__, i ); 01795 #endif 01796 01797 /* Next iteration */ 01798 continue; 01799 } 01800 #endif 01801 01802 ctrl->idx[i] = cpc_set_add_request( cpc, ctrl->set, 01803 __t2_ntv_events[ctrl->code[i]. 01804 event_code], 01805 ctrl->preset[i], ctrl->flags[i], 0, 01806 NULL ); 01807 __CHECK_ERR_NEGV( ctrl->idx[i] ); 01808 } 01809 01810 ctrl->counter_buffer = cpc_buf_create( cpc, ctrl->set ); 01811 __CHECK_ERR_NULL( ctrl->counter_buffer ); 01812 01813 #ifdef DEBUG 01814 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01815 __LINE__ ); 01816 #endif 01817 01818 return PAPI_OK; 01819 } 01820 01821 static inline int 01822 __cpc_domain_translator( const int papi_domain ) 01823 { 01824 int domain = 0; 01825 01826 #ifdef DEBUG 01827 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01828 __LINE__ ); 01829 SUBDBG( " -> %s: papi_domain=%d requested\n", __func__, papi_domain ); 01830 #endif 01831 01832 if ( papi_domain & PAPI_DOM_USER ) { 01833 #ifdef DEBUG 01834 SUBDBG( " -> %s: Domain PAPI_DOM_USER/CPC_COUNT_USER selected\n", 01835 __func__ ); 01836 #endif 01837 domain |= CPC_COUNT_USER; 01838 } 01839 01840 if ( papi_domain & PAPI_DOM_KERNEL ) { 01841 #ifdef DEBUG 01842 SUBDBG( " -> %s: Domain PAPI_DOM_KERNEL/CPC_COUNT_SYSTEM selected\n", 01843 __func__ ); 01844 #endif 01845 domain |= CPC_COUNT_SYSTEM; 01846 } 01847 01848 if ( papi_domain & PAPI_DOM_SUPERVISOR ) { 01849 #ifdef DEBUG 01850 SUBDBG( " -> %s: Domain PAPI_DOM_SUPERVISOR/CPC_COUNT_HV selected\n", 01851 __func__ ); 01852 #endif 01853 domain |= CPC_COUNT_HV; 01854 } 01855 #ifdef DEBUG 01856 SUBDBG( " -> %s: domain=%d\n", __func__, domain ); 01857 #endif 01858 01859 return domain; 01860 } 01861 01862 void 01863 __cpc_error_handler( const char *fn, int subcode, const char *fmt, va_list ap ) 01864 { 01865 #ifdef DEBUG 01866 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01867 __LINE__ ); 01868 #endif 01869 01870 /* From the libcpc manpages */ 01871 fprintf( stderr, "ERROR - libcpc error handler in %s() called!\n", fn ); 01872 vfprintf( stderr, fmt, ap ); 01873 01874 #ifdef DEBUG 01875 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01876 __LINE__ ); 01877 #endif 01878 } 01879 01880 static inline int 01881 __cpc_enable_sigemt( hwd_control_state_t * ctrl, int position ) 01882 { 01883 #ifdef DEBUG 01884 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01885 __LINE__ ); 01886 #endif 01887 01888 if ( position >= MAX_COUNTERS ) { 01889 #ifdef DEBUG 01890 SUBDBG( " -> %s: Position of the counter does not exist\n", __func__ ); 01891 #endif 01892 01893 return PAPI_EINVAL; 01894 } 01895 01896 ctrl->flags[position] = ctrl->flags[position] | CPC_OVF_NOTIFY_EMT; 01897 01898 #ifdef DEBUG 01899 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01900 __LINE__ ); 01901 #endif 01902 01903 return __cpc_recreate_set( ctrl ); 01904 } 01905 01906 void 01907 __cpc_walk_events_pic_action_count( void *arg, uint_t picno, const char *event ) 01908 { 01909 #ifdef DEBUG 01910 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01911 __LINE__ ); 01912 #endif 01913 01914 __t2_store.pic_ntv_count[picno]++; 01915 01916 #ifdef DEBUG 01917 SUBDBG 01918 ( " -> %s: Found one native event on PIC#%d (now totally %d events)\n", 01919 __func__, picno, __t2_store.pic_ntv_count[picno] ); 01920 #endif 01921 01922 #ifdef DEBUG 01923 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01924 __LINE__ ); 01925 #endif 01926 } 01927 01928 void 01929 __cpc_walk_events_pic_action_store( void *arg, uint_t picno, const char *event ) 01930 { 01931 int *tmp = ( int * ) arg; 01932 01933 #ifdef DEBUG 01934 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01935 __LINE__ ); 01936 #endif 01937 01938 __t2_ntv_events[*tmp] = papi_strdup( event ); 01939 01940 #ifdef DEBUG 01941 SUBDBG( " -> %s: Native event >>%s<< registered\n", 01942 __func__, __t2_ntv_events[*tmp] ); 01943 #endif 01944 01945 *tmp = *tmp + 1; 01946 01947 #ifdef DEBUG 01948 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01949 __LINE__ ); 01950 #endif 01951 } 01952 01953 static inline int 01954 __sol_get_processor_clock( void ) 01955 { 01956 processor_info_t pinfo; 01957 01958 #ifdef DEBUG 01959 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01960 __LINE__ ); 01961 #endif 01962 01963 // Fetch information from the first processor in the system 01964 if ( processor_info( getcpuid( ), &pinfo ) == 0 ) { 01965 01966 #ifdef DEBUG 01967 SUBDBG( " -> %s: Clock at %d MHz\n", __func__, pinfo.pi_clock ); 01968 #endif 01969 01970 return pinfo.pi_clock; 01971 } 01972 #ifdef DEBUG 01973 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 01974 __LINE__ ); 01975 #endif 01976 01977 return PAPI_ESYS; 01978 } 01979 01980 /* This function either increases the ns supplied to itimer_res_ns or pads it up 01981 * to a multiple of itimer_res_ns if the value is bigger than itimer_res_ns. 01982 * 01983 * The source is taken from the old component. 01984 */ 01985 static inline int 01986 __sol_get_itimer_ns( int ns ) 01987 { 01988 if ( ns < _papi_os_info.itimer_res_ns ) { 01989 return _papi_os_info.itimer_res_ns; 01990 } else { 01991 int leftover_ns = ns % _papi_os_info.itimer_res_ns; 01992 return ns + leftover_ns; 01993 } 01994 } 01995 01996 static inline lwpstatus_t * 01997 __sol_get_lwp_status( const pid_t pid, const lwpid_t lwpid ) 01998 { 01999 char *pattern = "/proc/%d/lwp/%d/lwpstatus"; 02000 char filename[PAPI_MIN_STR_LEN]; 02001 int fd; 02002 static lwpstatus_t lwp; 02003 02004 #ifdef DEBUG 02005 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02006 __LINE__ ); 02007 #endif 02008 02009 memset( &lwp, 0, sizeof ( lwp ) ); 02010 snprintf( filename, PAPI_MIN_STR_LEN, pattern, pid, lwpid ); 02011 02012 fd = open( filename, O_RDONLY ); 02013 if ( fd == -1 ) 02014 return NULL; 02015 02016 read( fd, ( void * ) &lwp, sizeof ( lwp ) ); 02017 02018 close( fd ); 02019 02020 #ifdef DEBUG 02021 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02022 __LINE__ ); 02023 #endif 02024 02025 return &lwp; 02026 } 02027 02028 static inline psinfo_t * 02029 __sol_get_proc_info( const pid_t pid ) 02030 { 02031 char *pattern = "/proc/%d/psinfo"; 02032 char filename[PAPI_MIN_STR_LEN]; 02033 int fd; 02034 static psinfo_t proc; 02035 02036 #ifdef DEBUG 02037 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02038 __LINE__ ); 02039 #endif 02040 02041 memset( &proc, 0, sizeof ( proc ) ); 02042 snprintf( filename, PAPI_MIN_STR_LEN, pattern, pid ); 02043 02044 fd = open( filename, O_RDONLY ); 02045 if ( fd == -1 ) 02046 return NULL; 02047 02048 read( fd, ( void * ) &proc, sizeof ( proc ) ); 02049 02050 close( fd ); 02051 02052 #ifdef DEBUG 02053 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02054 __LINE__ ); 02055 #endif 02056 02057 return &proc; 02058 } 02059 02060 static inline pstatus_t * 02061 __sol_get_proc_status( const pid_t pid ) 02062 { 02063 char *pattern = "/proc/%d/status"; 02064 char filename[PAPI_MIN_STR_LEN]; 02065 int fd; 02066 static pstatus_t proc; 02067 02068 #ifdef DEBUG 02069 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02070 __LINE__ ); 02071 #endif 02072 02073 memset( &proc, 0, sizeof ( proc ) ); 02074 snprintf( filename, PAPI_MIN_STR_LEN, pattern, pid ); 02075 02076 fd = open( filename, O_RDONLY ); 02077 if ( fd == -1 ) 02078 return NULL; 02079 02080 read( fd, ( void * ) &proc, sizeof ( proc ) ); 02081 02082 close( fd ); 02083 02084 #ifdef DEBUG 02085 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02086 __LINE__ ); 02087 #endif 02088 02089 return &proc; 02090 } 02091 02092 /* This function handles synthetic events and returns their result. Synthetic 02093 * events are events retrieved from outside of libcpc, e.g. all events which 02094 * can not be retrieved using cpc_set_add_request/cpc_buf_get. */ 02095 02096 #ifdef SYNTHETIC_EVENTS_SUPPORTED 02097 02098 uint64_t 02099 __int_get_synthetic_event( int code, hwd_control_state_t * ctrl, void *arg ) 02100 { 02101 #ifdef DEBUG 02102 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02103 __LINE__ ); 02104 #endif 02105 02106 switch ( code ) { 02107 case SYNTHETIC_CYCLES_ELAPSED: 02108 /* Return the count of ticks this set was bound. If a reset of the set 02109 has been executed the last count will be subtracted. */ 02110 { 02111 int *i = ( int * ) arg; 02112 return cpc_buf_tick( cpc, 02113 ctrl->counter_buffer ) - ctrl->syn_hangover[*i]; 02114 } 02115 case SYNTHETIC_RETURN_ONE: 02116 // The name says it - only for testing purposes. 02117 #ifdef DEBUG 02118 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02119 __LINE__ ); 02120 #endif 02121 return 1; 02122 case SYNTHETIC_RETURN_TWO: 02123 // The name says it - only for testing purposes. 02124 #ifdef DEBUG 02125 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02126 __LINE__ ); 02127 #endif 02128 return 2; 02129 default: 02130 02131 #ifdef DEBUG 02132 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02133 __LINE__ ); 02134 #endif 02135 return PAPI_EINVAL; 02136 } 02137 } 02138 #endif 02139 02140 #ifdef SYNTHETIC_EVENTS_SUPPORTED 02141 02142 int 02143 __int_setup_synthetic_event( int code, hwd_control_state_t * ctrl, void *arg ) 02144 { 02145 #ifdef DEBUG 02146 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02147 __LINE__ ); 02148 #endif 02149 02150 switch ( code ) { 02151 case SYNTHETIC_CYCLES_ELAPSED: 02152 02153 #ifdef DEBUG 02154 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02155 __LINE__ ); 02156 #endif 02157 return PAPI_OK; 02158 default: 02159 02160 #ifdef DEBUG 02161 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02162 __LINE__ ); 02163 #endif 02164 return PAPI_EINVAL; 02165 } 02166 #ifdef DEBUG 02167 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02168 __LINE__ ); 02169 #endif 02170 } 02171 #endif 02172 02173 #ifdef SYNTHETIC_EVENTS_SUPPORTED 02174 02175 void 02176 __int_walk_synthetic_events_action_count( void ) 02177 { 02178 int i = 0; 02179 02180 #ifdef DEBUG 02181 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02182 __LINE__ ); 02183 #endif 02184 02185 /* Count all synthetic events in __int_syn_table, the last event is marked 02186 with an event code of -1. */ 02187 while ( __int_syn_table[i].code != -1 ) { 02188 __t2_store.syn_evt_count++; 02189 i++; 02190 } 02191 02192 #ifdef DEBUG 02193 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02194 __LINE__ ); 02195 #endif 02196 } 02197 #endif 02198 02199 #ifdef SYNTHETIC_EVENTS_SUPPORTED 02200 02201 void 02202 __int_walk_synthetic_events_action_store( void ) 02203 { 02204 /* The first index of a synthetic event starts after last native event */ 02205 int i = 0; 02206 int offset = _niagara2_vector.cmp_info.num_native_events + 1 - 02207 __t2_store.syn_evt_count; 02208 02209 #ifdef DEBUG 02210 SUBDBG( "ENTERING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02211 __LINE__ ); 02212 #endif 02213 02214 while ( i < __t2_store.syn_evt_count ) { 02215 __t2_ntv_events[i + offset] = papi_strdup( __int_syn_table[i].name ); 02216 i++; 02217 } 02218 02219 #ifdef DEBUG 02220 SUBDBG( "LEAVING FUNCTION >>%s<< at %s:%d\n", __func__, __FILE__, 02221 __LINE__ ); 02222 #endif 02223 } 02224 #endif 02225 02226 02227 papi_vector_t _niagara2_vector = { 02228 /************* COMPONENT CAPABILITIES/INFORMATION/ETC ************************/ 02229 .cmp_info = { 02230 .name = "solaris-niagara2", 02231 .description = "Solaris Counters", 02232 .num_cntrs = MAX_COUNTERS, 02233 .num_mpx_cntrs = MAX_COUNTERS, 02234 .default_domain = PAPI_DOM_USER, 02235 .available_domains = ( PAPI_DOM_USER | PAPI_DOM_KERNEL 02236 | PAPI_DOM_SUPERVISOR ), 02237 .default_granularity = PAPI_GRN_THR, 02238 .available_granularities = PAPI_GRN_THR, 02239 .fast_real_timer = 1, 02240 .fast_virtual_timer = 1, 02241 .attach = 1, 02242 .attach_must_ptrace = 1, 02243 .hardware_intr = 1, 02244 .hardware_intr_sig = SIGEMT, 02245 .precise_intr = 1, 02246 } 02247 , 02248 /************* COMPONENT DATA STRUCTURE SIZES ********************************/ 02249 .size = { 02250 .context = sizeof ( hwd_context_t ), 02251 .control_state = sizeof ( hwd_control_state_t ), 02252 .reg_value = sizeof ( hwd_register_t ), 02253 .reg_alloc = sizeof ( niagara2_reg_alloc_t ), 02254 } 02255 , 02256 /************* COMPONENT INTERFACE FUNCTIONS *********************************/ 02257 .init_control_state = _niagara2_init_control_state, 02258 .start = _niagara2_start, 02259 .stop = _niagara2_stop, 02260 .read = _niagara2_read, 02261 .write = NULL, /* NOT IMPLEMENTED */ 02262 .shutdown_thread = _niagara2_shutdown, 02263 .shutdown_component = _niagara2_shutdown_global, 02264 .ctl = _niagara2_ctl, 02265 .update_control_state = _niagara2_update_control_state, 02266 .set_domain = _niagara2_set_domain, 02267 .reset = _niagara2_reset, 02268 .set_overflow = _niagara2_set_overflow, 02269 .set_profile = _niagara2_set_profile, 02270 .stop_profiling = NULL, /* NOT IMPLEMENTED */ 02271 .ntv_enum_events = _niagara2_ntv_enum_events, 02272 .ntv_name_to_code = NULL, /* NOT IMPLEMENTED */ 02273 .ntv_code_to_name = _niagara2_ntv_code_to_name, 02274 .ntv_code_to_descr = _niagara2_ntv_code_to_descr, 02275 .ntv_code_to_bits = _niagara2_ntv_code_to_bits, 02276 .init_component = _niagara2_init_component, 02277 .dispatch_timer = _niagara2_dispatch_timer, 02278 }; 02279 02280 papi_os_vector_t _papi_os_vector = { 02281 .get_memory_info = _niagara2_get_memory_info, 02282 .get_dmem_info = _solaris_get_dmem_info, 02283 02284 .get_real_usec = _solaris_get_real_usec, 02285 .get_real_cycles = _solaris_get_real_cycles, 02286 .get_virt_usec = _solaris_get_virt_usec, 02287 .update_shlib_info = _solaris_update_shlib_info, 02288 .get_system_info = _solaris_get_system_info, 02289 };