diff options
author | jkoshy <jkoshy@FreeBSD.org> | 2008-11-09 17:37:54 +0000 |
---|---|---|
committer | jkoshy <jkoshy@FreeBSD.org> | 2008-11-09 17:37:54 +0000 |
commit | fdb59f927ee739bbda9db671e11bf83d5a3143f3 (patch) | |
tree | 9977abc62b812534217ab29faac7edc58cae0570 /sys/dev/hwpmc/hwpmc_mod.c | |
parent | 957a6ed81ce56e8deae2eb8eb5082acf7bbfe234 (diff) | |
download | FreeBSD-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.c | 352 |
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 */ |