static inline void vperfctr_handle_overflow(struct task_struct *tsk, struct vperfctr *perfctr) { unsigned int pmc_mask; siginfo_t si; sigset_t old_blocked; pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state); if (!pmc_mask) { printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n", __FUNCTION__, tsk->pid); return; } /* suspend a-mode and i-mode PMCs, leaving only TSC on */ /* XXX: some people also want to suspend the TSC */ // we are storing 'cpu_state.cstatus' in 'iresume_cstatus' because // in vperfctr_resume, we only want to read the status of those // In the following TSC is resumed and continues to collect the // stats // if 'perfctr->iresume_cstatus' is not updated below, vperfctr_iresume() fails // as it thinks it was spuriously called inspite of absence of i-mode counters. // vperfctr_iresume() -> ... -> do_vperfctr_iresume() is a different thread of // execution from vperfctr_resume() -> ... -> vperfctr_iresume() -> __write_control() -> // ... perfctr->iresume_cstatus = perfctr->cpu_state.cstatus; if (perfctr_cstatus_has_tsc(perfctr->iresume_cstatus)) { perfctr->cpu_state.cstatus = perfctr_mk_cstatus(1, 0, 0); vperfctr_resume(perfctr); } else { perfctr->cpu_state.cstatus = 0; } // the following siginfo_t structure helps the kernel in invoking // the correct signal handler. Is that right ? // what's the deal with si_errno? what does it say ? si_code ? si.si_signo = perfctr->si_signo; si.si_errno = 0; si.si_code = SI_PMC_OVF; si.si_pmc_ovf_mask = pmc_mask; /* deliver signal without waking up the receiver */ spin_lock_irq(&tsk->sighand->siglock); old_blocked = tsk->blocked; sigaddset(&tsk->blocked, si.si_signo); spin_unlock_irq(&tsk->sighand->siglock); if (!send_sig_info(si.si_signo, &si, tsk)) { send_sig(si.si_signo, tsk, 1); } spin_lock_irq(&tsk->sighand->siglock); tsk->blocked = old_blocked; recalc_sigpending(); spin_unlock_irq(&tsk->sighand->siglock); }
static void vperfctr_handle_overflow(struct task_struct *tsk, struct vperfctr *perfctr) { unsigned int pmc_mask; siginfo_t si; sigset_t old_blocked; pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state); if (!pmc_mask) { #ifdef CONFIG_PPC64 /* On some hardware (ppc64, in particular) it's * impossible to control interrupts finely enough to * eliminate overflows on counters we don't care * about. So in this case just restart the counters * and keep going. */ vperfctr_resume(perfctr); #else printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n", __FUNCTION__, tsk->id); #endif return; } perfctr->ireload_needed = 1; /* suspend a-mode and i-mode PMCs, leaving only TSC on */ /* XXX: some people also want to suspend the TSC */ perfctr->resume_cstatus = perfctr->cpu_state.user.cstatus; if (perfctr_cstatus_has_tsc(perfctr->resume_cstatus)) { perfctr->cpu_state.user.cstatus = perfctr_mk_cstatus(1, 0, 0); vperfctr_resume(perfctr); } else perfctr->cpu_state.user.cstatus = 0; si.si_signo = perfctr->si_signo; si.si_errno = 0; si.si_code = SI_PMC_OVF; si.si_pmc_ovf_mask = pmc_mask; /* deliver signal without waking up the receiver */ spin_lock_irq(&tsk->sighand->siglock); old_blocked = tsk->blocked; sigaddset(&tsk->blocked, si.si_signo); spin_unlock_irq(&tsk->sighand->siglock); if (!send_sig_info(si.si_signo, &si, tsk)) send_sig(si.si_signo, tsk, 1); spin_lock_irq(&tsk->sighand->siglock); tsk->blocked = old_blocked; recalc_sigpending(); spin_unlock_irq(&tsk->sighand->siglock); }
static void vperfctr_handle_overflow(struct task_struct *tsk, struct vperfctr *perfctr) { unsigned int pmc_mask; siginfo_t si; sigset_t old_blocked; pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state); if (!pmc_mask) { printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n", __FUNCTION__, tsk->pid); return; } /* suspend a-mode and i-mode PMCs, leaving only TSC on */ /* XXX: some people also want to suspend the TSC */ perfctr->iresume_cstatus = perfctr->cpu_state.cstatus; if (perfctr_cstatus_has_tsc(perfctr->iresume_cstatus)) { perfctr->cpu_state.cstatus = perfctr_mk_cstatus(1, 0, 0); vperfctr_resume(perfctr); } else perfctr->cpu_state.cstatus = 0; si.si_signo = perfctr->si_signo; si.si_errno = 0; si.si_code = SI_PMC_OVF; si.si_pmc_ovf_mask = pmc_mask; /* deliver signal without waking up the receiver */ spin_lock_irq(&task_siglock(tsk)); old_blocked = tsk->blocked; sigaddset(&tsk->blocked, si.si_signo); spin_unlock_irq(&task_siglock(tsk)); if (!send_sig_info(si.si_signo, &si, tsk)) send_sig(si.si_signo, tsk, 1); spin_lock_irq(&task_siglock(tsk)); tsk->blocked = old_blocked; recalc_sigpending(); spin_unlock_irq(&task_siglock(tsk)); }
int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global) { int err; // since we updated the control, we invalidate the cpu id in the state // so that we can force reload of control registers clear_isuspend_cpu(state); state->cstatus = 0; /* disallow i-mode counters if we cannot catch the interrupts */ if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT) && state->control.nrictrs) { return -EPERM; } err = check_ireset(state); if (err < 0) { return err; } err = check_control(state); /* may initialise state->cstatus */ if (err < 0) { return err; } // Ok, while the map values and the start values for i-mode counters // are updated in the above function check_control() and the following // function setup_imode_start_values(), the 'cstatus' values is set here // how do u ensure that all i-mode registers are specified beyond a-mode // registers state->cstatus |= perfctr_mk_cstatus(state->control.tsc_on, state->control.nractrs, state->control.nrictrs); setup_imode_start_values(state); return 0; }