FreeBSD/sys/dev/hwpmc/hwpmc_mod.c
/*
 * Capture a user call chain.  This function will be called from ast()
 * before control returns to userland and before the process gets
 * rescheduled.
 */
Capture a user call chain.  This function will be called from ast()
before control returns to userland and before the process gets
rescheduled.
Capture a user call chain . This function will be called from ast () before control returns to userland and before the process gets rescheduled .
static void
pmc_capture_user_callchain(int cpu, int ring, struct trapframe *tf)
{
	struct pmc *pm;
	struct thread *td;
	struct pmc_sample *ps, *ps_end;
	struct pmc_samplebuffer *psb;
#ifdef	INVARIANTS
	int ncallchains;
	int nfree;
#endif
	psb = pmc_pcpu[cpu]->pc_sb[ring];
	td = curthread;
	KASSERT(td->td_pflags & TDP_CALLCHAIN,
	    ("[pmc,%d] Retrieving callchain for thread that doesn't want it",
		__LINE__));
#ifdef	INVARIANTS
	ncallchains = 0;
	nfree = 0;
#endif
	ps = psb->ps_read;
	ps_end = psb->ps_write;
	do {
#ifdef	INVARIANTS
		if (ps->ps_pmc->pm_state != PMC_STATE_RUNNING)
			nfree++;
#endif
		if (ps->ps_nsamples != PMC_SAMPLE_INUSE)
			goto next;
		if (ps->ps_td != td)
			goto next;
		KASSERT(ps->ps_cpu == cpu,
		    ("[pmc,%d] cpu mismatch ps_cpu=%d pcpu=%d", __LINE__,
			ps->ps_cpu, PCPU_GET(cpuid)));
		pm = ps->ps_pmc;
		KASSERT(pm->pm_flags & PMC_F_CALLCHAIN,
		    ("[pmc,%d] Retrieving callchain for PMC that doesn't "
			"want it", __LINE__));
		KASSERT(pm->pm_runcount > 0,
		    ("[pmc,%d] runcount %d", __LINE__, pm->pm_runcount));
		ps->ps_nsamples = pmc_save_user_callchain(ps->ps_pc,
		    pmc_callchaindepth, tf);
#ifdef	INVARIANTS
		ncallchains++;
#endif
next:
		if (++ps == psb->ps_fence)
			ps = psb->ps_samples;
	} while (ps != ps_end);
	KASSERT(ncallchains > 0 || nfree > 0,
	    ("[pmc,%d] cpu %d didn't find a sample to collect", __LINE__,
		cpu));
	KASSERT(td->td_pinned == 1,
	    ("[pmc,%d] invalid td_pinned value", __LINE__));
	sched_unpin();	
	CPU_SET_ATOMIC(cpu, &pmc_cpumask);
	return;
}
static void pmc_capture_user_callchain ( int cpu , int ring , struct trapframe * tf ) { struct pmc * pm ; struct thread * td ; struct pmc_sample * ps , * ps_end ; struct pmc_samplebuffer * psb ; #ifdef INVARIANTS int ncallchains ; int nfree ; #endif psb = pmc_pcpu [ cpu ] -> pc_sb [ ring ] ; td = curthread ; KASSERT ( td -> td_pflags & TDP_CALLCHAIN , ( " " , __LINE__ ) ) ; #ifdef INVARIANTS ncallchains = 0 ; nfree = 0 ; #endif ps = psb -> ps_read ; ps_end = psb -> ps_write ; do { #ifdef INVARIANTS if ( ps -> ps_pmc -> pm_state != PMC_STATE_RUNNING ) nfree ++ ; #endif if ( ps -> ps_nsamples != PMC_SAMPLE_INUSE ) goto next ; if ( ps -> ps_td != td ) goto next ; KASSERT ( ps -> ps_cpu == cpu , ( " " , __LINE__ , ps -> ps_cpu , PCPU_GET ( cpuid ) ) ) ; pm = ps -> ps_pmc ; KASSERT ( pm -> pm_flags & PMC_F_CALLCHAIN , ( " " " " , __LINE__ ) ) ; KASSERT ( pm -> pm_runcount > 0 , ( " " , __LINE__ , pm -> pm_runcount ) ) ; ps -> ps_nsamples = pmc_save_user_callchain ( ps -> ps_pc , pmc_callchaindepth , tf ) ; #ifdef INVARIANTS ncallchains ++ ; #endif next : if ( ++ ps == psb -> ps_fence ) ps = psb -> ps_samples ; } while ( ps != ps_end ) ; KASSERT ( ncallchains > 0 || nfree > 0 , ( " " , __LINE__ , cpu ) ) ; KASSERT ( td -> td_pinned == 1 , ( " " , __LINE__ ) ) ; sched_unpin ( ) ; CPU_SET_ATOMIC ( cpu , & pmc_cpumask ) ; return ; }
Capture a user call chain.
Capture a user call chain .
/*
	 * Iterate through all deferred callchain requests.
	 * Walk from the current read pointer to the current
	 * write pointer.
	 */ /*
		 * Retrieve the callchain and mark the sample buffer
		 * as 'processable' by the timer tick sweep code.
		 */ /* increment the pointer, modulo sample ring size */ /* Can migrate safely now. */ /* mark CPU as needing processing */