|
PAPI
5.0.1.0
|
00001 /* 00002 * File: solaris-ultra.c 00003 * Author: Philip Mucci 00004 * mucci@cs.utk.edu 00005 * Mods: Kevin London 00006 * london@cs.utk.edu 00007 * Mods: Min Zhou 00008 * min@cs.utk.edu 00009 * Mods: Larry Meadows(helped us to build the native table dynamically) 00010 * Mods: Brian Sheely 00011 * bsheely@eecs.utk.edu 00012 * Mods: Vince Weaver 00013 * vweaver1@eecs.utk.edu 00014 */ 00015 00016 /* to understand this program, first you should read the user's manual 00017 about UltraSparc II and UltraSparc III, then the man pages 00018 about cpc_take_sample(cpc_event_t *event) 00019 */ 00020 00021 #include "papi.h" 00022 #include "papi_internal.h" 00023 #include "papi_vector.h" 00024 #include "papi_memory.h" 00025 #include <sys/utsname.h> 00026 00027 #include "solaris-common.h" 00028 #include "solaris-memory.h" 00029 00030 #ifdef CPC_ULTRA3_I 00031 #define LASTULTRA3 CPC_ULTRA3_I 00032 #else 00033 #define LASTULTRA3 CPC_ULTRA3_PLUS 00034 #endif 00035 00036 #define MAX_ENAME 40 00037 00038 static void action( void *arg, int regno, const char *name, uint8_t bits ); 00039 00040 /* Probably could dispense with this and just use native_table */ 00041 typedef struct ctr_info 00042 { 00043 char *name; /* Counter name */ 00044 int bits[2]; /* bits for register */ 00045 int bitmask; /* 1 = pic0; 2 = pic1; 3 = both */ 00046 } ctr_info_t; 00047 00048 typedef struct einfo 00049 { 00050 unsigned int papi_event; 00051 char *event_str; 00052 } einfo_t; 00053 static einfo_t us3info[] = { 00054 {PAPI_FP_INS, "FA_pipe_completion+FM_pipe_completion"}, 00055 {PAPI_FAD_INS, "FA_pipe_completion"}, 00056 {PAPI_FML_INS, "FM_pipe_completion"}, 00057 {PAPI_TLB_IM, "ITLB_miss"}, 00058 {PAPI_TLB_DM, "DTLB_miss"}, 00059 {PAPI_TOT_CYC, "Cycle_cnt"}, 00060 {PAPI_TOT_IIS, "Instr_cnt"}, 00061 {PAPI_TOT_INS, "Instr_cnt"}, 00062 {PAPI_L2_TCM, "EC_misses"}, 00063 {PAPI_L2_ICM, "EC_ic_miss"}, 00064 {PAPI_L1_ICM, "IC_miss"}, 00065 {PAPI_L1_LDM, "DC_rd_miss"}, 00066 {PAPI_L1_STM, "DC_wr_miss"}, 00067 {PAPI_L2_LDM, "EC_rd_miss"}, 00068 {PAPI_BR_MSP, "IU_Stat_Br_miss_taken+IU_Stat_Br_miss_untaken"}, 00069 {PAPI_L1_DCR, "DC_rd"}, 00070 {PAPI_L1_DCW, "DC_wr"}, 00071 {PAPI_L1_ICH, "IC_ref-IC_miss"}, /* Is this really hits only? */ 00072 {PAPI_L1_ICA, "IC_ref"}, /* Ditto? */ 00073 {PAPI_L2_TCH, "EC_ref-EC_misses"}, 00074 {PAPI_L2_TCA, "EC_ref"}, 00075 }; 00076 00077 static einfo_t us2info[] = { 00078 {PAPI_L1_ICM, "IC_ref-IC_hit"}, 00079 {PAPI_L2_TCM, "EC_ref-EC_hit"}, 00080 {PAPI_CA_SNP, "EC_snoop_cb"}, 00081 {PAPI_CA_INV, "EC_snoop_inv"}, 00082 {PAPI_L1_LDM, "DC_rd-DC_rd_hit"}, 00083 {PAPI_L1_STM, "DC_wr-DC_wr_hit"}, 00084 {PAPI_L2_LDM, "EC_rd_miss"}, 00085 {PAPI_BR_MSP, "Dispatch0_mispred"}, 00086 {PAPI_TOT_IIS, "Instr_cnt"}, 00087 {PAPI_TOT_INS, "Instr_cnt"}, 00088 {PAPI_LD_INS, "DC_rd"}, 00089 {PAPI_SR_INS, "DC_wr"}, 00090 {PAPI_TOT_CYC, "Cycle_cnt"}, 00091 {PAPI_L1_DCR, "DC_rd"}, 00092 {PAPI_L1_DCW, "DC_wr"}, 00093 {PAPI_L1_ICH, "IC_hit"}, 00094 {PAPI_L2_ICH, "EC_ic_hit"}, 00095 {PAPI_L1_ICA, "IC_ref"}, 00096 {PAPI_L2_TCH, "EC_hit"}, 00097 {PAPI_L2_TCA, "EC_ref"}, 00098 }; 00099 00100 papi_vector_t _solaris_vector; 00101 00102 static native_info_t *native_table; 00103 static hwi_search_t *preset_table; 00104 00105 static struct ctr_info *ctrs; 00106 static int nctrs; 00107 00108 static int build_tables( void ); 00109 static void add_preset( hwi_search_t * tab, int *np, einfo_t e ); 00110 00111 /* Globals used to access the counter registers. */ 00112 00113 static int cpuver; 00114 static int pcr_shift[2]; 00115 00116 hwi_search_t *preset_search_map; 00117 00118 #ifdef DEBUG 00119 static void 00120 dump_cmd( papi_cpc_event_t * t ) 00121 { 00122 SUBDBG( "cpc_event_t.ce_cpuver %d\n", t->cmd.ce_cpuver ); 00123 SUBDBG( "ce_tick %llu\n", t->cmd.ce_tick ); 00124 SUBDBG( "ce_pic[0] %llu ce_pic[1] %llu\n", t->cmd.ce_pic[0], 00125 t->cmd.ce_pic[1] ); 00126 SUBDBG( "ce_pcr 0x%llx\n", t->cmd.ce_pcr ); 00127 SUBDBG( "flags %x\n", t->flags ); 00128 } 00129 #endif 00130 00131 static void 00132 dispatch_emt( int signal, siginfo_t * sip, void *arg ) 00133 { 00134 int event_counter; 00135 _papi_hwi_context_t ctx; 00136 caddr_t address; 00137 ctx.si = sip; 00138 ctx.ucontext = arg; 00139 SUBDBG( "%d, %p, %p\n", signal, sip, arg ); 00140 00141 if ( sip->si_code == EMT_CPCOVF ) { 00142 papi_cpc_event_t *sample; 00143 EventSetInfo_t *ESI; 00144 ThreadInfo_t *thread = NULL; 00145 int t, overflow_vector, readvalue; 00146 00147 thread = _papi_hwi_lookup_thread( 0 ); 00148 ESI = ( EventSetInfo_t * ) thread->running_eventset; 00149 int cidx = ESI->CmpIdx; 00150 00151 if ( ( ESI == NULL ) || ( ( ESI->state & PAPI_OVERFLOWING ) == 0 ) ) { 00152 OVFDBG( "Either no eventset or eventset not set to overflow.\n" ); 00153 return; 00154 } 00155 00156 if ( ESI->master != thread ) { 00157 PAPIERROR 00158 ( "eventset->thread 0x%lx vs. current thread 0x%lx mismatch", 00159 ESI->master, thread ); 00160 return; 00161 } 00162 00163 event_counter = ESI->overflow.event_counter; 00164 sample = &( ESI->ctl_state->counter_cmd ); 00165 00166 /* GROSS! This is a hack to 'push' the correct values 00167 back into the hardware, such that when PAPI handles 00168 the overflow and reads the values, it gets the correct ones. 00169 */ 00170 00171 /* Find which HW counter overflowed */ 00172 00173 if ( ESI->EventInfoArray[ESI->overflow.EventIndex[0]].pos[0] == 0 ) 00174 t = 0; 00175 else 00176 t = 1; 00177 00178 if ( cpc_take_sample( &sample->cmd ) == -1 ) 00179 return; 00180 if ( event_counter == 1 ) { 00181 /* only one event is set to be the overflow monitor */ 00182 00183 /* generate the overflow vector */ 00184 overflow_vector = 1 << t; 00185 /* reset the threshold */ 00186 sample->cmd.ce_pic[t] = UINT64_MAX - ESI->overflow.threshold[0]; 00187 } else { 00188 /* two events are set to be the overflow monitors */ 00189 overflow_vector = 0; 00190 readvalue = sample->cmd.ce_pic[0]; 00191 if ( readvalue >= 0 ) { 00192 /* the first counter overflowed */ 00193 00194 /* generate the overflow vector */ 00195 overflow_vector = 1; 00196 /* reset the threshold */ 00197 if ( t == 0 ) 00198 sample->cmd.ce_pic[0] = 00199 UINT64_MAX - ESI->overflow.threshold[0]; 00200 else 00201 sample->cmd.ce_pic[0] = 00202 UINT64_MAX - ESI->overflow.threshold[1]; 00203 } 00204 readvalue = sample->cmd.ce_pic[1]; 00205 if ( readvalue >= 0 ) { 00206 /* the second counter overflowed */ 00207 00208 /* generate the overflow vector */ 00209 overflow_vector ^= 1 << 1; 00210 /* reset the threshold */ 00211 if ( t == 0 ) 00212 sample->cmd.ce_pic[1] = 00213 UINT64_MAX - ESI->overflow.threshold[1]; 00214 else 00215 sample->cmd.ce_pic[1] = 00216 UINT64_MAX - ESI->overflow.threshold[0]; 00217 } 00218 SUBDBG( "overflow_vector, = %d\n", overflow_vector ); 00219 /* something is wrong here */ 00220 if ( overflow_vector == 0 ) { 00221 PAPIERROR( "BUG! overflow_vector is 0, dropping interrupt" ); 00222 return; 00223 } 00224 } 00225 00226 /* Call the regular overflow function in extras.c */ 00227 if ( thread->running_eventset[cidx]->overflow. 00228 flags & PAPI_OVERFLOW_FORCE_SW ) { 00229 address = GET_OVERFLOW_ADDRESS(ctx); 00230 _papi_hwi_dispatch_overflow_signal( ( void * ) &ctx, address, NULL, 00231 overflow_vector, 0, &thread, 00232 cidx ); 00233 } else { 00234 PAPIERROR( "Additional implementation needed in dispatch_emt!" ); 00235 } 00236 00237 #if DEBUG 00238 dump_cmd( sample ); 00239 #endif 00240 /* push back the correct values and start counting again */ 00241 if ( cpc_bind_event( &sample->cmd, sample->flags ) == -1 ) 00242 return; 00243 } else { 00244 SUBDBG( "dispatch_emt() dropped, si_code = %d\n", sip->si_code ); 00245 return; 00246 } 00247 } 00248 00249 static int 00250 scan_prtconf( char *cpuname, int len_cpuname, int *hz, int *ver ) 00251 { 00252 /* This code courtesy of our friends in Germany. Thanks Rudolph Berrendorf! */ 00253 /* See the PCL home page for the German version of PAPI. */ 00254 /* Modified by Nils Smeds, all new bugs are my fault */ 00255 /* The routine now looks for the first "Node" with the following: */ 00256 /* "device_type" = 'cpu' */ 00257 /* "name" = (Any value) */ 00258 /* "sparc-version" = (Any value) */ 00259 /* "clock-frequency" = (Any value) */ 00260 int ihz, version; 00261 char line[256], cmd[80], name[256]; 00262 FILE *f = NULL; 00263 char cmd_line[PAPI_HUGE_STR_LEN + PAPI_HUGE_STR_LEN], fname[L_tmpnam]; 00264 unsigned int matched; 00265 00266 /*??? system call takes very long */ 00267 /* get system configuration and put output into file */ 00268 00269 tmpnam( fname ); 00270 SUBDBG( "Temporary name %s\n", fname ); 00271 00272 sprintf( cmd_line, "/usr/sbin/prtconf -vp > %s", fname ); 00273 SUBDBG( "Executing %s\n", cmd_line ); 00274 if ( system( cmd_line ) == -1 ) { 00275 remove( fname ); 00276 return -1; 00277 } 00278 00279 f = fopen( fname, "r" ); 00280 /* open output file */ 00281 if ( f == NULL ) { 00282 remove( fname ); 00283 return -1; 00284 } 00285 00286 /* ignore all lines until we reach something with a sparc line */ 00287 matched = 0x0; 00288 ihz = -1; 00289 while ( fgets( line, 256, f ) != NULL ) { 00290 /*SUBDBG(">>> %s",line); */ 00291 if ( ( sscanf( line, "%s", cmd ) == 1 ) 00292 && strstr( line, "Node 0x" ) ) { 00293 matched = 0x0; 00294 /*SUBDBG("Found 'Node' -- search reset. (0x%2.2x)\n",matched); */ 00295 } else { 00296 if ( strstr( cmd, "device_type:" ) && strstr( line, "'cpu'" ) ) { 00297 matched |= 0x1; 00298 SUBDBG( "Found 'cpu'. (0x%2.2x)\n", matched ); 00299 } else if ( !strcmp( cmd, "sparc-version:" ) && 00300 ( sscanf( line, "%s %x", cmd, &version ) == 2 ) ) { 00301 matched |= 0x2; 00302 SUBDBG( "Found version=%d. (0x%2.2x)\n", version, matched ); 00303 } else if ( !strcmp( cmd, "clock-frequency:" ) && 00304 ( sscanf( line, "%s %x", cmd, &ihz ) == 2 ) ) { 00305 matched |= 0x4; 00306 SUBDBG( "Found ihz=%d. (0x%2.2x)\n", ihz, matched ); 00307 } else if ( !strcmp( cmd, "name:" ) && 00308 ( sscanf( line, "%s %s", cmd, name ) == 2 ) ) { 00309 matched |= 0x8; 00310 SUBDBG( "Found name: %s. (0x%2.2x)\n", name, matched ); 00311 } 00312 } 00313 if ( ( matched & 0xF ) == 0xF ) 00314 break; 00315 } 00316 SUBDBG( "Parsing found name=%s, speed=%dHz, version=%d\n", name, ihz, 00317 version ); 00318 00319 if ( matched ^ 0x0F ) 00320 ihz = -1; 00321 else { 00322 *hz = ( float ) ihz; 00323 *ver = version; 00324 strncpy( cpuname, name, len_cpuname ); 00325 } 00326 00327 return ihz; 00328 00329 /* End stolen code */ 00330 } 00331 00332 int 00333 _ultra_set_domain( hwd_control_state_t * this_state, int domain ) 00334 { 00335 papi_cpc_event_t *command = &this_state->counter_cmd; 00336 cpc_event_t *event = &command->cmd; 00337 uint64_t pcr = event->ce_pcr; 00338 int did = 0; 00339 00340 pcr = pcr | 0x7; 00341 pcr = pcr ^ 0x7; 00342 00343 if ( domain & PAPI_DOM_USER ) { 00344 pcr = pcr | 1 << CPC_ULTRA_PCR_USR; 00345 did = 1; 00346 } 00347 if ( domain & PAPI_DOM_KERNEL ) { 00348 pcr = pcr | 1 << CPC_ULTRA_PCR_SYS; 00349 did = 1; 00350 } 00351 /* DOMAIN ERROR */ 00352 if ( !did ) { 00353 return ( PAPI_EINVAL ); 00354 } 00355 00356 event->ce_pcr = pcr; 00357 00358 return ( PAPI_OK ); 00359 } 00360 00361 static int 00362 set_granularity( hwd_control_state_t * this_state, int domain ) 00363 { 00364 switch ( domain ) { 00365 case PAPI_GRN_PROCG: 00366 case PAPI_GRN_SYS: 00367 case PAPI_GRN_SYS_CPU: 00368 case PAPI_GRN_PROC: 00369 return PAPI_ECMP; 00370 case PAPI_GRN_THR: 00371 break; 00372 default: 00373 return ( PAPI_EINVAL ); 00374 } 00375 return ( PAPI_OK ); 00376 } 00377 00378 /* Utility functions */ 00379 00380 /* This is a wrapper arount fprintf(stderr,...) for cpc_walk_events() */ 00381 void 00382 print_walk_names( void *arg, int regno, const char *name, uint8_t bits ) 00383 { 00384 SUBDBG( arg, regno, name, bits ); 00385 } 00386 00387 00388 static int 00389 build_tables( void ) 00390 { 00391 int i; 00392 int regno; 00393 int npic; 00394 einfo_t *ep; 00395 int n; 00396 int npresets; 00397 npic = cpc_getnpic( cpuver ); 00398 nctrs = 0; 00399 for ( regno = 0; regno < npic; ++regno ) { 00400 cpc_walk_names( cpuver, regno, 0, action ); 00401 } 00402 SUBDBG( "%d counters\n", nctrs ); 00403 if ( ( ctrs = papi_malloc( nctrs * sizeof ( struct ctr_info ) ) ) == 0 ) { 00404 return PAPI_ENOMEM; 00405 } 00406 nctrs = 0; 00407 for ( regno = 0; regno < npic; ++regno ) { 00408 cpc_walk_names( cpuver, regno, ( void * ) 1, action ); 00409 } 00410 SUBDBG( "%d counters\n", nctrs ); 00411 #if DEBUG 00412 if ( ISLEVEL( DEBUG_SUBSTRATE ) ) { 00413 for ( i = 0; i < nctrs; ++i ) { 00414 SUBDBG( "%s: bits (%x,%x) pics %x\n", ctrs[i].name, ctrs[i].bits[0], 00415 ctrs[i].bits[1], ctrs[i].bitmask ); 00416 } 00417 } 00418 #endif 00419 /* Build the native event table */ 00420 if ( ( native_table = 00421 papi_malloc( nctrs * sizeof ( native_info_t ) ) ) == 0 ) { 00422 papi_free( ctrs ); 00423 return PAPI_ENOMEM; 00424 } 00425 for ( i = 0; i < nctrs; ++i ) { 00426 native_table[i].name[39] = 0; 00427 strncpy( native_table[i].name, ctrs[i].name, 39 ); 00428 if ( ctrs[i].bitmask & 1 ) 00429 native_table[i].encoding[0] = ctrs[i].bits[0]; 00430 else 00431 native_table[i].encoding[0] = -1; 00432 if ( ctrs[i].bitmask & 2 ) 00433 native_table[i].encoding[1] = ctrs[i].bits[1]; 00434 else 00435 native_table[i].encoding[1] = -1; 00436 } 00437 papi_free( ctrs ); 00438 00439 /* Build the preset table */ 00440 if ( cpuver <= CPC_ULTRA2 ) { 00441 n = sizeof ( us2info ) / sizeof ( einfo_t ); 00442 ep = us2info; 00443 } else if ( cpuver <= LASTULTRA3 ) { 00444 n = sizeof ( us3info ) / sizeof ( einfo_t ); 00445 ep = us3info; 00446 } else 00447 return PAPI_ECMP; 00448 preset_table = papi_malloc( ( n + 1 ) * sizeof ( hwi_search_t ) ); 00449 npresets = 0; 00450 for ( i = 0; i < n; ++i ) { 00451 add_preset( preset_table, &npresets, ep[i] ); 00452 } 00453 memset( &preset_table[npresets], 0, sizeof ( hwi_search_t ) ); 00454 00455 #ifdef DEBUG 00456 if ( ISLEVEL( DEBUG_SUBSTRATE ) ) { 00457 SUBDBG( "Native table: %d\n", nctrs ); 00458 for ( i = 0; i < nctrs; ++i ) { 00459 SUBDBG( "%40s: %8x %8x\n", native_table[i].name, 00460 native_table[i].encoding[0], native_table[i].encoding[1] ); 00461 } 00462 SUBDBG( "\nPreset table: %d\n", npresets ); 00463 for ( i = 0; preset_table[i].event_code != 0; ++i ) { 00464 SUBDBG( "%8x: op %2d e0 %8x e1 %8x\n", 00465 preset_table[i].event_code, 00466 preset_table[i].data.derived, 00467 preset_table[i].data.native[0], 00468 preset_table[i].data.native[1] ); 00469 } 00470 } 00471 #endif 00472 00473 _solaris_vector.cmp_info.num_native_events = nctrs; 00474 00475 return PAPI_OK; 00476 } 00477 00478 static int 00479 srch_event( char *e1 ) 00480 { 00481 int i; 00482 00483 for ( i = 0; i < nctrs; ++i ) { 00484 if ( strcmp( e1, native_table[i].name ) == 0 ) 00485 break; 00486 } 00487 if ( i >= nctrs ) 00488 return -1; 00489 return i; 00490 } 00491 00492 /* we should read from the CSV file and make this all unnecessary */ 00493 00494 static void 00495 add_preset( hwi_search_t * tab, int *np, einfo_t e ) 00496 { 00497 /* Parse the event info string and build the PAPI preset. 00498 * If parse fails, just return, otherwise increment the table 00499 * size. We assume that the table is big enough. 00500 */ 00501 char *p; 00502 char *q; 00503 char op; 00504 char e1[MAX_ENAME], e2[MAX_ENAME]; 00505 int i; 00506 int ne; 00507 int ne2; 00508 00509 p = e.event_str; 00510 /* Assume p is the name of a native event, the sum of two 00511 * native events, or the difference of two native events. 00512 * This could be extended with a real parser (hint). 00513 */ 00514 while ( isspace( *p ) ) 00515 ++p; 00516 q = p; 00517 i = 0; 00518 while ( isalnum( *p ) || ( *p == '_' ) ) { 00519 if ( i >= MAX_ENAME - 1 ) 00520 break; 00521 e1[i] = *p++; 00522 ++i; 00523 } 00524 e1[i] = 0; 00525 if ( *p == '+' || *p == '-' ) 00526 op = *p++; 00527 else 00528 op = 0; 00529 while ( isspace( *p ) ) 00530 ++p; 00531 q = p; 00532 i = 0; 00533 while ( isalnum( *p ) || ( *p == '_' ) ) { 00534 if ( i >= MAX_ENAME - 1 ) 00535 break; 00536 e2[i] = *p++; 00537 ++i; 00538 } 00539 e2[i] = 0; 00540 00541 if ( e2[0] == 0 && e1[0] == 0 ) { 00542 return; 00543 } 00544 if ( e2[0] == 0 || op == 0 ) { 00545 ne = srch_event( e1 ); 00546 if ( ne == -1 ) 00547 return; 00548 tab[*np].event_code = e.papi_event; 00549 tab[*np].data.derived = 0; 00550 tab[*np].data.native[0] = PAPI_NATIVE_MASK | ne; 00551 tab[*np].data.native[1] = PAPI_NULL; 00552 memset( tab[*np].data.operation, 0, 00553 sizeof ( tab[*np].data.operation ) ); 00554 ++*np; 00555 return; 00556 } 00557 ne = srch_event( e1 ); 00558 ne2 = srch_event( e2 ); 00559 if ( ne == -1 || ne2 == -1 ) 00560 return; 00561 tab[*np].event_code = e.papi_event; 00562 tab[*np].data.derived = ( op == '-' ) ? DERIVED_SUB : DERIVED_ADD; 00563 tab[*np].data.native[0] = PAPI_NATIVE_MASK | ne; 00564 tab[*np].data.native[1] = PAPI_NATIVE_MASK | ne2; 00565 tab[*np].data.native[2] = PAPI_NULL; 00566 memset( tab[*np].data.operation, 0, sizeof ( tab[*np].data.operation ) ); 00567 ++*np; 00568 } 00569 00570 void 00571 action( void *arg, int regno, const char *name, uint8_t bits ) 00572 { 00573 int i; 00574 00575 if ( arg == 0 ) { 00576 ++nctrs; 00577 return; 00578 } 00579 assert( regno == 0 || regno == 1 ); 00580 for ( i = 0; i < nctrs; ++i ) { 00581 if ( strcmp( ctrs[i].name, name ) == 0 ) { 00582 ctrs[i].bits[regno] = bits; 00583 ctrs[i].bitmask |= ( 1 << regno ); 00584 return; 00585 } 00586 } 00587 memset( &ctrs[i], 0, sizeof ( ctrs[i] ) ); 00588 ctrs[i].name = papi_strdup( name ); 00589 ctrs[i].bits[regno] = bits; 00590 ctrs[i].bitmask = ( 1 << regno ); 00591 ++nctrs; 00592 } 00593 00594 /* This function should tell your kernel extension that your children 00595 inherit performance register information and propagate the values up 00596 upon child exit and parent wait. */ 00597 00598 static int 00599 set_inherit( EventSetInfo_t * global, int arg ) 00600 { 00601 return PAPI_ECMP; 00602 00603 /* 00604 hwd_control_state_t *machdep = (hwd_control_state_t *)global->machdep; 00605 papi_cpc_event_t *command= &machdep->counter_cmd; 00606 00607 return(PAPI_EINVAL); 00608 */ 00609 00610 #if 0 00611 if ( arg == 0 ) { 00612 if ( command->flags & CPC_BIND_LWP_INHERIT ) 00613 command->flags = command->flags ^ CPC_BIND_LWP_INHERIT; 00614 } else if ( arg == 1 ) { 00615 command->flags = command->flags | CPC_BIND_LWP_INHERIT; 00616 } else 00617 return ( PAPI_EINVAL ); 00618 00619 return ( PAPI_OK ); 00620 #endif 00621 } 00622 00623 static int 00624 set_default_domain( hwd_control_state_t * ctrl_state, int domain ) 00625 { 00626 /* This doesn't exist on this platform */ 00627 00628 if ( domain == PAPI_DOM_OTHER ) 00629 return ( PAPI_EINVAL ); 00630 00631 return ( _ultra_set_domain( ctrl_state, domain ) ); 00632 } 00633 00634 static int 00635 set_default_granularity( hwd_control_state_t * current_state, int granularity ) 00636 { 00637 return ( set_granularity( current_state, granularity ) ); 00638 } 00639 00640 rwlock_t lock[PAPI_MAX_LOCK]; 00641 00642 static void 00643 lock_init( void ) 00644 { 00645 memset( lock, 0x0, sizeof ( rwlock_t ) * PAPI_MAX_LOCK ); 00646 } 00647 00648 int 00649 _ultra_hwd_shutdown_component( void ) 00650 { 00651 ( void ) cpc_rele( ); 00652 return ( PAPI_OK ); 00653 } 00654 00655 int 00656 _ultra_hwd_init_component( int cidx ) 00657 { 00658 int retval; 00659 /* retval = _papi_hwi_setup_vector_table(vtable, _solaris_ultra_table); 00660 if ( retval != PAPI_OK ) return(retval); */ 00661 00662 /* Fill in what we can of the papi_system_info. */ 00663 retval = _solaris_get_system_info( &_papi_hwi_system_info ); 00664 if ( retval ) 00665 return ( retval ); 00666 00667 /* Setup memory info */ 00668 retval = _papi_os_vector.get_memory_info( &_papi_hwi_system_info.hw_info, 00669 0 ); 00670 if ( retval ) 00671 return ( retval ); 00672 00673 00674 lock_init( ); 00675 00676 SUBDBG( "Found %d %s %s CPUs at %d Mhz.\n", 00677 _papi_hwi_system_info.hw_info.totalcpus, 00678 _papi_hwi_system_info.hw_info.vendor_string, 00679 _papi_hwi_system_info.hw_info.model_string, 00680 _papi_hwi_system_info.hw_info.cpu_max_mhz ); 00681 00682 return ( PAPI_OK ); 00683 } 00684 00685 /* reset the hardware counter */ 00686 int 00687 _ultra_hwd_reset( hwd_context_t * ctx, hwd_control_state_t * ctrl ) 00688 { 00689 int retval; 00690 00691 /* reset the hardware counter */ 00692 ctrl->counter_cmd.cmd.ce_pic[0] = 0; 00693 ctrl->counter_cmd.cmd.ce_pic[1] = 0; 00694 /* let's rock and roll */ 00695 retval = cpc_bind_event( &ctrl->counter_cmd.cmd, ctrl->counter_cmd.flags ); 00696 if ( retval == -1 ) 00697 return ( PAPI_ESYS ); 00698 00699 return ( PAPI_OK ); 00700 } 00701 00702 00703 int 00704 _ultra_hwd_read( hwd_context_t * ctx, hwd_control_state_t * ctrl, 00705 long long **events, int flags ) 00706 { 00707 int retval; 00708 00709 retval = cpc_take_sample( &ctrl->counter_cmd.cmd ); 00710 if ( retval == -1 ) 00711 return ( PAPI_ESYS ); 00712 00713 *events = ( long long * ) ctrl->counter_cmd.cmd.ce_pic; 00714 00715 return PAPI_OK; 00716 } 00717 00718 int 00719 _ultra_hwd_ctl( hwd_context_t * ctx, int code, _papi_int_option_t * option ) 00720 { 00721 00722 switch ( code ) { 00723 case PAPI_DEFDOM: 00724 return ( set_default_domain 00725 ( option->domain.ESI->ctl_state, option->domain.domain ) ); 00726 case PAPI_DOMAIN: 00727 return ( _ultra_set_domain 00728 ( option->domain.ESI->ctl_state, option->domain.domain ) ); 00729 case PAPI_DEFGRN: 00730 return ( set_default_granularity 00731 ( option->domain.ESI->ctl_state, 00732 option->granularity.granularity ) ); 00733 case PAPI_GRANUL: 00734 return ( set_granularity 00735 ( option->granularity.ESI->ctl_state, 00736 option->granularity.granularity ) ); 00737 default: 00738 return ( PAPI_EINVAL ); 00739 } 00740 } 00741 00742 void 00743 _ultra_hwd_dispatch_timer( int signal, siginfo_t * si, void *context ) 00744 { 00745 00746 _papi_hwi_context_t ctx; 00747 ThreadInfo_t *master = NULL; 00748 int isHardware = 0; 00749 caddr_t address; 00750 int cidx = _solaris_vector.cmp_info.CmpIdx; 00751 00752 ctx.si = si; 00753 ctx.ucontext = ( ucontext_t * ) context; 00754 00755 address = GET_OVERFLOW_ADDRESS( ctx ); 00756 _papi_hwi_dispatch_overflow_signal( ( void * ) &ctx, address, &isHardware, 00757 0, 0, &master, _solaris_vector.cmp_info.CmpIdx ); 00758 00759 /* We are done, resume interrupting counters */ 00760 if ( isHardware ) { 00761 // errno = vperfctr_iresume( master->context[cidx]->perfctr ); 00762 //if ( errno < 0 ) { 00763 // PAPIERROR( "vperfctr_iresume errno %d", errno ); 00764 //} 00765 } 00766 00767 00768 #if 0 00769 EventSetInfo_t *ESI = NULL; 00770 ThreadInfo_t *thread = NULL; 00771 int overflow_vector = 0; 00772 hwd_control_state_t *ctrl = NULL; 00773 long_long results[MAX_COUNTERS]; 00774 int i; 00775 _papi_hwi_context_t ctx; 00776 caddr_t address; 00777 int cidx = _solaris_vector.cmp_info.CmpIdx; 00778 00779 ctx.si = si; 00780 ctx.ucontext = ( hwd_ucontext_t * ) info; 00781 00782 thread = _papi_hwi_lookup_thread( 0 ); 00783 00784 if ( thread == NULL ) { 00785 PAPIERROR( "thread == NULL in _papi_hwd_dispatch_timer"); 00786 return; 00787 } 00788 00789 ESI = ( EventSetInfo_t * ) thread->running_eventset[cidx]; 00790 00791 00792 if ( ESI == NULL || ESI->master != thread || ESI->ctl_state == NULL || 00793 ( ( ESI->state & PAPI_OVERFLOWING ) == 0 ) ) { 00794 00795 if ( ESI == NULL ) 00796 PAPIERROR( "ESI is NULL\n"); 00797 00798 if ( ESI->master != thread ) 00799 PAPIERROR( "Thread mismatch, ESI->master=%x thread=%x\n", 00800 ESI->master, thread ); 00801 00802 if ( ESI->ctl_state == NULL ) 00803 PAPIERROR( "Counter state invalid\n"); 00804 00805 if ( ( ( ESI->state & PAPI_OVERFLOWING ) == 0 ) ) 00806 PAPIERROR( "Overflow flag missing"); 00807 } 00808 00809 ctrl = ESI->ctl_state; 00810 00811 if ( thread->running_eventset[cidx]->overflow.flags & PAPI_OVERFLOW_FORCE_SW ) { 00812 address = GET_OVERFLOW_ADDRESS( ctx ); 00813 _papi_hwi_dispatch_overflow_signal( ( void * ) &ctx, address, NULL, 0, 00814 0, &thread, cidx ); 00815 } else { 00816 PAPIERROR ( "Need to implement additional code in _papi_hwd_dispatch_timer!" ); 00817 } 00818 #endif 00819 } 00820 00821 int 00822 _ultra_hwd_set_overflow( EventSetInfo_t * ESI, int EventIndex, int threshold ) 00823 { 00824 hwd_control_state_t *this_state = ESI->ctl_state; 00825 papi_cpc_event_t *arg = &this_state->counter_cmd; 00826 int hwcntr; 00827 00828 if ( threshold == 0 ) { 00829 if ( this_state->overflow_num == 1 ) { 00830 arg->flags ^= CPC_BIND_EMT_OVF; 00831 if ( sigaction 00832 ( _solaris_vector.cmp_info.hardware_intr_sig, NULL, 00833 NULL ) == -1 ) 00834 return ( PAPI_ESYS ); 00835 this_state->overflow_num = 0; 00836 } else 00837 this_state->overflow_num--; 00838 00839 } else { 00840 struct sigaction act; 00841 /* increase the counter for overflow events */ 00842 this_state->overflow_num++; 00843 00844 act.sa_sigaction = dispatch_emt; 00845 memset( &act.sa_mask, 0x0, sizeof ( act.sa_mask ) ); 00846 act.sa_flags = SA_RESTART | SA_SIGINFO; 00847 if ( sigaction 00848 ( _solaris_vector.cmp_info.hardware_intr_sig, &act, 00849 NULL ) == -1 ) 00850 return ( PAPI_ESYS ); 00851 00852 arg->flags |= CPC_BIND_EMT_OVF; 00853 hwcntr = ESI->EventInfoArray[EventIndex].pos[0]; 00854 if ( hwcntr == 0 ) 00855 arg->cmd.ce_pic[0] = UINT64_MAX - ( uint64_t ) threshold; 00856 else if ( hwcntr == 1 ) 00857 arg->cmd.ce_pic[1] = UINT64_MAX - ( uint64_t ) threshold; 00858 } 00859 00860 return ( PAPI_OK ); 00861 } 00862 00863 00864 _ultra_shutdown( hwd_context_t * ctx ) 00865 { 00866 00867 return PAPI_OK; 00868 } 00869 00870 00871 /* 00872 int _papi_hwd_stop_profiling(ThreadInfo_t * master, EventSetInfo_t * ESI) 00873 { 00874 ESI->profile.overflowcount = 0; 00875 return (PAPI_OK); 00876 } 00877 */ 00878 00879 void * 00880 _ultra_hwd_get_overflow_address( void *context ) 00881 { 00882 void *location; 00883 ucontext_t *info = ( ucontext_t * ) context; 00884 location = ( void * ) info->uc_mcontext.gregs[REG_PC]; 00885 00886 return ( location ); 00887 } 00888 00889 int 00890 _ultra_hwd_start( hwd_context_t * ctx, hwd_control_state_t * ctrl ) 00891 { 00892 int retval; 00893 00894 /* reset the hardware counter */ 00895 if ( ctrl->overflow_num == 0 ) { 00896 ctrl->counter_cmd.cmd.ce_pic[0] = 0; 00897 ctrl->counter_cmd.cmd.ce_pic[1] = 0; 00898 } 00899 /* let's rock and roll */ 00900 retval = cpc_bind_event( &ctrl->counter_cmd.cmd, ctrl->counter_cmd.flags ); 00901 if ( retval == -1 ) 00902 return ( PAPI_ESYS ); 00903 00904 return ( PAPI_OK ); 00905 } 00906 00907 int 00908 _ultra_hwd_stop( hwd_context_t * ctx, hwd_control_state_t * ctrl ) 00909 { 00910 cpc_bind_event( NULL, 0 ); 00911 return PAPI_OK; 00912 } 00913 00914 int 00915 _ultra_hwd_remove_event( hwd_register_map_t * chosen, 00916 unsigned int hardware_index, hwd_control_state_t * out ) 00917 { 00918 return PAPI_OK; 00919 } 00920 00921 int 00922 _ultra_hwd_encode_native( char *name, int *code ) 00923 { 00924 return ( PAPI_OK ); 00925 } 00926 00927 int 00928 _ultra_hwd_ntv_enum_events( unsigned int *EventCode, int modifier ) 00929 { 00930 int index = *EventCode & PAPI_NATIVE_AND_MASK; 00931 00932 if ( modifier == PAPI_ENUM_FIRST ) { 00933 *EventCode = PAPI_NATIVE_MASK + 1; 00934 00935 return PAPI_OK; 00936 } 00937 00938 if ( cpuver <= CPC_ULTRA2 ) { 00939 if ( index < MAX_NATIVE_EVENT_USII - 1 ) { 00940 *EventCode = *EventCode + 1; 00941 return ( PAPI_OK ); 00942 } else 00943 return ( PAPI_ENOEVNT ); 00944 } else if ( cpuver <= LASTULTRA3 ) { 00945 if ( index < MAX_NATIVE_EVENT - 1 ) { 00946 *EventCode = *EventCode + 1; 00947 return ( PAPI_OK ); 00948 } else 00949 return ( PAPI_ENOEVNT ); 00950 }; 00951 return ( PAPI_ENOEVNT ); 00952 } 00953 00954 int 00955 _ultra_hwd_ntv_code_to_name( unsigned int EventCode, char *ntv_name, int len ) 00956 { 00957 00958 int event_code = EventCode & PAPI_NATIVE_AND_MASK; 00959 00960 if ( event_code >= 0 && event_code < nctrs ) { 00961 strlcpy( ntv_name, native_table[event_code].name, len ); 00962 return PAPI_OK; 00963 } 00964 return PAPI_ENOEVNT; 00965 } 00966 00967 00968 int 00969 _ultra_hwd_ntv_code_to_descr( unsigned int EventCode, char *hwd_descr, int len ) 00970 { 00971 return ( _ultra_hwd_ntv_code_to_name( EventCode, hwd_descr, len ) ); 00972 } 00973 00974 static void 00975 copy_value( unsigned int val, char *nam, char *names, unsigned int *values, 00976 int len ) 00977 { 00978 *values = val; 00979 strncpy( names, nam, len ); 00980 names[len - 1] = 0; 00981 } 00982 00983 int 00984 _ultra_hwd_ntv_code_to_bits( unsigned int EventCode, hwd_register_t * bits ) 00985 { 00986 int index = EventCode & PAPI_NATIVE_AND_MASK; 00987 00988 if ( cpuver <= CPC_ULTRA2 ) { 00989 if ( index >= MAX_NATIVE_EVENT_USII ) { 00990 return ( PAPI_ENOEVNT ); 00991 } 00992 } else if ( cpuver <= LASTULTRA3 ) { 00993 if ( index >= MAX_NATIVE_EVENT ) { 00994 return ( PAPI_ENOEVNT ); 00995 } 00996 } else 00997 return ( PAPI_ENOEVNT ); 00998 00999 bits->event[0] = native_table[index].encoding[0]; 01000 bits->event[1] = native_table[index].encoding[1]; 01001 return ( PAPI_OK ); 01002 } 01003 01004 int 01005 _ultra_hwd_init_control_state( hwd_control_state_t * ptr ) 01006 { 01007 ptr->counter_cmd.flags = 0x0; 01008 ptr->counter_cmd.cmd.ce_cpuver = cpuver; 01009 ptr->counter_cmd.cmd.ce_pcr = 0x0; 01010 ptr->counter_cmd.cmd.ce_pic[0] = 0; 01011 ptr->counter_cmd.cmd.ce_pic[1] = 0; 01012 01013 _ultra_set_domain( ptr, _solaris_vector.cmp_info.default_domain ); 01014 set_granularity( ptr, _solaris_vector.cmp_info.default_granularity ); 01015 01016 return PAPI_OK; 01017 } 01018 01019 int 01020 _ultra_hwd_update_control_state( hwd_control_state_t * this_state, 01021 NativeInfo_t * native, int count, 01022 hwd_context_t * zero ) 01023 { 01024 int nidx1, nidx2, hwcntr; 01025 uint64_t tmp = 0; 01026 uint64_t pcr; 01027 int64_t cmd0, cmd1; 01028 01029 /* save the last three bits */ 01030 pcr = this_state->counter_cmd.cmd.ce_pcr & 0x7; 01031 01032 /* clear the control register */ 01033 this_state->counter_cmd.cmd.ce_pcr = pcr; 01034 01035 /* no native events left */ 01036 if ( count == 0 ) 01037 return ( PAPI_OK ); 01038 01039 cmd0 = -1; 01040 cmd1 = -1; 01041 /* one native event */ 01042 if ( count == 1 ) { 01043 nidx1 = native[0].ni_event & PAPI_NATIVE_AND_MASK; 01044 hwcntr = 0; 01045 cmd0 = native_table[nidx1].encoding[0]; 01046 native[0].ni_position = 0; 01047 if ( cmd0 == -1 ) { 01048 cmd1 = native_table[nidx1].encoding[1]; 01049 native[0].ni_position = 1; 01050 } 01051 } 01052 01053 /* two native events */ 01054 if ( count == 2 ) { 01055 int avail1, avail2; 01056 01057 avail1 = 0; 01058 avail2 = 0; 01059 nidx1 = native[0].ni_event & PAPI_NATIVE_AND_MASK; 01060 nidx2 = native[1].ni_event & PAPI_NATIVE_AND_MASK; 01061 if ( native_table[nidx1].encoding[0] != -1 ) 01062 avail1 = 0x1; 01063 if ( native_table[nidx1].encoding[1] != -1 ) 01064 avail1 += 0x2; 01065 if ( native_table[nidx2].encoding[0] != -1 ) 01066 avail2 = 0x1; 01067 if ( native_table[nidx2].encoding[1] != -1 ) 01068 avail2 += 0x2; 01069 if ( ( avail1 | avail2 ) != 0x3 ) 01070 return ( PAPI_ECNFLCT ); 01071 if ( avail1 == 0x3 ) { 01072 if ( avail2 == 0x1 ) { 01073 cmd0 = native_table[nidx2].encoding[0]; 01074 cmd1 = native_table[nidx1].encoding[1]; 01075 native[0].ni_position = 1; 01076 native[1].ni_position = 0; 01077 } else { 01078 cmd1 = native_table[nidx2].encoding[1]; 01079 cmd0 = native_table[nidx1].encoding[0]; 01080 native[0].ni_position = 0; 01081 native[1].ni_position = 1; 01082 } 01083 } else { 01084 if ( avail1 == 0x1 ) { 01085 cmd0 = native_table[nidx1].encoding[0]; 01086 cmd1 = native_table[nidx2].encoding[1]; 01087 native[0].ni_position = 0; 01088 native[1].ni_position = 1; 01089 } else { 01090 cmd0 = native_table[nidx2].encoding[0]; 01091 cmd1 = native_table[nidx1].encoding[1]; 01092 native[0].ni_position = 1; 01093 native[1].ni_position = 0; 01094 } 01095 } 01096 } 01097 01098 /* set the control register */ 01099 if ( cmd0 != -1 ) { 01100 tmp = ( ( uint64_t ) cmd0 << pcr_shift[0] ); 01101 } 01102 if ( cmd1 != -1 ) { 01103 tmp = tmp | ( ( uint64_t ) cmd1 << pcr_shift[1] ); 01104 } 01105 this_state->counter_cmd.cmd.ce_pcr = tmp | pcr; 01106 #if DEBUG 01107 dump_cmd( &this_state->counter_cmd ); 01108 #endif 01109 01110 return ( PAPI_OK ); 01111 } 01112 01113 01114 01115 01116 papi_vector_t _solaris_vector = { 01117 .cmp_info = { 01118 .name = "solaris.ultra", 01119 .description = "Solaris CPU counters", 01120 .num_cntrs = MAX_COUNTERS, 01121 .num_mpx_cntrs = MAX_COUNTERS, 01122 .default_domain = PAPI_DOM_USER, 01123 .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL, 01124 .default_granularity = PAPI_GRN_THR, 01125 .available_granularities = PAPI_GRN_THR, 01126 .fast_real_timer = 1, 01127 .fast_virtual_timer = 1, 01128 .attach = 1, 01129 .attach_must_ptrace = 1, 01130 .hardware_intr = 0, 01131 .hardware_intr_sig = PAPI_INT_SIGNAL, 01132 .precise_intr = 0, 01133 } 01134 , 01135 01136 /* component data structure sizes */ 01137 .size = { 01138 .context = sizeof ( hwd_context_t ), 01139 .control_state = sizeof ( hwd_control_state_t ), 01140 .reg_value = sizeof ( hwd_register_t ), 01141 .reg_alloc = sizeof ( hwd_reg_alloc_t ), 01142 } 01143 , 01144 01145 /* component interface functions */ 01146 .init_control_state = _ultra_hwd_init_control_state, 01147 .start = _ultra_hwd_start, 01148 .stop = _ultra_hwd_stop, 01149 .read = _ultra_hwd_read, 01150 .shutdown = _ultra_shutdown, 01151 .shutdown_component = _ultra_hwd_shutdown_component, 01152 .ctl = _ultra_hwd_ctl, 01153 .update_control_state = _ultra_hwd_update_control_state, 01154 .set_domain = _ultra_set_domain, 01155 .reset = _ultra_hwd_reset, 01156 .set_overflow = _ultra_hwd_set_overflow, 01157 /* .set_profile */ 01158 /* .stop_profiling = _papi_hwd_stop_profiling, */ 01159 .ntv_enum_events = _ultra_hwd_ntv_enum_events, 01160 /* .ntv_name_to_code */ 01161 .ntv_code_to_name = _ultra_hwd_ntv_code_to_name, 01162 .ntv_code_to_descr = _ultra_hwd_ntv_code_to_descr, 01163 .ntv_code_to_bits = _ultra_hwd_ntv_code_to_bits, 01164 .init_component = _ultra_hwd_init_component, 01165 .dispatch_timer = _ultra_hwd_dispatch_timer, 01166 01167 }; 01168 01169 papi_os_vector_t _papi_os_vector = { 01170 01171 /* OS dependent local routines */ 01172 .get_memory_info = _solaris_get_memory_info, 01173 .get_dmem_info = _solaris_get_dmem_info, 01174 .update_shlib_info = _solaris_update_shlib_info, 01175 .get_system_info = _solaris_get_system_info, 01176 .get_real_usec = _solaris_get_real_usec, 01177 .get_real_cycles = _solaris_get_real_cycles, 01178 .get_virt_usec = _solaris_get_virt_usec, 01179 };