PAPI  5.0.1.0
solaris-ultra.c
Go to the documentation of this file.
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 };
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines