diff options
-rw-r--r-- | sys/dev/hwpmc/hwpmc_amd.c | 27 | ||||
-rw-r--r-- | sys/dev/hwpmc/hwpmc_mod.c | 31 | ||||
-rw-r--r-- | sys/dev/hwpmc/hwpmc_piv.c | 28 | ||||
-rw-r--r-- | sys/dev/hwpmc/hwpmc_ppro.c | 13 | ||||
-rw-r--r-- | sys/i386/include/pmc_mdep.h | 3 | ||||
-rw-r--r-- | sys/sys/pmc.h | 16 |
6 files changed, 89 insertions, 29 deletions
diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c index a78943a..158dc0b 100644 --- a/sys/dev/hwpmc/hwpmc_amd.c +++ b/sys/dev/hwpmc/hwpmc_amd.c @@ -443,6 +443,8 @@ amd_config_pmc(int cpu, int ri, struct pmc *pm) { struct pmc_hw *phw; + PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); + KASSERT(cpu >= 0 && cpu < mp_ncpus, ("[amd,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < AMD_NPMCS, @@ -451,7 +453,8 @@ amd_config_pmc(int cpu, int ri, struct pmc *pm) phw = pmc_pcpu[cpu]->pc_hwpmcs[ri]; KASSERT(pm == NULL || phw->phw_pmc == NULL, - ("[amd,%d] hwpmc not unconfigured before re-config", __LINE__)); + ("[amd,%d] pm=%p phw->pm=%p hwpmc not unconfigured", + __LINE__, pm, phw->phw_pmc)); phw->phw_pmc = pm; return 0; @@ -463,12 +466,17 @@ amd_config_pmc(int cpu, int ri, struct pmc *pm) */ static int -amd_switch_in(struct pmc_cpu *pc) +amd_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) { (void) pc; - /* enable the RDPMC instruction */ - load_cr4(rcr4() | CR4_PCE); + PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp, + (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0); + + /* enable the RDPMC instruction if needed */ + if (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) + load_cr4(rcr4() | CR4_PCE); + return 0; } @@ -478,12 +486,17 @@ amd_switch_in(struct pmc_cpu *pc) */ static int -amd_switch_out(struct pmc_cpu *pc) +amd_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) { (void) pc; + (void) pp; /* can be NULL */ - /* disallow RDPMC instruction */ + PMCDBG(MDP,SWO,1, "pc=%p pp=%p enable-msr=%d", pc, pp, pp ? + (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) == 1 : 0); + + /* always turn off the RDPMC instruction */ load_cr4(rcr4() & ~CR4_PCE); + return 0; } @@ -818,7 +831,7 @@ amd_get_msr(int ri, uint32_t *msr) KASSERT(ri >= 0 && ri < AMD_NPMCS, ("[amd,%d] ri %d out of range", __LINE__, ri)); - *msr = amd_pmcdesc[ri].pm_perfctr; + *msr = amd_pmcdesc[ri].pm_perfctr - AMD_PMC_PERFCTR_0; return 0; } diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c index 3f5cbd7..00cf9fa 100644 --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -739,8 +739,13 @@ pmc_link_target_process(struct pmc *pm, struct pmc_process *pp) atomic_store_rel_ptr(&pp->pp_pmcs[ri].pp_pmc, pm); + if (pm->pm_owner->po_owner == pp->pp_proc) + pp->pp_flags |= PMC_FLAG_ENABLE_MSR_ACCESS; + pp->pp_refcnt++; + PMCDBG(PRC,TLK,2, "enable-msr %d", + (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0); } /* @@ -774,6 +779,9 @@ pmc_unlink_target_process(struct pmc *pm, struct pmc_process *pp) pp->pp_pmcs[ri].pp_pmc = NULL; pp->pp_pmcs[ri].pp_pmcval = (pmc_value_t) 0; + if (pm->pm_owner->po_owner == pp->pp_proc) + pp->pp_flags &= ~PMC_FLAG_ENABLE_MSR_ACCESS; + pp->pp_refcnt--; /* Remove the target process from the PMC structure */ @@ -784,7 +792,8 @@ pmc_unlink_target_process(struct pmc *pm, struct pmc_process *pp) KASSERT(ptgt != NULL, ("[pmc,%d] process %p (pp: %p) not found " "in pmc %p", __LINE__, pp->pp_proc, pp, pm)); - PMCDBG(PRC,TUL,4, "unlink ptgt=%p", ptgt); + PMCDBG(PRC,TUL,4, "unlink ptgt=%p, enable-msr=%d", ptgt, + (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0); LIST_REMOVE(ptgt, pt_next); FREE(ptgt, M_PMC); @@ -1159,10 +1168,10 @@ pmc_hook_handler(struct thread *td, int function, void *arg) "process-exit proc=%p pmc-process=%p", p, pp); /* - * This process could the target of some PMCs. - * Such PMCs will thus be running on currently - * executing CPU at this point in the code - * since we've disallowed context switches. + * The exiting process could the target of + * some PMCs which will be running on + * currently executing CPU. + * * We need to turn these PMCs off like we * would do at context switch OUT time. */ @@ -1219,6 +1228,14 @@ pmc_hook_handler(struct thread *td, int function, void *arg) atomic_subtract_rel_32(&pm->pm_runcount,1); (void) md->pmd_config_pmc(cpu, ri, NULL); } + + /* + * Inform the MD layer of this pseudo "context switch + * out" + */ + + (void) md->pmd_switch_out(pmc_pcpu[cpu], pp); + critical_exit(); /* ok to be pre-empted now */ /* @@ -1475,7 +1492,7 @@ pmc_hook_handler(struct thread *td, int function, void *arg) * switch-in actions. */ - (void) (*md->pmd_switch_in)(pc); + (void) (*md->pmd_switch_in)(pc, pp); critical_exit(); @@ -1614,7 +1631,7 @@ pmc_hook_handler(struct thread *td, int function, void *arg) * switch out functions. */ - (void) (*md->pmd_switch_out)(pc); + (void) (*md->pmd_switch_out)(pc, pp); critical_exit(); diff --git a/sys/dev/hwpmc/hwpmc_piv.c b/sys/dev/hwpmc/hwpmc_piv.c index de2ad70..67be026 100644 --- a/sys/dev/hwpmc/hwpmc_piv.c +++ b/sys/dev/hwpmc/hwpmc_piv.c @@ -578,11 +578,19 @@ p4_cleanup(int cpu) */ static int -p4_switch_in(struct pmc_cpu *pc) +p4_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) { (void) pc; + + PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp, + (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) != 0); + /* enable the RDPMC instruction */ - load_cr4(rcr4() | CR4_PCE); + if (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) + load_cr4(rcr4() | CR4_PCE); + + PMCDBG(MDP,SWI,2, "cr4=0x%x", rcr4()); + return 0; } @@ -591,11 +599,18 @@ p4_switch_in(struct pmc_cpu *pc) */ static int -p4_switch_out(struct pmc_cpu *pc) +p4_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) { (void) pc; - /* disallow RDPMC instruction */ + (void) pp; /* can be null */ + + PMCDBG(MDP,SWO,1, "pc=%p pp=%p", pc, pp); + + /* always disallow the RDPMC instruction */ load_cr4(rcr4() & ~CR4_PCE); + + PMCDBG(MDP,SWO,2, "cr4=0x%x", rcr4()); + return 0; } @@ -1419,7 +1434,10 @@ p4_get_msr(int ri, uint32_t *msr) KASSERT(ri >= 0 && ri < P4_NPMCS, ("[p4,%d] ri %d out of range", __LINE__, ri)); - *msr = p4_pmcdesc[ri].pm_pmc_msr; + *msr = p4_pmcdesc[ri].pm_pmc_msr - P4_PERFCTR_MSR_FIRST; + + PMCDBG(MDP,OPS, 1, "ri=%d getmsr=0x%x", ri, *msr); + return 0; } diff --git a/sys/dev/hwpmc/hwpmc_ppro.c b/sys/dev/hwpmc/hwpmc_ppro.c index c08c509..1bd19be6 100644 --- a/sys/dev/hwpmc/hwpmc_ppro.c +++ b/sys/dev/hwpmc/hwpmc_ppro.c @@ -332,16 +332,25 @@ p6_cleanup(int cpu) } static int -p6_switch_in(struct pmc_cpu *pc) +p6_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) { (void) pc; + + /* allow the RDPMC instruction if needed */ + if (pp->pp_flags & PMC_FLAG_ENABLE_MSR_ACCESS) + load_cr4(rcr4() | CR4_PCE); return 0; } static int -p6_switch_out(struct pmc_cpu *pc) +p6_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) { (void) pc; + (void) pp; /* can be NULL */ + + /* always turn off the RDPMC instruction */ + load_cr4(rcr4() & ~CR4_PCE); + return 0; } diff --git a/sys/i386/include/pmc_mdep.h b/sys/i386/include/pmc_mdep.h index 84f75d7..8b25e1e 100644 --- a/sys/i386/include/pmc_mdep.h +++ b/sys/i386/include/pmc_mdep.h @@ -123,6 +123,9 @@ #define P4_PERFCTR_MASK 0xFFFFFFFFFFLL /* 40 bits */ +#define P4_CCCR_MSR_FIRST 0x360 /* MSR_BPU_CCCR0 */ +#define P4_PERFCTR_MSR_FIRST 0x300 /* MSR_BPU_COUNTER0 */ + /* Intel PPro, Celeron, P-II, P-III, Pentium-M PMCS */ #define P6_NPMCS 3 /* 1 TSC + 2 PMCs */ diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h index b2a3479..76baa16 100644 --- a/sys/sys/pmc.h +++ b/sys/sys/pmc.h @@ -1158,6 +1158,7 @@ struct pmc_targetstate { struct pmc_process { LIST_ENTRY(pmc_process) pp_next; /* hash chain */ int pp_refcnt; /* reference count */ + uint32_t pp_flags; /* flags */ struct proc *pp_proc; /* target thread */ struct pmc_targetstate pp_pmcs[]; /* NHWPMCs */ }; @@ -1183,9 +1184,10 @@ struct pmc_owner { int po_logfd; /* XXX for now */ }; -#define PMC_FLAG_IS_OWNER 0x01 -#define PMC_FLAG_HAS_TS_PMC 0x02 -#define PMC_FLAG_OWNS_LOGFILE 0x04 /* owns system-sampling log file */ +#define PMC_FLAG_IS_OWNER 0x01 +#define PMC_FLAG_HAS_TS_PMC 0x02 +#define PMC_FLAG_OWNS_LOGFILE 0x04 +#define PMC_FLAG_ENABLE_MSR_ACCESS 0x08 /* * struct pmc_hw -- describe the state of the PMC hardware @@ -1283,11 +1285,9 @@ struct pmc_mdep { int (*pmd_init)(int _cpu); /* machine dependent initialization */ int (*pmd_cleanup)(int _cpu); /* machine dependent cleanup */ - /* thread context switch in */ - int (*pmd_switch_in)(struct pmc_cpu *_p); - - /* thread context switch out */ - int (*pmd_switch_out)(struct pmc_cpu *_p); + /* thread context switch in/out */ + int (*pmd_switch_in)(struct pmc_cpu *_p, struct pmc_process *_pp); + int (*pmd_switch_out)(struct pmc_cpu *_p, struct pmc_process *_pp); /* configuring/reading/writing the hardware PMCs */ int (*pmd_config_pmc)(int _cpu, int _ri, struct pmc *_pm); |