From nobody Wed Jun 14 16:46:43 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4QhBCS44SDz4dHrm; Wed, 14 Jun 2023 16:46:44 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4QhBCR6YvHz4Pp3; Wed, 14 Jun 2023 16:46:43 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1686761203; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=ghR0R8z746KweurbtvNXJeYId9qH3e7u2dKI3Hjx4gc=; b=u83aY2hoQsLGocvL1hoxgf0kyLfZ160Z4Kh6vzNM2CkaKQM+3CABxEp/g4w+NkotGWr4sH fLjuVyoV2f2q2BlGGle/QBZsBDNB90ClVF+/XNnBRpW1ycGilO2Wrf5OMpMX1uGQxrMbGR tDaJn58kOiZiOMtt6xIJKAgnKQKybsspDEV1DOJgMyQs4pIFtVxibP7axtIzMuNFh1cec5 uLebN9V4N/Fz6634DjiSIDRox87Q8gPPphFuKPdWtI4+aNyaHGrphmzWTlFzl1WEDZcI1e Ts6jqsS84qMSW/XzNCSKr+iZFKROiD+s+vJaMNG4tTh8l7hNAaOmBAufL3fFsQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1686761203; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=ghR0R8z746KweurbtvNXJeYId9qH3e7u2dKI3Hjx4gc=; b=pEqM8hhpwISuGnaNd5fphsQJpJboSm50O6e4J/SKP6SipYbavpe1gwizS57RFMkIrrf2kg hvOtxqCaSD7nmKqFnd+hqJuBJHAol+uTLDJEYIh+jsfQ1PVT0+9t9znHtfeEB3gxhL+GyL xn39D7iLTnfcyy6wssyRATFW0f/eVwPb5kWOYTYM7OsxKuQIfgg4vT2VgQKlRwDgJw51Iv e9AKXU3cs+oR9pMxSRK1xmAPslCwGxFwf0R0phd2iZSWSTl1NlU3wIBSLbu2aoyG3ecZ1u t7rrYh5mFyhSO+3zBesF+HmBbgnhcuY+9WJXu0Hc1fOU/3Ecl6aKaF05diVshg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1686761203; a=rsa-sha256; cv=none; b=CEZmOAYbL/to3DdCFIR1k6winXMS1GHN2FH74WfQNYJqg07gu+z5U7pmLzINWu8ZRf2mct kVxJDbsUgXr2zKVRZEQblO3ONDovv2ztHade07ed/F/IMO4edAooQShaGimHNlPKIDUysC RG29N+iGIX/x4y29VmCz0vyQnd/Db7qECIcC+WZtbcPr+HKevvfwPOxYvErCM/tRF8DDQw /f+9/MKdCX3N3dsUgN0hGvcNDoXlUYf+ctnjhDRUNuLOMy+uqQ42KwDXvEmoqy8M5NHDCd Xt2i5ZFO/xYwzr7QPsqaJlABiw53I3MBKd8iQQw4N9i07aeGPtCKhdU+/8lxQA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4QhBCR4g7tz1B29; Wed, 14 Jun 2023 16:46:43 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 35EGkh5C028450; Wed, 14 Jun 2023 16:46:43 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 35EGkh0J028449; Wed, 14 Jun 2023 16:46:43 GMT (envelope-from git) Date: Wed, 14 Jun 2023 16:46:43 GMT Message-Id: <202306141646.35EGkh0J028449@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mitchell Horne Subject: git: c514a571af74 - main - hwpmc: split out PMC_OP_PMCALLOCATE List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mhorne X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: c514a571af74429d9f2a0e9e1118e0903906c4de Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by mhorne: URL: https://cgit.FreeBSD.org/src/commit/?id=c514a571af74429d9f2a0e9e1118e0903906c4de commit c514a571af74429d9f2a0e9e1118e0903906c4de Author: Mitchell Horne AuthorDate: 2023-06-14 16:33:27 +0000 Commit: Mitchell Horne CommitDate: 2023-06-14 16:34:21 +0000 hwpmc: split out PMC_OP_PMCALLOCATE Split out the large chunk of functional logic from the syscall handler into a helper function. This keeps it separate from the syscall control-flow logic, resulting in better readability overall. It also wins back a level of indentation. Flip the return values of the pmc_can_allocate_row() and pmc_can_allocate_rowindex() functions to boolean types, like their naming implies. We weren't actually using the error codes they were returning. While here, make some small style cleanups. No functional change intended. Reviewed by: jkoshy MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D40292 --- sys/dev/hwpmc/hwpmc_mod.c | 521 +++++++++++++++++++++++----------------------- 1 file changed, 256 insertions(+), 265 deletions(-) diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c index 24cd3ba0fc0f..fb6aa3ad4588 100644 --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -210,7 +210,8 @@ static int pmc_attach_process(struct proc *p, struct pmc *pm); static struct pmc *pmc_allocate_pmc_descriptor(void); static struct pmc_owner *pmc_allocate_owner_descriptor(struct proc *p); static int pmc_attach_one_process(struct proc *p, struct pmc *pm); -static int pmc_can_allocate_rowindex(struct proc *p, unsigned int ri, +static bool pmc_can_allocate_row(int ri, enum pmc_mode mode); +static bool pmc_can_allocate_rowindex(struct proc *p, unsigned int ri, int cpu); static int pmc_can_attach(struct pmc *pm, struct proc *p); static void pmc_capture_user_callchain(int cpu, int soft, @@ -2904,7 +2905,7 @@ pmc_getrowdisp(int ri) * - the current process has already allocated a PMC at index 'ri' * via OP_ALLOCATE. */ -static int +static bool pmc_can_allocate_rowindex(struct proc *p, unsigned int ri, int cpu) { struct pmc *pm; @@ -2927,10 +2928,10 @@ pmc_can_allocate_rowindex(struct proc *p, unsigned int ri, int cpu) if (PMC_TO_ROWINDEX(pm) == ri) { mode = PMC_TO_MODE(pm); if (PMC_IS_VIRTUAL_MODE(mode)) - return (EEXIST); + return (false); if (PMC_IS_SYSTEM_MODE(mode) && PMC_TO_CPU(pm) == cpu) - return (EEXIST); + return (false); } } } @@ -2941,18 +2942,18 @@ pmc_can_allocate_rowindex(struct proc *p, unsigned int ri, int cpu) */ if ((pp = pmc_find_process_descriptor(p, 0)) != NULL) if (pp->pp_pmcs[ri].pp_pmc != NULL) - return (EEXIST); + return (false); PMCDBG4(PMC,ALR,2, "can-allocate-rowindex proc=%p (%d, %s) ri=%d ok", p, p->p_pid, p->p_comm, ri); - return (0); + return (true); } /* * Check if a given PMC at row index 'ri' can be currently used in * mode 'mode'. */ -static int +static bool pmc_can_allocate_row(int ri, enum pmc_mode mode) { enum pmc_disp disp; @@ -2979,13 +2980,13 @@ pmc_can_allocate_row(int ri, enum pmc_mode mode) if (!PMC_ROW_DISP_IS_FREE(ri) && !(disp == PMC_DISP_THREAD && PMC_ROW_DISP_IS_THREAD(ri)) && !(disp == PMC_DISP_STANDALONE && PMC_ROW_DISP_IS_STANDALONE(ri))) - return (EBUSY); + return (false); /* * All OK */ PMCDBG2(PMC,ALR,2, "can-allocate-row ri=%d mode=%d ok", ri, mode); - return (0); + return (true); } /* @@ -3282,6 +3283,248 @@ static const char *pmc_op_to_name[] = { is_sx_downgraded = true; \ } while (0) +/* + * Main body of PMC_OP_PMCALLOCATE. + */ +static int +pmc_do_op_pmcallocate(struct thread *td, struct pmc_op_pmcallocate *pa) +{ + struct proc *p; + struct pmc *pmc; + struct pmc_binding pb; + struct pmc_classdep *pcd; + struct pmc_hw *phw; + enum pmc_mode mode; + enum pmc_class class; + uint32_t caps; + u_int cpu; + int adjri, n; + int error; + + class = pa->pm_class; + caps = pa->pm_caps; + mode = pa->pm_mode; + cpu = pa->pm_cpu; + + p = td->td_proc; + + /* Requested mode must exist. */ + if ((mode != PMC_MODE_SS && mode != PMC_MODE_SC && + mode != PMC_MODE_TS && mode != PMC_MODE_TC)) + return (EINVAL); + + /* Requested CPU must be valid. */ + if (cpu != PMC_CPU_ANY && cpu >= pmc_cpu_max()) + return (EINVAL); + + /* + * Virtual PMCs should only ask for a default CPU. + * System mode PMCs need to specify a non-default CPU. + */ + if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != PMC_CPU_ANY) || + (PMC_IS_SYSTEM_MODE(mode) && cpu == PMC_CPU_ANY)) + return (EINVAL); + + /* + * Check that an inactive CPU is not being asked for. + */ + if (PMC_IS_SYSTEM_MODE(mode) && !pmc_cpu_is_active(cpu)) + return (ENXIO); + + /* + * Refuse an allocation for a system-wide PMC if this process has been + * jailed, or if this process lacks super-user credentials and the + * sysctl tunable 'security.bsd.unprivileged_syspmcs' is zero. + */ + if (PMC_IS_SYSTEM_MODE(mode)) { + if (jailed(td->td_ucred)) + return (EPERM); + if (!pmc_unprivileged_syspmcs) { + error = priv_check(td, PRIV_PMC_SYSTEM); + if (error != 0) + return (error); + } + } + + /* + * Look for valid values for 'pm_flags'. + */ + if ((pa->pm_flags & ~(PMC_F_DESCENDANTS | PMC_F_LOG_PROCCSW | + PMC_F_LOG_PROCEXIT | PMC_F_CALLCHAIN | PMC_F_USERCALLCHAIN)) != 0) + return (EINVAL); + + /* PMC_F_USERCALLCHAIN is only valid with PMC_F_CALLCHAIN. */ + if ((pa->pm_flags & (PMC_F_CALLCHAIN | PMC_F_USERCALLCHAIN)) == + PMC_F_USERCALLCHAIN) + return (EINVAL); + + /* PMC_F_USERCALLCHAIN is only valid for sampling mode. */ + if ((pa->pm_flags & PMC_F_USERCALLCHAIN) != 0 && mode != PMC_MODE_TS && + mode != PMC_MODE_SS) + return (EINVAL); + + /* Process logging options are not allowed for system PMCs. */ + if (PMC_IS_SYSTEM_MODE(mode) && + (pa->pm_flags & (PMC_F_LOG_PROCCSW | PMC_F_LOG_PROCEXIT)) != 0) + return (EINVAL); + + /* + * All sampling mode PMCs need to be able to interrupt the CPU. + */ + if (PMC_IS_SAMPLING_MODE(mode)) + caps |= PMC_CAP_INTERRUPT; + + /* A valid class specifier should have been passed in. */ + pcd = pmc_class_to_classdep(class); + if (pcd == NULL) + return (EINVAL); + + /* The requested PMC capabilities should be feasible. */ + if ((pcd->pcd_caps & caps) != caps) + return (EOPNOTSUPP); + + PMCDBG4(PMC,ALL,2, "event=%d caps=0x%x mode=%d cpu=%d", pa->pm_ev, + caps, mode, cpu); + + pmc = pmc_allocate_pmc_descriptor(); + pmc->pm_id = PMC_ID_MAKE_ID(cpu, pa->pm_mode, class, PMC_ID_INVALID); + pmc->pm_event = pa->pm_ev; + pmc->pm_state = PMC_STATE_FREE; + pmc->pm_caps = caps; + pmc->pm_flags = pa->pm_flags; + + /* XXX set lower bound on sampling for process counters */ + if (PMC_IS_SAMPLING_MODE(mode)) { + /* + * Don't permit requested sample rate to be less than + * pmc_mincount. + */ + if (pa->pm_count < MAX(1, pmc_mincount)) + log(LOG_WARNING, "pmcallocate: passed sample " + "rate %ju - setting to %u\n", + (uintmax_t)pa->pm_count, + MAX(1, pmc_mincount)); + pmc->pm_sc.pm_reloadcount = MAX(MAX(1, pmc_mincount), + pa->pm_count); + } else + pmc->pm_sc.pm_initial = pa->pm_count; + + /* switch thread to CPU 'cpu' */ + pmc_save_cpu_binding(&pb); + +#define PMC_IS_SHAREABLE_PMC(cpu, n) \ + (pmc_pcpu[(cpu)]->pc_hwpmcs[(n)]->phw_state & \ + PMC_PHW_FLAG_IS_SHAREABLE) +#define PMC_IS_UNALLOCATED(cpu, n) \ + (pmc_pcpu[(cpu)]->pc_hwpmcs[(n)]->phw_pmc == NULL) + + if (PMC_IS_SYSTEM_MODE(mode)) { + pmc_select_cpu(cpu); + for (n = pcd->pcd_ri; n < md->pmd_npmc; n++) { + pcd = pmc_ri_to_classdep(md, n, &adjri); + + if (!pmc_can_allocate_row(n, mode) || + !pmc_can_allocate_rowindex(p, n, cpu)) + continue; + if (!PMC_IS_UNALLOCATED(cpu, n) && + !PMC_IS_SHAREABLE_PMC(cpu, n)) + continue; + + if (pcd->pcd_allocate_pmc(cpu, adjri, pmc, pa) == 0) { + /* Success. */ + break; + } + } + } else { + /* Process virtual mode */ + for (n = pcd->pcd_ri; n < md->pmd_npmc; n++) { + pcd = pmc_ri_to_classdep(md, n, &adjri); + + if (!pmc_can_allocate_row(n, mode) || + !pmc_can_allocate_rowindex(p, n, PMC_CPU_ANY)) + continue; + + if (pcd->pcd_allocate_pmc(td->td_oncpu, adjri, pmc, + pa) == 0) { + /* Success. */ + break; + } + } + } + +#undef PMC_IS_UNALLOCATED +#undef PMC_IS_SHAREABLE_PMC + + pmc_restore_cpu_binding(&pb); + + if (n == md->pmd_npmc) { + pmc_destroy_pmc_descriptor(pmc); + return (EINVAL); + } + + /* Fill in the correct value in the ID field. */ + pmc->pm_id = PMC_ID_MAKE_ID(cpu, mode, class, n); + + PMCDBG5(PMC,ALL,2, "ev=%d class=%d mode=%d n=%d -> pmcid=%x", + pmc->pm_event, class, mode, n, pmc->pm_id); + + /* Process mode PMCs with logging enabled need log files. */ + if ((pmc->pm_flags & (PMC_F_LOG_PROCEXIT | PMC_F_LOG_PROCCSW)) != 0) + pmc->pm_flags |= PMC_F_NEEDS_LOGFILE; + + /* All system mode sampling PMCs require a log file. */ + if (PMC_IS_SAMPLING_MODE(mode) && PMC_IS_SYSTEM_MODE(mode)) + pmc->pm_flags |= PMC_F_NEEDS_LOGFILE; + + /* + * Configure global pmc's immediately. + */ + if (PMC_IS_SYSTEM_MODE(PMC_TO_MODE(pmc))) { + pmc_save_cpu_binding(&pb); + 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 = pcd->pcd_config_pmc(cpu, adjri, pmc)) != 0) { + (void)pcd->pcd_release_pmc(cpu, adjri, pmc); + pmc_destroy_pmc_descriptor(pmc); + pmc_restore_cpu_binding(&pb); + return (EPERM); + } + + pmc_restore_cpu_binding(&pb); + } + + pmc->pm_state = PMC_STATE_ALLOCATED; + pmc->pm_class = class; + + /* + * Mark row disposition. + */ + if (PMC_IS_SYSTEM_MODE(mode)) + PMC_MARK_ROW_STANDALONE(n); + else + PMC_MARK_ROW_THREAD(n); + + /* + * Register this PMC with the current thread as its owner. + */ + error = pmc_register_owner(p, pmc); + if (error != 0) { + pmc_release_pmc_descriptor(pmc); + pmc_destroy_pmc_descriptor(pmc); + return (error); + } + + /* + * Return the allocated index. + */ + pa->pm_pmcid = pmc->pm_id; + return (0); +} + /* * Main body of PMC_OP_PMCATTACH. */ @@ -3833,269 +4076,17 @@ pmc_syscall_handler(struct thread *td, void *syscall_args) /* * Allocate a PMC. */ - case PMC_OP_PMCALLOCATE: { - int adjri, n; - u_int cpu; - uint32_t caps; - struct pmc *pmc; - enum pmc_mode mode; - struct pmc_hw *phw; - struct pmc_binding pb; - struct pmc_classdep *pcd; struct pmc_op_pmcallocate pa; - if ((error = copyin(arg, &pa, sizeof(pa))) != 0) - break; - - caps = pa.pm_caps; - mode = pa.pm_mode; - cpu = pa.pm_cpu; - - if ((mode != PMC_MODE_SS && mode != PMC_MODE_SC && - mode != PMC_MODE_TS && mode != PMC_MODE_TC) || - (cpu != (u_int) PMC_CPU_ANY && cpu >= pmc_cpu_max())) { - error = EINVAL; - break; - } - - /* - * Virtual PMCs should only ask for a default CPU. - * System mode PMCs need to specify a non-default CPU. - */ - - if ((PMC_IS_VIRTUAL_MODE(mode) && cpu != (u_int) PMC_CPU_ANY) || - (PMC_IS_SYSTEM_MODE(mode) && cpu == (u_int) PMC_CPU_ANY)) { - error = EINVAL; - break; - } - - /* - * Check that an inactive CPU is not being asked for. - */ - - if (PMC_IS_SYSTEM_MODE(mode) && !pmc_cpu_is_active(cpu)) { - error = ENXIO; - break; - } - - /* - * Refuse an allocation for a system-wide PMC if this - * process has been jailed, or if this process lacks - * super-user credentials and the sysctl tunable - * 'security.bsd.unprivileged_syspmcs' is zero. - */ - - if (PMC_IS_SYSTEM_MODE(mode)) { - if (jailed(curthread->td_ucred)) { - error = EPERM; - break; - } - if (!pmc_unprivileged_syspmcs) { - error = priv_check(curthread, - PRIV_PMC_SYSTEM); - if (error) - break; - } - } - - /* - * Look for valid values for 'pm_flags' - */ - - if ((pa.pm_flags & ~(PMC_F_DESCENDANTS | PMC_F_LOG_PROCCSW | - PMC_F_LOG_PROCEXIT | PMC_F_CALLCHAIN | - PMC_F_USERCALLCHAIN)) != 0) { - error = EINVAL; - break; - } - - /* PMC_F_USERCALLCHAIN is only valid with PMC_F_CALLCHAIN */ - if ((pa.pm_flags & (PMC_F_CALLCHAIN | PMC_F_USERCALLCHAIN)) == - PMC_F_USERCALLCHAIN) { - error = EINVAL; - break; - } - - /* PMC_F_USERCALLCHAIN is only valid for sampling mode */ - if (pa.pm_flags & PMC_F_USERCALLCHAIN && - mode != PMC_MODE_TS && mode != PMC_MODE_SS) { - error = EINVAL; - break; - } - - /* process logging options are not allowed for system PMCs */ - if (PMC_IS_SYSTEM_MODE(mode) && (pa.pm_flags & - (PMC_F_LOG_PROCCSW | PMC_F_LOG_PROCEXIT))) { - error = EINVAL; - break; - } - - /* - * All sampling mode PMCs need to be able to interrupt the - * CPU. - */ - if (PMC_IS_SAMPLING_MODE(mode)) - caps |= PMC_CAP_INTERRUPT; - - /* A valid class specifier should have been passed in. */ - pcd = pmc_class_to_classdep(pa.pm_class); - if (pcd == NULL) { - error = EINVAL; - break; - } - - /* The requested PMC capabilities should be feasible. */ - if ((pcd->pcd_caps & caps) != caps) { - error = EOPNOTSUPP; - break; - } - - PMCDBG4(PMC,ALL,2, "event=%d caps=0x%x mode=%d cpu=%d", - pa.pm_ev, caps, mode, cpu); - - pmc = pmc_allocate_pmc_descriptor(); - pmc->pm_id = PMC_ID_MAKE_ID(cpu,pa.pm_mode,pa.pm_class, - PMC_ID_INVALID); - pmc->pm_event = pa.pm_ev; - pmc->pm_state = PMC_STATE_FREE; - pmc->pm_caps = caps; - pmc->pm_flags = pa.pm_flags; - - /* XXX set lower bound on sampling for process counters */ - if (PMC_IS_SAMPLING_MODE(mode)) { - /* - * Don't permit requested sample rate to be - * less than pmc_mincount. - */ - if (pa.pm_count < MAX(1, pmc_mincount)) - log(LOG_WARNING, "pmcallocate: passed sample " - "rate %ju - setting to %u\n", - (uintmax_t)pa.pm_count, - MAX(1, pmc_mincount)); - pmc->pm_sc.pm_reloadcount = MAX(MAX(1, pmc_mincount), - pa.pm_count); - } else - pmc->pm_sc.pm_initial = pa.pm_count; - - /* switch thread to CPU 'cpu' */ - pmc_save_cpu_binding(&pb); - -#define PMC_IS_SHAREABLE_PMC(cpu, n) \ - (pmc_pcpu[(cpu)]->pc_hwpmcs[(n)]->phw_state & \ - PMC_PHW_FLAG_IS_SHAREABLE) -#define PMC_IS_UNALLOCATED(cpu, n) \ - (pmc_pcpu[(cpu)]->pc_hwpmcs[(n)]->phw_pmc == NULL) - - if (PMC_IS_SYSTEM_MODE(mode)) { - pmc_select_cpu(cpu); - for (n = pcd->pcd_ri; 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)) && - pcd->pcd_allocate_pmc(cpu, adjri, pmc, - &pa) == 0) - break; - } - } else { - /* Process virtual mode */ - for (n = pcd->pcd_ri; 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 && - pcd->pcd_allocate_pmc(curthread->td_oncpu, - adjri, pmc, &pa) == 0) - break; - } - } - -#undef PMC_IS_UNALLOCATED -#undef PMC_IS_SHAREABLE_PMC - - pmc_restore_cpu_binding(&pb); - - if (n == (int) md->pmd_npmc) { - pmc_destroy_pmc_descriptor(pmc); - pmc = NULL; - error = EINVAL; + error = copyin(arg, &pa, sizeof(pa)); + if (error != 0) break; - } - - /* Fill in the correct value in the ID field */ - pmc->pm_id = PMC_ID_MAKE_ID(cpu,mode,pa.pm_class,n); - - PMCDBG5(PMC,ALL,2, "ev=%d class=%d mode=%d n=%d -> pmcid=%x", - pmc->pm_event, pa.pm_class, mode, n, pmc->pm_id); - - /* Process mode PMCs with logging enabled need log files */ - if (pmc->pm_flags & (PMC_F_LOG_PROCEXIT | PMC_F_LOG_PROCCSW)) - pmc->pm_flags |= PMC_F_NEEDS_LOGFILE; - /* All system mode sampling PMCs require a log file */ - if (PMC_IS_SAMPLING_MODE(mode) && PMC_IS_SYSTEM_MODE(mode)) - pmc->pm_flags |= PMC_F_NEEDS_LOGFILE; - - /* - * Configure global pmc's immediately - */ - - if (PMC_IS_SYSTEM_MODE(PMC_TO_MODE(pmc))) { - - pmc_save_cpu_binding(&pb); - 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 = pcd->pcd_config_pmc(cpu, adjri, pmc)) != 0) { - (void)pcd->pcd_release_pmc(cpu, adjri, pmc); - pmc_destroy_pmc_descriptor(pmc); - pmc = NULL; - pmc_restore_cpu_binding(&pb); - error = EPERM; - break; - } - - pmc_restore_cpu_binding(&pb); - } - - pmc->pm_state = PMC_STATE_ALLOCATED; - pmc->pm_class = pa.pm_class; - - /* - * mark row disposition - */ - - if (PMC_IS_SYSTEM_MODE(mode)) - PMC_MARK_ROW_STANDALONE(n); - else - PMC_MARK_ROW_THREAD(n); - - /* - * Register this PMC with the current thread as its owner. - */ - - if ((error = - pmc_register_owner(curthread->td_proc, pmc)) != 0) { - pmc_release_pmc_descriptor(pmc); - pmc_destroy_pmc_descriptor(pmc); - pmc = NULL; + error = pmc_do_op_pmcallocate(td, &pa); + if (error != 0) break; - } - - - /* - * Return the allocated index. - */ - - pa.pm_pmcid = pmc->pm_id; error = copyout(&pa, arg, sizeof(pa)); }