Improve accuracy of PMC sampling frequency
The code tracks a counter which is the number of events until the next sample. On context switch in, it loads the saved counter. On context switch out, it tries to calculate a new saved counter. Problems: 1. The saved counter was shared by all threads in a process. However, this means that all threads would be initially loaded with the same saved counter. However, that could result in sampling more often than once every X number of events. 2. The calculation to determine a new saved counter was backwards. It added when it should have subtracted, and subtracted when it should have added. Assume a single-threaded process with a reload count of 1000 events. Assuming the counter on context switch in was 100 and the counter on context switch out was 50 (meaning the thread has "consumed" 50 more events), the code would calculate a new saved counter of 150 (instead of the proper 50). Fix: 1. As soon as the saved counter is used to initialize a monitor for a thread on context switch in, set the saved counter to the reload count. That way, subsequent threads to use the saved counter will get the full reload count, assuring we sample at least once every X number of events (across all threads). 2. Change the calculation of the saved counter. Due to the change to the saved counter in #1, we simply need to add (modulo the reload count) the remaining counter time we retrieve from the CPU when a thread is context switched out. Differential Revision: https://reviews.freebsd.org/D4122 Approved by: gnn (mentor) MFC after: 1 month Sponsored by: Juniper Networks
This commit is contained in:
parent
327d3d0e64
commit
3fdce597b1
@ -1282,8 +1282,16 @@ pmc_process_csw_in(struct thread *td)
|
||||
*/
|
||||
if (PMC_TO_MODE(pm) == PMC_MODE_TS) {
|
||||
mtx_pool_lock_spin(pmc_mtxpool, pm);
|
||||
|
||||
/*
|
||||
* Use the saved value calculated after the most recent
|
||||
* thread switch out to start this counter. Reset
|
||||
* the saved count in case another thread from this
|
||||
* process switches in before any threads switch out.
|
||||
*/
|
||||
newvalue = PMC_PCPU_SAVED(cpu,ri) =
|
||||
pp->pp_pmcs[ri].pp_pmcval;
|
||||
pp->pp_pmcs[ri].pp_pmcval = pm->pm_sc.pm_reloadcount;
|
||||
mtx_pool_unlock_spin(pmc_mtxpool, pm);
|
||||
} else {
|
||||
KASSERT(PMC_TO_MODE(pm) == PMC_MODE_TC,
|
||||
@ -1431,31 +1439,43 @@ pmc_process_csw_out(struct thread *td)
|
||||
|
||||
pcd->pcd_read_pmc(cpu, adjri, &newvalue);
|
||||
|
||||
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri);
|
||||
|
||||
PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd", cpu, ri,
|
||||
tmp);
|
||||
|
||||
if (mode == PMC_MODE_TS) {
|
||||
PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (samp)",
|
||||
cpu, ri, PMC_PCPU_SAVED(cpu,ri) - newvalue);
|
||||
|
||||
/*
|
||||
* For sampling process-virtual PMCs,
|
||||
* we expect the count to be
|
||||
* decreasing as the 'value'
|
||||
* programmed into the PMC is the
|
||||
* number of events to be seen till
|
||||
* the next sampling interrupt.
|
||||
* newvalue is the number of events to be seen
|
||||
* until the next sampling interrupt.
|
||||
* We can just add the events left from this
|
||||
* invocation to the counter, then adjust
|
||||
* in case we overflow our range.
|
||||
*
|
||||
* (Recall that we reload the counter every
|
||||
* time we use it.)
|
||||
*/
|
||||
if (tmp < 0)
|
||||
tmp += pm->pm_sc.pm_reloadcount;
|
||||
mtx_pool_lock_spin(pmc_mtxpool, pm);
|
||||
pp->pp_pmcs[ri].pp_pmcval -= tmp;
|
||||
if ((int64_t) pp->pp_pmcs[ri].pp_pmcval <= 0)
|
||||
pp->pp_pmcs[ri].pp_pmcval +=
|
||||
|
||||
pp->pp_pmcs[ri].pp_pmcval += newvalue;
|
||||
if (pp->pp_pmcs[ri].pp_pmcval >
|
||||
pm->pm_sc.pm_reloadcount)
|
||||
pp->pp_pmcs[ri].pp_pmcval -=
|
||||
pm->pm_sc.pm_reloadcount;
|
||||
KASSERT(pp->pp_pmcs[ri].pp_pmcval > 0 &&
|
||||
pp->pp_pmcs[ri].pp_pmcval <=
|
||||
pm->pm_sc.pm_reloadcount,
|
||||
("[pmc,%d] pp_pmcval outside of expected "
|
||||
"range cpu=%d ri=%d pp_pmcval=%jx "
|
||||
"pm_reloadcount=%jx", __LINE__, cpu, ri,
|
||||
pp->pp_pmcs[ri].pp_pmcval,
|
||||
pm->pm_sc.pm_reloadcount));
|
||||
mtx_pool_unlock_spin(pmc_mtxpool, pm);
|
||||
|
||||
} else {
|
||||
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri);
|
||||
|
||||
PMCDBG3(CSW,SWO,1,"cpu=%d ri=%d tmp=%jd (count)",
|
||||
cpu, ri, tmp);
|
||||
|
||||
/*
|
||||
* For counting process-virtual PMCs,
|
||||
|
Loading…
Reference in New Issue
Block a user