int _papi_hwd_set_overflow( EventSetInfo_t * ESI, int EventIndex, int threshold ) { hwd_control_state_t *this_state = &ESI->machdep; struct hwd_pmc_control *contr = &this_state->control; int i, ncntrs, nricntrs = 0, nracntrs = 0, retval = 0; OVFDBG( "EventIndex=%d, threshold = %d\n", EventIndex, threshold ); /* The correct event to overflow is EventIndex */ ncntrs = _papi_hwi_system_info.sub_info.num_cntrs; i = ESI->EventInfoArray[EventIndex].pos[0]; if ( i >= ncntrs ) { OVFDBG( "Selector id (%d) larger than ncntrs (%d)\n", i, ncntrs ); return PAPI_EINVAL; } if ( threshold != 0 ) { /* Set an overflow threshold */ if ( ESI->EventInfoArray[EventIndex].derived ) { OVFDBG( "Can't overflow on a derived event.\n" ); return PAPI_EINVAL; } if ( ( retval = _papi_hwi_start_signal( _papi_hwi_system_info.sub_info. hardware_intr_sig, NEED_CONTEXT ) ) != PAPI_OK ) return ( retval ); contr->cpu_control.ireset[i] = PMC_OVFL - threshold; nricntrs = ++contr->cpu_control.nrictrs; nracntrs = --contr->cpu_control.nractrs; contr->si_signo = _papi_hwi_system_info.sub_info.hardware_intr_sig; contr->cpu_control.ppc64.mmcr0 |= PERF_INT_ENABLE; /* move this event to the bottom part of the list if needed */ if ( i < nracntrs ) swap_events( ESI, contr, i, nracntrs ); OVFDBG( "Modified event set\n" ); } else { if ( contr->cpu_control.ppc64.mmcr0 & PERF_INT_ENABLE ) { contr->cpu_control.ireset[i] = 0; nricntrs = --contr->cpu_control.nrictrs; nracntrs = ++contr->cpu_control.nractrs; if ( !nricntrs ) contr->cpu_control.ppc64.mmcr0 &= ( ~PERF_INT_ENABLE ); } /* move this event to the top part of the list if needed */ if ( i >= nracntrs ) swap_events( ESI, contr, i, nracntrs - 1 ); if ( !nricntrs ) contr->si_signo = 0; OVFDBG( "Modified event set\n" ); retval = _papi_hwi_stop_signal( _papi_hwi_system_info.sub_info. hardware_intr_sig ); } #ifdef DEBUG print_control( &contr->cpu_control ); #endif OVFDBG( "%s:%d: Hardware overflow is still experimental.\n", __FILE__, __LINE__ ); OVFDBG( "End of call. Exit code: %d\n", retval ); return ( retval ); }
static void dispatch_emt( int signal, siginfo_t * sip, void *arg ) { int event_counter; _papi_hwi_context_t ctx; caddr_t address; ctx.si = sip; ctx.ucontext = arg; SUBDBG( "%d, %p, %p\n", signal, sip, arg ); if ( sip->si_code == EMT_CPCOVF ) { papi_cpc_event_t *sample; EventSetInfo_t *ESI; ThreadInfo_t *thread = NULL; int t, overflow_vector, readvalue; thread = _papi_hwi_lookup_thread( 0 ); ESI = ( EventSetInfo_t * ) thread->running_eventset; int cidx = ESI->CmpIdx; if ( ( ESI == NULL ) || ( ( ESI->state & PAPI_OVERFLOWING ) == 0 ) ) { OVFDBG( "Either no eventset or eventset not set to overflow.\n" ); return; } if ( ESI->master != thread ) { PAPIERROR ( "eventset->thread 0x%lx vs. current thread 0x%lx mismatch", ESI->master, thread ); return; } event_counter = ESI->overflow.event_counter; sample = &( ESI->ctl_state->counter_cmd ); /* GROSS! This is a hack to 'push' the correct values back into the hardware, such that when PAPI handles the overflow and reads the values, it gets the correct ones. */ /* Find which HW counter overflowed */ if ( ESI->EventInfoArray[ESI->overflow.EventIndex[0]].pos[0] == 0 ) t = 0; else t = 1; if ( cpc_take_sample( &sample->cmd ) == -1 ) return; if ( event_counter == 1 ) { /* only one event is set to be the overflow monitor */ /* generate the overflow vector */ overflow_vector = 1 << t; /* reset the threshold */ sample->cmd.ce_pic[t] = UINT64_MAX - ESI->overflow.threshold[0]; } else { /* two events are set to be the overflow monitors */ overflow_vector = 0; readvalue = sample->cmd.ce_pic[0]; if ( readvalue >= 0 ) { /* the first counter overflowed */ /* generate the overflow vector */ overflow_vector = 1; /* reset the threshold */ if ( t == 0 ) sample->cmd.ce_pic[0] = UINT64_MAX - ESI->overflow.threshold[0]; else sample->cmd.ce_pic[0] = UINT64_MAX - ESI->overflow.threshold[1]; } readvalue = sample->cmd.ce_pic[1]; if ( readvalue >= 0 ) { /* the second counter overflowed */ /* generate the overflow vector */ overflow_vector ^= 1 << 1; /* reset the threshold */ if ( t == 0 ) sample->cmd.ce_pic[1] = UINT64_MAX - ESI->overflow.threshold[1]; else sample->cmd.ce_pic[1] = UINT64_MAX - ESI->overflow.threshold[0]; } SUBDBG( "overflow_vector, = %d\n", overflow_vector ); /* something is wrong here */ if ( overflow_vector == 0 ) { PAPIERROR( "BUG! overflow_vector is 0, dropping interrupt" ); return; } } /* Call the regular overflow function in extras.c */ if ( thread->running_eventset[cidx]->overflow. flags & PAPI_OVERFLOW_FORCE_SW ) { address = GET_OVERFLOW_ADDRESS(ctx); _papi_hwi_dispatch_overflow_signal( ( void * ) &ctx, address, NULL, overflow_vector, 0, &thread, cidx ); } else { PAPIERROR( "Additional implementation needed in dispatch_emt!" ); } #if DEBUG dump_cmd( sample ); #endif /* push back the correct values and start counting again */ if ( cpc_bind_event( &sample->cmd, sample->flags ) == -1 ) return; } else { SUBDBG( "dispatch_emt() dropped, si_code = %d\n", sip->si_code ); return; } }
static int _x86_set_overflow( EventSetInfo_t * ESI, int EventIndex, int threshold ) { struct hwd_pmc_control *contr = &ESI->ctl_state->control; int i, ncntrs, nricntrs = 0, nracntrs = 0, retval = 0; OVFDBG( "EventIndex=%d\n", EventIndex ); #ifdef DEBUG if ( is_pentium4() ) print_control( &ESI->ctl_state->control.cpu_control ); #endif /* The correct event to overflow is EventIndex */ ncntrs = MY_VECTOR.cmp_info.num_cntrs; i = ESI->EventInfoArray[EventIndex].pos[0]; if ( i >= ncntrs ) { PAPIERROR( "Selector id %d is larger than ncntrs %d", i, ncntrs ); return PAPI_EINVAL; } if ( threshold != 0 ) { /* Set an overflow threshold */ retval = _papi_hwi_start_signal( MY_VECTOR.cmp_info.hardware_intr_sig, NEED_CONTEXT, MY_VECTOR.cmp_info.CmpIdx ); if ( retval != PAPI_OK ) return ( retval ); /* overflow interrupt occurs on the NEXT event after overflow occurs thus we subtract 1 from the threshold. */ contr->cpu_control.ireset[i] = ( -threshold + 1 ); if ( is_pentium4() ) contr->cpu_control.evntsel[i] |= CCCR_OVF_PMI_T0; else contr->cpu_control.evntsel[i] |= PERF_INT_ENABLE; contr->cpu_control.nrictrs++; contr->cpu_control.nractrs--; nricntrs = ( int ) contr->cpu_control.nrictrs; nracntrs = ( int ) contr->cpu_control.nractrs; contr->si_signo = MY_VECTOR.cmp_info.hardware_intr_sig; /* move this event to the bottom part of the list if needed */ if ( i < nracntrs ) swap_events( ESI, contr, i, nracntrs ); OVFDBG( "Modified event set\n" ); } else { if ( is_pentium4() && contr->cpu_control.evntsel[i] & CCCR_OVF_PMI_T0 ) { contr->cpu_control.ireset[i] = 0; contr->cpu_control.evntsel[i] &= ( ~CCCR_OVF_PMI_T0 ); contr->cpu_control.nrictrs--; contr->cpu_control.nractrs++; } else if ( !is_pentium4() && contr->cpu_control.evntsel[i] & PERF_INT_ENABLE ) { contr->cpu_control.ireset[i] = 0; contr->cpu_control.evntsel[i] &= ( ~PERF_INT_ENABLE ); contr->cpu_control.nrictrs--; contr->cpu_control.nractrs++; } nricntrs = ( int ) contr->cpu_control.nrictrs; nracntrs = ( int ) contr->cpu_control.nractrs; /* move this event to the top part of the list if needed */ if ( i >= nracntrs ) swap_events( ESI, contr, i, nracntrs - 1 ); if ( !nricntrs ) contr->si_signo = 0; OVFDBG( "Modified event set\n" ); retval = _papi_hwi_stop_signal( MY_VECTOR.cmp_info.hardware_intr_sig ); } #ifdef DEBUG if ( is_pentium4() ) print_control( &ESI->ctl_state->control.cpu_control ); #endif OVFDBG( "End of call. Exit code: %d\n", retval ); return ( retval ); }