FreeBSD/sys/dev/hwpmc/hwpmc_mod.c
/*
 * Interrupt processing.
 *
 * Find a free slot in the per-cpu array of samples and capture the
 * current callchain there.  If a sample was successfully added, a bit
 * is set in mask 'pmc_cpumask' denoting that the DO_SAMPLES hook
 * needs to be invoked from the clock handler.
 *
 * This function is meant to be called from an NMI handler.  It cannot
 * use any of the locking primitives supplied by the OS.
 */
Interrupt processing.
Find a free slot in the per-cpu array of samples and capture the
current callchain there.  If a sample was successfully added, a bit
is set in mask 'pmc_cpumask' denoting that the DO_SAMPLES hook
needs to be invoked from the clock handler.

This function is meant to be called from an NMI handler.  It cannot
use any of the locking primitives supplied by the OS.
Interrupt processing . Find a free slot in the per - cpu array of samples and capture the current callchain there . If a sample was successfully added a bit is set in mask ' pmc_cpumask ' denoting that the DO_SAMPLES hook needs to be invoked from the clock handler . This function is meant to be called from an NMI handler . It cannot use any of the locking primitives supplied by the OS .
int
pmc_process_interrupt(int cpu, int ring, struct pmc *pm, struct trapframe *tf,
    int inuserspace)
{
	int error, callchaindepth;
	struct thread *td;
	struct pmc_sample *ps;
	struct pmc_samplebuffer *psb;
	error = 0;
	psb = pmc_pcpu[cpu]->pc_sb[ring];
	ps = psb->ps_write;
	if (ps->ps_nsamples) {	
		CPU_SET_ATOMIC(cpu, &pm->pm_stalled);
		atomic_add_int(&pmc_stats.pm_intr_bufferfull, 1);
		PMCDBG6(SAM,INT,1,"(spc) cpu=%d pm=%p tf=%p um=%d wr=%d rd=%d",
		    cpu, pm, (void *) tf, inuserspace,
		    (int) (psb->ps_write - psb->ps_samples),
		    (int) (psb->ps_read - psb->ps_samples));
		callchaindepth = 1;
		error = ENOMEM;
		goto done;
	}
	PMCDBG6(SAM,INT,1,"cpu=%d pm=%p tf=%p um=%d wr=%d rd=%d", cpu, pm,
	    (void *) tf, inuserspace,
	    (int) (psb->ps_write - psb->ps_samples),
	    (int) (psb->ps_read - psb->ps_samples));
	KASSERT(pm->pm_runcount >= 0,
	    ("[pmc,%d] pm=%p runcount %d", __LINE__, (void *) pm,
		pm->pm_runcount));
	atomic_add_rel_int(&pm->pm_runcount, 1);	
	ps->ps_pmc = pm;
	if ((td = curthread) && td->td_proc)
		ps->ps_pid = td->td_proc->p_pid;
	else
		ps->ps_pid = -1;
	ps->ps_cpu = cpu;
	ps->ps_td = td;
	ps->ps_flags = inuserspace ? PMC_CC_F_USERSPACE : 0;
	callchaindepth = (pm->pm_flags & PMC_F_CALLCHAIN) ?
	    pmc_callchaindepth : 1;
	if (callchaindepth == 1)
		ps->ps_pc[0] = PMC_TRAPFRAME_TO_PC(tf);
	else {
		if (!inuserspace) {
			callchaindepth =
			    pmc_save_kernel_callchain(ps->ps_pc,
				callchaindepth, tf);
		} else {
			pmc_post_callchain_callback();
			callchaindepth = PMC_SAMPLE_INUSE;
		}
	}
	ps->ps_nsamples = callchaindepth;	
	ps++;
	if (ps == psb->ps_fence)
		psb->ps_write = psb->ps_samples;
	else
		psb->ps_write = ps;
 done:
	if (callchaindepth != PMC_SAMPLE_INUSE)
		CPU_SET_ATOMIC(cpu, &pmc_cpumask);
	return (error);
}
int pmc_process_interrupt ( int cpu , int ring , struct pmc * pm , struct trapframe * tf , int inuserspace ) { int error , callchaindepth ; struct thread * td ; struct pmc_sample * ps ; struct pmc_samplebuffer * psb ; error = 0 ; psb = pmc_pcpu [ cpu ] -> pc_sb [ ring ] ; ps = psb -> ps_write ; if ( ps -> ps_nsamples ) { CPU_SET_ATOMIC ( cpu , & pm -> pm_stalled ) ; atomic_add_int ( & pmc_stats . pm_intr_bufferfull , 1 ) ; PMCDBG6 ( SAM , INT , 1 , " " , cpu , pm , ( void * ) tf , inuserspace , ( int ) ( psb -> ps_write - psb -> ps_samples ) , ( int ) ( psb -> ps_read - psb -> ps_samples ) ) ; callchaindepth = 1 ; error = ENOMEM ; goto done ; } PMCDBG6 ( SAM , INT , 1 , " " , cpu , pm , ( void * ) tf , inuserspace , ( int ) ( psb -> ps_write - psb -> ps_samples ) , ( int ) ( psb -> ps_read - psb -> ps_samples ) ) ; KASSERT ( pm -> pm_runcount >= 0 , ( " " , __LINE__ , ( void * ) pm , pm -> pm_runcount ) ) ; atomic_add_rel_int ( & pm -> pm_runcount , 1 ) ; ps -> ps_pmc = pm ; if ( ( td = curthread ) && td -> td_proc ) ps -> ps_pid = td -> td_proc -> p_pid ; else ps -> ps_pid = -1 ; ps -> ps_cpu = cpu ; ps -> ps_td = td ; ps -> ps_flags = inuserspace ? PMC_CC_F_USERSPACE : 0 ; callchaindepth = ( pm -> pm_flags & PMC_F_CALLCHAIN ) ? pmc_callchaindepth : 1 ; if ( callchaindepth == 1 ) ps -> ps_pc [ 0 ] = PMC_TRAPFRAME_TO_PC ( tf ) ; else { if ( ! inuserspace ) { callchaindepth = pmc_save_kernel_callchain ( ps -> ps_pc , callchaindepth , tf ) ; } else { pmc_post_callchain_callback ( ) ; callchaindepth = PMC_SAMPLE_INUSE ; } } ps -> ps_nsamples = callchaindepth ; ps ++ ; if ( ps == psb -> ps_fence ) psb -> ps_write = psb -> ps_samples ; else psb -> ps_write = ps ; done : if ( callchaindepth != PMC_SAMPLE_INUSE ) CPU_SET_ATOMIC ( cpu , & pmc_cpumask ) ; return ( error ) ; }
Interrupt processing.
Interrupt processing .
/*
	 * Allocate space for a sample buffer.
	 */ /* in use, reader hasn't caught up */ /* Fill in entry. */ /* hold onto PMC */ /*
		 * Kernel stack traversals can be done immediately,
		 * while we defer to an AST for user space traversals.
		 */ /* mark entry as in use */ /* increment write pointer, modulo ring buffer size */ /* mark CPU as needing processing */