summaryrefslogtreecommitdiffstats
path: root/sys/dev/hwpmc/hwpmc_mod.c
diff options
context:
space:
mode:
authorjkoshy <jkoshy@FreeBSD.org>2008-11-09 17:37:54 +0000
committerjkoshy <jkoshy@FreeBSD.org>2008-11-09 17:37:54 +0000
commitfdb59f927ee739bbda9db671e11bf83d5a3143f3 (patch)
tree9977abc62b812534217ab29faac7edc58cae0570 /sys/dev/hwpmc/hwpmc_mod.c
parent957a6ed81ce56e8deae2eb8eb5082acf7bbfe234 (diff)
downloadFreeBSD-src-fdb59f927ee739bbda9db671e11bf83d5a3143f3.zip
FreeBSD-src-fdb59f927ee739bbda9db671e11bf83d5a3143f3.tar.gz
- Separate PMC class dependent code from other kinds of machine
dependencies. A 'struct pmc_classdep' structure describes operations on PMCs; 'struct pmc_mdep' contains one or more 'struct pmc_classdep' structures depending on the CPU in question. Inside PMC class dependent code, row indices are relative to the PMCs supported by the PMC class; MI code in "hwpmc_mod.c" translates global row indices before invoking class dependent operations. - Augment the OP_GETCPUINFO request with the number of PMCs present in a PMC class. - Move code common to Intel CPUs to file "hwpmc_intel.c". - Move TSC handling to file "hwpmc_tsc.c".
Diffstat (limited to 'sys/dev/hwpmc/hwpmc_mod.c')
-rw-r--r--sys/dev/hwpmc/hwpmc_mod.c352
1 files changed, 230 insertions, 122 deletions
diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c
index 61c0735..32db1b8 100644
--- a/sys/dev/hwpmc/hwpmc_mod.c
+++ b/sys/dev/hwpmc/hwpmc_mod.c
@@ -154,6 +154,11 @@ static LIST_HEAD(, pmc_owner) pmc_ss_owners;
/*
+ * A map of row indices to classdep structures.
+ */
+static struct pmc_classdep **pmc_rowindex_to_classdep;
+
+/*
* Prototypes
*/
@@ -463,7 +468,7 @@ pmc_debugflags_sysctl_handler(SYSCTL_HANDLER_ARGS)
(void) arg1; (void) arg2; /* unused parameters */
n = sizeof(pmc_debugstr);
- newstr = malloc(n, M_PMC, M_ZERO|M_WAITOK);
+ newstr = malloc(n, M_PMC, M_WAITOK|M_ZERO);
(void) strlcpy(newstr, pmc_debugstr, n);
error = sysctl_handle_string(oidp, newstr, n, req);
@@ -483,6 +488,33 @@ pmc_debugflags_sysctl_handler(SYSCTL_HANDLER_ARGS)
#endif
/*
+ * Map a row index to a classdep structure and return the adjusted row
+ * index for the PMC class index.
+ */
+static struct pmc_classdep *
+pmc_ri_to_classdep(struct pmc_mdep *md, int ri, int *adjri)
+{
+ struct pmc_classdep *pcd;
+
+ (void) md;
+
+ KASSERT(ri >= 0 && ri < md->pmd_npmc,
+ ("[pmc,%d] illegal row-index %d", __LINE__, ri));
+
+ pcd = pmc_rowindex_to_classdep[ri];
+
+ KASSERT(pcd != NULL,
+ ("[amd,%d] ri %d null pcd", __LINE__, ri));
+
+ *adjri = ri - pcd->pcd_ri;
+
+ KASSERT(*adjri >= 0 && *adjri < pcd->pcd_num,
+ ("[pmc,%d] adjusted row-index %d", __LINE__, *adjri));
+
+ return (pcd);
+}
+
+/*
* Concurrency Control
*
* The driver manages the following data structures:
@@ -774,8 +806,7 @@ pmc_link_target_process(struct pmc *pm, struct pmc_process *pp)
__LINE__, pp, pm));
#endif
- pt = malloc(sizeof(struct pmc_target), M_PMC, M_ZERO|M_WAITOK);
-
+ pt = malloc(sizeof(struct pmc_target), M_PMC, M_WAITOK|M_ZERO);
pt->pt_process = pp;
LIST_INSERT_HEAD(&pm->pm_targets, pt, pt_next);
@@ -1159,13 +1190,14 @@ static void
pmc_process_csw_in(struct thread *td)
{
int cpu;
- unsigned int ri;
+ unsigned int adjri, ri;
struct pmc *pm;
struct proc *p;
struct pmc_cpu *pc;
struct pmc_hw *phw;
- struct pmc_process *pp;
pmc_value_t newvalue;
+ struct pmc_process *pp;
+ struct pmc_classdep *pcd;
p = td->td_proc;
@@ -1212,7 +1244,8 @@ pmc_process_csw_in(struct thread *td)
atomic_add_rel_32(&pm->pm_runcount, 1);
/* configure the HWPMC we are going to use. */
- md->pmd_config_pmc(cpu, ri, pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
+ pcd->pcd_config_pmc(cpu, adjri, pm);
phw = pc->pc_hwpmcs[ri];
@@ -1247,8 +1280,8 @@ pmc_process_csw_in(struct thread *td)
PMCDBG(CSW,SWI,1,"cpu=%d ri=%d new=%jd", cpu, ri, newvalue);
- md->pmd_write_pmc(cpu, ri, newvalue);
- md->pmd_start_pmc(cpu, ri);
+ pcd->pcd_write_pmc(cpu, adjri, newvalue);
+ pcd->pcd_start_pmc(cpu, adjri);
}
/*
@@ -1270,14 +1303,16 @@ static void
pmc_process_csw_out(struct thread *td)
{
int cpu;
- enum pmc_mode mode;
- unsigned int ri;
+ int64_t tmp;
struct pmc *pm;
struct proc *p;
+ enum pmc_mode mode;
struct pmc_cpu *pc;
- struct pmc_process *pp;
- int64_t tmp;
pmc_value_t newvalue;
+ unsigned int adjri, ri;
+ struct pmc_process *pp;
+ struct pmc_classdep *pcd;
+
/*
* Locate our process descriptor; this may be NULL if
@@ -1325,8 +1360,9 @@ pmc_process_csw_out(struct thread *td)
for (ri = 0; ri < md->pmd_npmc; ri++) {
- pm = NULL;
- (void) (*md->pmd_get_config)(cpu, ri, &pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
+ pm = NULL;
+ (void) (*pcd->pcd_get_config)(cpu, adjri, &pm);
if (pm == NULL) /* nothing at this row index */
continue;
@@ -1341,7 +1377,7 @@ pmc_process_csw_out(struct thread *td)
/* Stop hardware if not already stopped */
if (pm->pm_stalled == 0)
- md->pmd_stop_pmc(cpu, ri);
+ pcd->pcd_stop_pmc(cpu, adjri);
/* reduce this PMC's runcount */
atomic_subtract_rel_32(&pm->pm_runcount, 1);
@@ -1361,7 +1397,7 @@ pmc_process_csw_out(struct thread *td)
("[pmc,%d] pp refcnt = %d", __LINE__,
pp->pp_refcnt));
- md->pmd_read_pmc(cpu, ri, &newvalue);
+ pcd->pcd_read_pmc(cpu, adjri, &newvalue);
tmp = newvalue - PMC_PCPU_SAVED(cpu,ri);
@@ -1412,7 +1448,7 @@ pmc_process_csw_out(struct thread *td)
}
/* mark hardware as free */
- md->pmd_config_pmc(cpu, ri, NULL);
+ pcd->pcd_config_pmc(cpu, adjri, NULL);
}
/*
@@ -1857,8 +1893,7 @@ pmc_allocate_owner_descriptor(struct proc *p)
poh = &pmc_ownerhash[hindex];
/* allocate space for N pointers and one descriptor struct */
- po = malloc(sizeof(struct pmc_owner), M_PMC, M_ZERO|M_WAITOK);
-
+ po = malloc(sizeof(struct pmc_owner), M_PMC, M_WAITOK|M_ZERO);
po->po_sscount = po->po_error = po->po_flags = 0;
po->po_file = NULL;
po->po_owner = p;
@@ -1907,12 +1942,9 @@ pmc_find_process_descriptor(struct proc *p, uint32_t mode)
* Pre-allocate memory in the FIND_ALLOCATE case since we
* cannot call malloc(9) once we hold a spin lock.
*/
-
- if (mode & PMC_FLAG_ALLOCATE) {
- /* allocate additional space for 'n' pmc pointers */
+ if (mode & PMC_FLAG_ALLOCATE)
ppnew = malloc(sizeof(struct pmc_process) + md->pmd_npmc *
- sizeof(struct pmc_targetstate), M_PMC, M_ZERO|M_WAITOK);
- }
+ sizeof(struct pmc_targetstate), M_PMC, M_WAITOK|M_ZERO);
mtx_lock_spin(&pmc_processhash_mtx);
LIST_FOREACH(pp, pph, pp_next)
@@ -1991,7 +2023,7 @@ pmc_allocate_pmc_descriptor(void)
{
struct pmc *pmc;
- pmc = malloc(sizeof(struct pmc), M_PMC, M_ZERO|M_WAITOK);
+ pmc = malloc(sizeof(struct pmc), M_PMC, M_WAITOK|M_ZERO);
if (pmc != NULL) {
pmc->pm_owner = NULL;
@@ -2066,19 +2098,21 @@ pmc_wait_for_pmc_idle(struct pmc *pm)
static void
pmc_release_pmc_descriptor(struct pmc *pm)
{
- u_int ri, cpu;
enum pmc_mode mode;
struct pmc_hw *phw;
+ u_int adjri, ri, cpu;
struct pmc_owner *po;
+ struct pmc_binding pb;
struct pmc_process *pp;
+ struct pmc_classdep *pcd;
struct pmc_target *ptgt, *tmp;
- struct pmc_binding pb;
sx_assert(&pmc_sx, SX_XLOCKED);
KASSERT(pm, ("[pmc,%d] null pmc", __LINE__));
ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
mode = PMC_TO_MODE(pm);
PMCDBG(PMC,REL,1, "release-pmc pmc=%p ri=%d mode=%d", pm, ri,
@@ -2112,14 +2146,14 @@ pmc_release_pmc_descriptor(struct pmc *pm)
PMCDBG(PMC,REL,2, "stopping cpu=%d ri=%d", cpu, ri);
critical_enter();
- md->pmd_stop_pmc(cpu, ri);
+ pcd->pcd_stop_pmc(cpu, adjri);
critical_exit();
}
PMCDBG(PMC,REL,2, "decfg cpu=%d ri=%d", cpu, ri);
critical_enter();
- md->pmd_config_pmc(cpu, ri, NULL);
+ pcd->pcd_config_pmc(cpu, adjri, NULL);
critical_exit();
/* adjust the global and process count of SS mode PMCs */
@@ -2192,8 +2226,7 @@ pmc_release_pmc_descriptor(struct pmc *pm)
/*
* Release any MD resources
*/
-
- (void) md->pmd_release_pmc(cpu, ri, pm);
+ (void) pcd->pcd_release_pmc(cpu, adjri, pm);
/*
* Update row disposition
@@ -2408,16 +2441,19 @@ pmc_find_pmc(pmc_id_t pmcid, struct pmc **pmc)
static int
pmc_start(struct pmc *pm)
{
- int error, cpu, ri;
enum pmc_mode mode;
struct pmc_owner *po;
struct pmc_binding pb;
+ struct pmc_classdep *pcd;
+ int adjri, error, cpu, ri;
KASSERT(pm != NULL,
("[pmc,%d] null pm", __LINE__));
mode = PMC_TO_MODE(pm);
ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
+
error = 0;
PMCDBG(PMC,OPS,1, "start pmc=%p mode=%d ri=%d", pm, mode, ri);
@@ -2430,7 +2466,7 @@ pmc_start(struct pmc *pm)
*/
if ((pm->pm_flags & PMC_F_NEEDS_LOGFILE) &&
(po->po_flags & PMC_PO_OWNS_LOGFILE) == 0)
- return EDOOFUS; /* programming error */
+ return (EDOOFUS); /* programming error */
/*
* If this is a sampling mode PMC, log mapping information for
@@ -2461,7 +2497,7 @@ pmc_start(struct pmc *pm)
pmc_force_context_switch();
}
- return error;
+ return (error);
}
@@ -2494,7 +2530,7 @@ pmc_start(struct pmc *pm)
cpu = PMC_TO_CPU(pm);
if (!pmc_cpu_is_active(cpu))
- return ENXIO;
+ return (ENXIO);
pmc_select_cpu(cpu);
@@ -2506,16 +2542,16 @@ pmc_start(struct pmc *pm)
pm->pm_state = PMC_STATE_RUNNING;
critical_enter();
- if ((error = md->pmd_write_pmc(cpu, ri,
+ if ((error = pcd->pcd_write_pmc(cpu, adjri,
PMC_IS_SAMPLING_MODE(mode) ?
pm->pm_sc.pm_reloadcount :
pm->pm_sc.pm_initial)) == 0)
- error = md->pmd_start_pmc(cpu, ri);
+ error = pcd->pcd_start_pmc(cpu, adjri);
critical_exit();
pmc_restore_cpu_binding(&pb);
- return error;
+ return (error);
}
/*
@@ -2525,9 +2561,10 @@ pmc_start(struct pmc *pm)
static int
pmc_stop(struct pmc *pm)
{
- int cpu, error, ri;
struct pmc_owner *po;
struct pmc_binding pb;
+ struct pmc_classdep *pcd;
+ int adjri, cpu, error, ri;
KASSERT(pm != NULL, ("[pmc,%d] null pmc", __LINE__));
@@ -2569,10 +2606,11 @@ pmc_stop(struct pmc *pm)
pmc_select_cpu(cpu);
ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
critical_enter();
- if ((error = md->pmd_stop_pmc(cpu, ri)) == 0)
- error = md->pmd_read_pmc(cpu, ri, &pm->pm_sc.pm_initial);
+ if ((error = pcd->pcd_stop_pmc(cpu, adjri)) == 0)
+ error = pcd->pcd_read_pmc(cpu, adjri, &pm->pm_sc.pm_initial);
critical_exit();
pmc_restore_cpu_binding(&pb);
@@ -2589,7 +2627,7 @@ pmc_stop(struct pmc *pm)
}
}
- return error;
+ return (error);
}
@@ -2726,13 +2764,22 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
case PMC_OP_GETCPUINFO: /* CPU information */
{
struct pmc_op_getcpuinfo gci;
+ struct pmc_classinfo *pci;
+ struct pmc_classdep *pcd;
+ int cl;
gci.pm_cputype = md->pmd_cputype;
gci.pm_ncpu = pmc_cpu_max();
gci.pm_npmc = md->pmd_npmc;
gci.pm_nclass = md->pmd_nclass;
- bcopy(md->pmd_classes, &gci.pm_classes,
- sizeof(gci.pm_classes));
+ pci = gci.pm_classes;
+ pcd = md->pmd_classdep;
+ for (cl = 0; cl < md->pmd_nclass; cl++, pci++, pcd++) {
+ pci->pm_caps = pcd->pcd_caps;
+ pci->pm_class = pcd->pcd_class;
+ pci->pm_width = pcd->pcd_width;
+ pci->pm_num = pcd->pcd_num;
+ }
error = copyout(&gci, arg, sizeof(gci));
}
break;
@@ -2781,13 +2828,15 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
case PMC_OP_GETPMCINFO:
{
- uint32_t cpu, n, npmc;
- size_t pmcinfo_size;
+ int ari;
struct pmc *pm;
- struct pmc_info *p, *pmcinfo;
- struct pmc_op_getpmcinfo *gpi;
+ size_t pmcinfo_size;
+ uint32_t cpu, n, npmc;
struct pmc_owner *po;
struct pmc_binding pb;
+ struct pmc_classdep *pcd;
+ struct pmc_info *p, *pmcinfo;
+ struct pmc_op_getpmcinfo *gpi;
PMC_DOWNGRADE_SX();
@@ -2819,7 +2868,12 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
for (n = 0; n < md->pmd_npmc; n++, p++) {
- if ((error = md->pmd_describe(cpu, n, p, &pm)) != 0)
+ pcd = pmc_ri_to_classdep(md, n, &ari);
+
+ KASSERT(pcd != NULL,
+ ("[pmc,%d] null pcd ri=%d", __LINE__, n));
+
+ if ((error = pcd->pcd_describe(cpu, ari, p, &pm)) != 0)
break;
if (PMC_ROW_DISP_IS_STANDALONE(n))
@@ -2964,14 +3018,15 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
case PMC_OP_PMCALLOCATE:
{
- uint32_t caps;
+ int adjri, n;
u_int cpu;
- int n;
- enum pmc_mode mode;
+ uint32_t caps;
struct pmc *pmc;
+ enum pmc_mode mode;
struct pmc_hw *phw;
- struct pmc_op_pmcallocate pa;
struct pmc_binding pb;
+ struct pmc_classdep *pcd;
+ struct pmc_op_pmcallocate pa;
if ((error = copyin(arg, &pa, sizeof(pa))) != 0)
break;
@@ -3056,7 +3111,7 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
/* A valid class specifier should have been passed in. */
for (n = 0; n < md->pmd_nclass; n++)
- if (md->pmd_classes[n].pm_class == pa.pm_class)
+ if (md->pmd_classdep[n].pcd_class == pa.pm_class)
break;
if (n == md->pmd_nclass) {
error = EINVAL;
@@ -3064,7 +3119,7 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
}
/* The requested PMC capabilities should be feasible. */
- if ((md->pmd_classes[n].pm_caps & caps) != caps) {
+ if ((md->pmd_classdep[n].pcd_caps & caps) != caps) {
error = EOPNOTSUPP;
break;
}
@@ -3091,24 +3146,27 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
if (PMC_IS_SYSTEM_MODE(mode)) {
pmc_select_cpu(cpu);
- for (n = 0; n < (int) md->pmd_npmc; n++)
+ for (n = 0; n < (int) md->pmd_npmc; n++) {
+ pcd = pmc_ri_to_classdep(md, n, &adjri);
if (pmc_can_allocate_row(n, mode) == 0 &&
pmc_can_allocate_rowindex(
curthread->td_proc, n, cpu) == 0 &&
(PMC_IS_UNALLOCATED(cpu, n) ||
PMC_IS_SHAREABLE_PMC(cpu, n)) &&
- md->pmd_allocate_pmc(cpu, n, pmc,
+ pcd->pcd_allocate_pmc(cpu, adjri, pmc,
&pa) == 0)
break;
+ }
} else {
/* Process virtual mode */
for (n = 0; n < (int) md->pmd_npmc; n++) {
+ pcd = pmc_ri_to_classdep(md, n, &adjri);
if (pmc_can_allocate_row(n, mode) == 0 &&
pmc_can_allocate_rowindex(
curthread->td_proc, n,
PMC_CPU_ANY) == 0 &&
- md->pmd_allocate_pmc(curthread->td_oncpu,
- n, pmc, &pa) == 0)
+ pcd->pcd_allocate_pmc(curthread->td_oncpu,
+ adjri, pmc, &pa) == 0)
break;
}
}
@@ -3150,10 +3208,11 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
pmc_select_cpu(cpu);
phw = pmc_pcpu[cpu]->pc_hwpmcs[n];
+ pcd = pmc_ri_to_classdep(md, n, &adjri);
if ((phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) == 0 ||
- (error = md->pmd_config_pmc(cpu, n, pmc)) != 0) {
- (void) md->pmd_release_pmc(cpu, n, pmc);
+ (error = pcd->pcd_config_pmc(cpu, adjri, pmc)) != 0) {
+ (void) pcd->pcd_release_pmc(cpu, adjri, pmc);
pmc_destroy_pmc_descriptor(pmc);
free(pmc, M_PMC);
pmc = NULL;
@@ -3319,19 +3378,14 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
case PMC_OP_PMCGETMSR:
{
- int ri;
- struct pmc *pm;
+ int adjri, ri;
+ struct pmc *pm;
struct pmc_target *pt;
struct pmc_op_getmsr gm;
+ struct pmc_classdep *pcd;
PMC_DOWNGRADE_SX();
- /* CPU has no 'GETMSR' support */
- if (md->pmd_get_msr == NULL) {
- error = ENOSYS;
- break;
- }
-
if ((error = copyin(arg, &gm, sizeof(gm))) != 0)
break;
@@ -3371,8 +3425,15 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
}
ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
+
+ /* PMC class has no 'GETMSR' support */
+ if (pcd->pcd_get_msr == NULL) {
+ error = ENOSYS;
+ break;
+ }
- if ((error = (*md->pmd_get_msr)(ri, &gm.pm_msr)) < 0)
+ if ((error = (*pcd->pcd_get_msr)(adjri, &gm.pm_msr)) < 0)
break;
if ((error = copyout(&gm, arg, sizeof(gm))) < 0)
@@ -3436,12 +3497,14 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
case PMC_OP_PMCRW:
{
- uint32_t cpu, ri;
+ int adjri;
struct pmc *pm;
- struct pmc_op_pmcrw *pprw;
- struct pmc_op_pmcrw prw;
- struct pmc_binding pb;
+ uint32_t cpu, ri;
pmc_value_t oldvalue;
+ struct pmc_binding pb;
+ struct pmc_op_pmcrw prw;
+ struct pmc_classdep *pcd;
+ struct pmc_op_pmcrw *pprw;
PMC_DOWNGRADE_SX();
@@ -3494,6 +3557,7 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
*/
ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
mtx_pool_lock_spin(pmc_mtxpool, pm);
cpu = curthread->td_oncpu;
@@ -3501,7 +3565,7 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
if (prw.pm_flags & PMC_F_OLDVALUE) {
if ((pm->pm_flags & PMC_F_ATTACHED_TO_OWNER) &&
(pm->pm_state == PMC_STATE_RUNNING))
- error = (*md->pmd_read_pmc)(cpu, ri,
+ error = (*pcd->pcd_read_pmc)(cpu, adjri,
&oldvalue);
else
oldvalue = pm->pm_gv.pm_savedvalue;
@@ -3514,6 +3578,7 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
} else { /* System mode PMCs */
cpu = PMC_TO_CPU(pm);
ri = PMC_TO_ROWINDEX(pm);
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
if (!pmc_cpu_is_active(cpu)) {
error = ENXIO;
@@ -3527,12 +3592,12 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
critical_enter();
/* save old value */
if (prw.pm_flags & PMC_F_OLDVALUE)
- if ((error = (*md->pmd_read_pmc)(cpu, ri,
+ if ((error = (*pcd->pcd_read_pmc)(cpu, adjri,
&oldvalue)))
goto error;
/* write out new value */
if (prw.pm_flags & PMC_F_NEWVALUE)
- error = (*md->pmd_write_pmc)(cpu, ri,
+ error = (*pcd->pcd_write_pmc)(cpu, adjri,
prw.pm_value);
error:
critical_exit();
@@ -3900,11 +3965,12 @@ pmc_capture_user_callchain(int cpu, struct trapframe *tf)
static void
pmc_process_samples(int cpu)
{
- int n, ri;
struct pmc *pm;
+ int adjri, n, ri;
struct thread *td;
struct pmc_owner *po;
struct pmc_sample *ps;
+ struct pmc_classdep *pcd;
struct pmc_samplebuffer *psb;
KASSERT(PCPU_GET(cpuid) == cpu,
@@ -3988,7 +4054,11 @@ pmc_process_samples(int cpu)
* the next hardclock tick.
*/
for (n = 0; n < md->pmd_npmc; n++) {
- (void) (*md->pmd_get_config)(cpu,n,&pm);
+ pcd = pmc_ri_to_classdep(md, n, &adjri);
+ KASSERT(pcd != NULL,
+ ("[pmc,%d] null pcd ri=%d", __LINE__, n));
+ (void) (*pcd->pcd_get_config)(cpu,adjri,&pm);
+
if (pm == NULL || /* !cfg'ed */
pm->pm_state != PMC_STATE_RUNNING || /* !active */
!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)) || /* !sampling */
@@ -3997,7 +4067,7 @@ pmc_process_samples(int cpu)
pm->pm_stalled = 0;
ri = PMC_TO_ROWINDEX(pm);
- (*md->pmd_start_pmc)(cpu, ri);
+ (*pcd->pcd_start_pmc)(cpu, adjri);
}
}
@@ -4025,12 +4095,13 @@ pmc_process_samples(int cpu)
static void
pmc_process_exit(void *arg __unused, struct proc *p)
{
- int is_using_hwpmcs;
- int cpu;
- unsigned int ri;
struct pmc *pm;
- struct pmc_process *pp;
+ int adjri, cpu;
+ unsigned int ri;
+ int is_using_hwpmcs;
struct pmc_owner *po;
+ struct pmc_process *pp;
+ struct pmc_classdep *pcd;
pmc_value_t newvalue, tmp;
PROC_LOCK(p);
@@ -4091,7 +4162,10 @@ pmc_process_exit(void *arg __unused, struct proc *p)
* state similar to the CSW_OUT code.
*/
pm = NULL;
- (void) (*md->pmd_get_config)(cpu, ri, &pm);
+
+ pcd = pmc_ri_to_classdep(md, ri, &adjri);
+
+ (void) (*pcd->pcd_get_config)(cpu, adjri, &pm);
PMCDBG(PRC,EXT,2, "ri=%d pm=%p", ri, pm);
@@ -4111,7 +4185,7 @@ pmc_process_exit(void *arg __unused, struct proc *p)
("[pmc,%d] pm %p != pp_pmcs[%d] %p",
__LINE__, pm, ri, pp->pp_pmcs[ri].pp_pmc));
- (void) md->pmd_stop_pmc(cpu, ri);
+ (void) pcd->pcd_stop_pmc(cpu, adjri);
KASSERT(pm->pm_runcount > 0,
("[pmc,%d] bad runcount ri %d rc %d",
@@ -4120,7 +4194,7 @@ pmc_process_exit(void *arg __unused, struct proc *p)
/* Stop hardware only if it is actually running */
if (pm->pm_state == PMC_STATE_RUNNING &&
pm->pm_stalled == 0) {
- md->pmd_read_pmc(cpu, ri, &newvalue);
+ pcd->pcd_read_pmc(cpu, adjri, &newvalue);
tmp = newvalue -
PMC_PCPU_SAVED(cpu,ri);
@@ -4135,7 +4209,7 @@ pmc_process_exit(void *arg __unused, struct proc *p)
KASSERT((int) pm->pm_runcount >= 0,
("[pmc,%d] runcount is %d", __LINE__, ri));
- (void) md->pmd_config_pmc(cpu, ri, NULL);
+ (void) pcd->pcd_config_pmc(cpu, adjri, NULL);
}
/*
@@ -4284,10 +4358,11 @@ static const char *pmc_name_of_pmcclass[] = {
static int
pmc_initialize(void)
{
- int cpu, error, n;
+ int c, cpu, error, n, ri;
unsigned int maxcpu;
struct pmc_binding pb;
struct pmc_sample *ps;
+ struct pmc_classdep *pcd;
struct pmc_samplebuffer *sb;
md = NULL;
@@ -4340,14 +4415,33 @@ pmc_initialize(void)
md = pmc_md_initialize();
- if (md == NULL || md->pmd_init == NULL)
- return ENOSYS;
+ if (md == NULL)
+ return (ENOSYS);
+
+ KASSERT(md->pmd_nclass >= 1 && md->pmd_npmc >= 1,
+ ("[pmc,%d] no classes or pmcs", __LINE__));
+
+ /* Compute the map from row-indices to classdep pointers. */
+ pmc_rowindex_to_classdep = malloc(sizeof(struct pmc_classdep *) *
+ md->pmd_npmc, M_PMC, M_WAITOK|M_ZERO);
+
+ for (n = 0; n < md->pmd_npmc; n++)
+ pmc_rowindex_to_classdep[n] = NULL;
+ for (ri = c = 0; c < md->pmd_nclass; c++) {
+ pcd = &md->pmd_classdep[c];
+ for (n = 0; n < pcd->pcd_num; n++, ri++)
+ pmc_rowindex_to_classdep[ri] = pcd;
+ }
+
+ KASSERT(ri == md->pmd_npmc,
+ ("[pmc,%d] npmc miscomputed: ri=%d, md->npmc=%d", __LINE__,
+ ri, md->pmd_npmc));
maxcpu = pmc_cpu_max();
/* allocate space for the per-cpu array */
- pmc_pcpu = malloc(maxcpu * sizeof(struct pmc_cpu *),
- M_PMC, M_WAITOK|M_ZERO);
+ pmc_pcpu = malloc(maxcpu * sizeof(struct pmc_cpu *), M_PMC,
+ M_WAITOK|M_ZERO);
/* per-cpu 'saved values' for managing process-mode PMCs */
pmc_pcpu_saved = malloc(sizeof(pmc_value_t) * maxcpu * md->pmd_npmc,
@@ -4355,34 +4449,40 @@ pmc_initialize(void)
/* Perform CPU-dependent initialization. */
pmc_save_cpu_binding(&pb);
- for (cpu = 0; cpu < maxcpu; cpu++) {
+ error = 0;
+ for (cpu = 0; error == 0 && cpu < maxcpu; cpu++) {
if (!pmc_cpu_is_active(cpu))
continue;
pmc_select_cpu(cpu);
- if ((error = md->pmd_init(cpu)) != 0)
- break;
+ pmc_pcpu[cpu] = malloc(sizeof(struct pmc_cpu) +
+ md->pmd_npmc * sizeof(struct pmc_hw *), M_PMC,
+ M_WAITOK|M_ZERO);
+ if (md->pmd_pcpu_init)
+ error = md->pmd_pcpu_init(cpu);
+ for (n = 0; error == 0 && n < md->pmd_nclass; n++)
+ error = md->pmd_classdep[n].pcd_pcpu_init(md, cpu);
}
pmc_restore_cpu_binding(&pb);
- if (error != 0)
- return error;
+ if (error)
+ return (error);
/* allocate space for the sample array */
for (cpu = 0; cpu < maxcpu; cpu++) {
if (!pmc_cpu_is_active(cpu))
continue;
+
sb = malloc(sizeof(struct pmc_samplebuffer) +
pmc_nsamples * sizeof(struct pmc_sample), M_PMC,
M_WAITOK|M_ZERO);
-
sb->ps_read = sb->ps_write = sb->ps_samples;
sb->ps_fence = sb->ps_samples + pmc_nsamples;
+
KASSERT(pmc_pcpu[cpu] != NULL,
("[pmc,%d] cpu=%d Null per-cpu data", __LINE__, cpu));
- sb->ps_callchains = malloc(pmc_callchaindepth *
- pmc_nsamples * sizeof(uintptr_t),
- M_PMC, M_WAITOK|M_ZERO);
+ sb->ps_callchains = malloc(pmc_callchaindepth * pmc_nsamples *
+ sizeof(uintptr_t), M_PMC, M_WAITOK|M_ZERO);
for (n = 0, ps = sb->ps_samples; n < pmc_nsamples; n++, ps++)
ps->ps_pc = sb->ps_callchains +
@@ -4438,10 +4538,11 @@ pmc_initialize(void)
if (error == 0) {
printf(PMC_MODULE_NAME ":");
for (n = 0; n < (int) md->pmd_nclass; n++) {
+ pcd = &md->pmd_classdep[n];
printf(" %s/%d/0x%b",
- pmc_name_of_pmcclass[md->pmd_classes[n].pm_class],
- md->pmd_nclasspmcs[n],
- md->pmd_classes[n].pm_caps,
+ pmc_name_of_pmcclass[pcd->pcd_class],
+ pcd->pcd_num,
+ pcd->pcd_caps,
"\20"
"\1INT\2USR\3SYS\4EDG\5THR"
"\6REA\7WRI\10INV\11QUA\12PRC"
@@ -4450,14 +4551,14 @@ pmc_initialize(void)
printf("\n");
}
- return error;
+ return (error);
}
/* prepare to be unloaded */
static void
pmc_cleanup(void)
{
- int cpu;
+ int c, cpu;
unsigned int maxcpu;
struct pmc_ownerhash *ph;
struct pmc_owner *po, *tmp;
@@ -4538,20 +4639,9 @@ pmc_cleanup(void)
KASSERT(pmc_ss_count == 0,
("[pmc,%d] Global SS count not empty", __LINE__));
- /* Free the per-cpu sample buffers. */
+ /* do processor and pmc-class dependent cleanup */
maxcpu = pmc_cpu_max();
- for (cpu = 0; cpu < maxcpu; cpu++) {
- if (!pmc_cpu_is_active(cpu))
- continue;
- KASSERT(pmc_pcpu[cpu]->pc_sb != NULL,
- ("[pmc,%d] Null cpu sample buffer cpu=%d", __LINE__,
- cpu));
- free(pmc_pcpu[cpu]->pc_sb->ps_callchains, M_PMC);
- free(pmc_pcpu[cpu]->pc_sb, M_PMC);
- pmc_pcpu[cpu]->pc_sb = NULL;
- }
- /* do processor dependent cleanup */
PMCDBG(MOD,INI,3, "%s", "md cleanup");
if (md) {
pmc_save_cpu_binding(&pb);
@@ -4561,15 +4651,28 @@ pmc_cleanup(void)
if (!pmc_cpu_is_active(cpu) || pmc_pcpu[cpu] == NULL)
continue;
pmc_select_cpu(cpu);
- if (md->pmd_cleanup)
- md->pmd_cleanup(cpu);
+ for (c = 0; c < md->pmd_nclass; c++)
+ md->pmd_classdep[c].pcd_pcpu_fini(md, cpu);
+ if (md->pmd_pcpu_fini)
+ md->pmd_pcpu_fini(cpu);
}
free(md, M_PMC);
md = NULL;
pmc_restore_cpu_binding(&pb);
}
- /* deallocate per-cpu structures */
+ /* Free per-cpu descriptors. */
+ for (cpu = 0; cpu < maxcpu; cpu++) {
+ if (!pmc_cpu_is_active(cpu))
+ continue;
+ KASSERT(pmc_pcpu[cpu]->pc_sb != NULL,
+ ("[pmc,%d] Null cpu sample buffer cpu=%d", __LINE__,
+ cpu));
+ free(pmc_pcpu[cpu]->pc_sb->ps_callchains, M_PMC);
+ free(pmc_pcpu[cpu]->pc_sb, M_PMC);
+ free(pmc_pcpu[cpu], M_PMC);
+ }
+
free(pmc_pcpu, M_PMC);
pmc_pcpu = NULL;
@@ -4581,6 +4684,11 @@ pmc_cleanup(void)
pmc_pmcdisp = NULL;
}
+ if (pmc_rowindex_to_classdep) {
+ free(pmc_rowindex_to_classdep, M_PMC);
+ pmc_rowindex_to_classdep = NULL;
+ }
+
pmclog_shutdown();
sx_xunlock(&pmc_sx); /* we are done */
OpenPOWER on IntegriCloud