inline void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
{
    unsigned int i, cstatus, nractrs;
    struct perfctr_low_ctrs now;
	int   cpu_id;

	cpu_id = hard_smp_processor_id() / 4;
	spin_lock (&pmc_resource[cpu_id].lock);
	if ( pmc_resource[cpu_id].current_thread != netlogic_thr_id() ) {
		// printk (KERN_INFO "PMCounters do not belong to this process[%d]\n", current->pid);
		spin_unlock (&pmc_resource[cpu_id].lock);
		return;
	}
	pmc_resource[cpu_id].current_thread = -1;
	spin_unlock (&pmc_resource[cpu_id].lock);

    // To prevent polluting the numbers, can we freeze the counters
    // here, as early as possible ?

    if (perfctr_cstatus_has_ictrs(state->cstatus)) {
        perfctr_cpu_isuspend(state);
	}
    perfctr_cpu_read_counters(state, &now);
    cstatus = state->cstatus;
    if (perfctr_cstatus_has_tsc(cstatus)) {
        state->tsc_sum += now.tsc - state->tsc_start;
    }
    nractrs = perfctr_cstatus_nractrs(cstatus);
    for(i = 0; i < nractrs; ++i) {
        state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
    }
}
Example #2
0
static int sys_vperfctr_iresume(struct vperfctr *perfctr, const struct task_struct *tsk)
{
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
	unsigned int iresume_cstatus;

	if (!tsk)
		return -ESRCH;	/* attempt to update unlinked perfctr */

	iresume_cstatus = perfctr->iresume_cstatus;
	if (!perfctr_cstatus_has_ictrs(iresume_cstatus))
		return -EPERM;

	/* PREEMPT note: preemption is disabled over the entire
	   region because we're updating an active perfctr. */
	preempt_disable();

	if (IS_RUNNING(perfctr) && tsk == current)
		vperfctr_suspend(perfctr);

	perfctr->cpu_state.cstatus = iresume_cstatus;
	perfctr->iresume_cstatus = 0;

	/* remote access note: perfctr_cpu_ireload() is ok */
	perfctr_cpu_ireload(&perfctr->cpu_state);

	if (tsk == current)
		vperfctr_resume(perfctr);

	preempt_enable();

	return 0;
#else
	return -ENOSYS;
#endif
}
static int do_vperfctr_iresume(struct vperfctr *perfctr, const struct task_struct *tsk)
{
#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT
	unsigned int iresume_cstatus;

	if (!tsk)
		return -ESRCH;	/* attempt to update unlinked perfctr */

	iresume_cstatus = perfctr->iresume_cstatus;
	if (!perfctr_cstatus_has_ictrs(iresume_cstatus)) {
		return -EPERM;
	}

	/* PREEMPT note: preemption is disabled over the entire
	   region because we're updating an active perfctr. */
	preempt_disable();

	// this is for resuming a task whose signal was handled prior to this call
	// are the i-mode counters frozen before the overflow-signal is delivered
	// yes, they are. in the suspend call invoked in the handler

	// why exactly are we suspending the following? Makes sense ... if the
	// counters are already running, then one should not just resume the task
	// which will overwrite the PMC registers with old values. Nice. Under
	// what condition do counters continue to count after the signal is delivered
	// remember TSC was not suspend in the handler and continues to count

	if (IS_RUNNING(perfctr) && tsk == current)
		vperfctr_suspend(perfctr);

	// setting the cstatus of 'cpu_state' back to what it was prior to its
	// zeroing out in the interrupt handler
	perfctr->cpu_state.cstatus = iresume_cstatus;
	perfctr->iresume_cstatus = 0;

	/* remote access note: perfctr_cpu_ireload() is ok */
	// the following forces the reload of control registers that 
	// unfreezes the i-mode registers
	perfctr_cpu_ireload(&perfctr->cpu_state);

	if (tsk == current)
		vperfctr_resume(perfctr);

	preempt_enable();

	return 0;
#else
	return -ENOSYS;
#endif
}
inline void perfctr_cpu_resume(struct perfctr_cpu_state *state)
{
	int   cpu_id;

	cpu_id = hard_smp_processor_id() / 4;
	spin_lock (&pmc_resource[cpu_id].lock);
	if ( pmc_resource[cpu_id].current_thread != -1 ) {
		// printk (KERN_INFO "PMCounters unavailable for process %d\n", current->pid);
		spin_unlock (&pmc_resource[cpu_id].lock);
		return;
	}
	pmc_resource[cpu_id].current_thread = netlogic_thr_id();
	spin_unlock (&pmc_resource[cpu_id].lock);

    if (perfctr_cstatus_has_ictrs(state->cstatus)) {
        perfctr_cpu_iresume(state);
	}

    // the counters are triggered, having been frozen in _iresume()
    // that preceded this point. So, the model is to trigger the
    // registere to collect the numbers and record the start state
    // that completes the 'resume' process.

    perfctr_cpu_write_control(state);
    {
        struct perfctr_low_ctrs now;
        unsigned int i, cstatus, nrctrs;
        perfctr_cpu_read_counters(state, &now);
        cstatus = state->cstatus;

        // the start state of the registers has to be recorded only
        // in resume() and that is what is being done.

        if (perfctr_cstatus_has_tsc(cstatus)) {
            state->tsc_start = now.tsc;
		}
        nrctrs = perfctr_cstatus_nractrs(cstatus);
        for (i = 0; i < nrctrs; ++i) {
            state->pmc[i].start = now.pmc[i];
		}
    }
    /* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
}
Example #5
0
/* PREEMPT note: called in IRQ context with preemption disabled. */
static void vperfctr_ihandler(unsigned long pc)
{
	struct task_struct *tsk = current;
	struct vperfctr *perfctr;

	perfctr = tsk->arch.thread.perfctr;
	if (!perfctr) {
		printk(KERN_ERR "%s: BUG! pid %d has no vperfctr\n",
		       __FUNCTION__, tsk->id);
		return;
	}
	if (!perfctr_cstatus_has_ictrs(perfctr->cpu_state.user.cstatus)) {
		printk(KERN_ERR "%s: BUG! vperfctr has cstatus %#x (pid %d, comm %s)\n",
		       __FUNCTION__, perfctr->cpu_state.user.cstatus, tsk->id, tsk->comm);
		return;
	}
	vperfctr_suspend(perfctr);
	vperfctr_handle_overflow(tsk, perfctr);
}
// PREEMPT note: called in IRQ context with preemption disabled.
static void vperfctr_ihandler(unsigned long pc)
{
	struct task_struct *tsk = current;
	struct vperfctr *perfctr;
	unsigned int pmc, cstatus, now = 0;
	int i;

	perfctr = tsk->thread.perfctr;
	if (!perfctr) {
		return;
	}
	if (!perfctr_cstatus_has_ictrs(perfctr->cpu_state.cstatus)) {
		return;
	}

	// if someone has really overflown then continue else return
	// just read, don't freeze them
	
	cstatus = perfctr->cpu_state.cstatus;
	for (i = perfctr_cstatus_nractrs(cstatus); (i < perfctr_cstatus_nrctrs(cstatus)) && ((int)now >= 0); ++i) {
		pmc = perfctr->cpu_state.pmc[i].map;
		now = read_pmc(pmc);
	}
	if ((int)now >= 0) {
		return;
	}

	// Fine, we are suspending the counters and reading them. vperfctr_suspend() 
	// in turn invokes _suspend() on i-mode ctrs (where they are frozen and read) 
	// and a-mode counters (where they are just read)

	vperfctr_suspend(perfctr);

	// Ok, Signal to the userland is sent in the following routine. But before that
	// the following routine calls vperfctr_resume() if the TSC counting is on.
	// what happens in that resume is just the TSC value is read and stored in the
	// 'start' state of the TSC

	vperfctr_handle_overflow(tsk, perfctr);
}