From nobody Tue Jul 28 15:01:28 2026 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 4h8dvr6Gb7z6msr0 for ; Tue, 28 Jul 2026 15:01:28 +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 "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h8dvr2rH9z3LCd for ; Tue, 28 Jul 2026 15:01:28 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785250888; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=YQ4SGCeZd9dc7VaxDMG47usUDsoZQUMNdLrFA+gh5Hk=; b=TKT1Y56wwCfVGIVs55it71zU8psNSXKVP33vnY0PZiDyKAAnn12nkG1hrFx70hJWfzAm8n xTo+66lbZHHjdjTYMqMYVlV7cB8o7EF5KeZlj3anCe//QFlB6JRpwSmBL+px+9HPF01qbN g6BT8GFb6qbgHcYnaEOsm3DGxrSJgSy3kKXndClgDSAPLECUqgpsJbQUUavMu76lrGqYya U1ZcXwKrZiOVRHthnYtr68V+MsuF+50Sog4WiG42YZqOjIr8HYRl3LfxVbuEG25Od0OMWn SyZx6dgmTNK6FW45ZmnPYMDBGm30wFIm7AosGbpHXgR7TVi49PDZel8vk/sL7g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1785250888; a=rsa-sha256; cv=none; b=MY97+brZ/VgQkylJp+o501upeVElURH6Q8j9cJBbeMJRLy4E2zkvgKhiThH1R6ws3Qv7tr c4/k7jq4sQBPDkIOhJ6KDyorCbk62kaY/6ehLRDwpzQBPzD/ciOtNlo5oH/oIlzGTHNgty wH5E9ObhtqC4OZBWFDs2V7X150C4bRMZxBHpXFPVY7pYHnfC9HDWMThh9tbGVOFsdMdxAO dZ+EXDw83u9vPqnJdklOE7Chss6VmBQ+Zk122VZPkqr1kZZrLV7sqrmdcMn7Fr0A4wvWc9 GnNGkvSecAwyTR7RInUGWM7E50++uIjWR1UK5dnipCnTvn/HKBiLjQR0gcULxA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785250888; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=YQ4SGCeZd9dc7VaxDMG47usUDsoZQUMNdLrFA+gh5Hk=; b=svGZvcS0iq7legqJAJesk9YxdLwQjdo/LLbhedEH09p6Zy7dQymgOtP3S2H1/V3eVPeW/H SpcKKG47nOqtCwCGeRfKAHt7sEUBRNHH3G9EAv3ssrbxOR9+r6VmZKq+97Yaho/BLoD5Gg 3W+DbJAYNbJSR9MBZrRdpdTVtp/DsyhSl7ojuIG0endix8w6cYQSgEBRL4gIEO/QidL6YI 6A9q0uCGijFNLJhUxgYm4tIUaa+JjKqBrNUh2AjQNywXLPnZFm67u+VzzChaUUJ4uZYvGC ZsfqRhkDCNBpiulDKoCCvOWJAu9xiHfzkU9KsG5B/6qBx2bTfwiDiiseKTvSHQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h8dvr1kCNzkQ0 for ; Tue, 28 Jul 2026 15:01:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1f1ac by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 28 Jul 2026 15:01:28 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Andre Silva From: Mitchell Horne Subject: git: 3fdd05c61216 - main - libpmc: userland support and pmc.rapl.3 for the RAPL class 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: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list 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: 3fdd05c612169d56c30b90d72533b75383210e81 Auto-Submitted: auto-generated Date: Tue, 28 Jul 2026 15:01:28 +0000 Message-Id: <6a68c448.1f1ac.2c28beec@gitrepo.freebsd.org> The branch main has been updated by mhorne: URL: https://cgit.FreeBSD.org/src/commit/?id=3fdd05c612169d56c30b90d72533b75383210e81 commit 3fdd05c612169d56c30b90d72533b75383210e81 Author: Andre Silva AuthorDate: 2026-07-28 14:52:22 +0000 Commit: Mitchell Horne CommitDate: 2026-07-28 14:54:26 +0000 libpmc: userland support and pmc.rapl.3 for the RAPL class Register PMC_CLASS_RAPL in libpmc: event table, allocator, class-table descriptor, and the event-name/class-listing lookups, all x86-guarded and modeled on the TSC class. Energy events are read-only and unqualified. The class prefix (RAPL-) supplies the friendly spelling, so pmcstat -S rapl-energy-pkg resolves to the canonical ENERGY_PKG event. Add a pmc.rapl.3 manual page documenting the events, counter scope, the microjoule unit and wrap handling, and the NUMA/package domain mapping; link it from pmc.3. Reviewed by: mhorne Discussed with: Ali Mashtizadeh Sponsored by: AMD Differential Revision: https://reviews.freebsd.org/D58029 --- lib/libpmc/Makefile | 1 + lib/libpmc/libpmc.c | 35 +++++++++++++ lib/libpmc/pmc.3 | 8 +++ lib/libpmc/pmc.rapl.3 | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+) diff --git a/lib/libpmc/Makefile b/lib/libpmc/Makefile index 442efdc3d9c0..d86191cc35cb 100644 --- a/lib/libpmc/Makefile +++ b/lib/libpmc/Makefile @@ -77,6 +77,7 @@ MAN+= pmc.iaf.3 MAN+= pmc.ibs.3 MAN+= pmc.ivybridge.3 MAN+= pmc.ivybridgexeon.3 +MAN+= pmc.rapl.3 MAN+= pmc.sandybridge.3 MAN+= pmc.sandybridgeuc.3 MAN+= pmc.sandybridgexeon.3 diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c index 63228773216e..5fc4630540fc 100644 --- a/lib/libpmc/libpmc.c +++ b/lib/libpmc/libpmc.c @@ -58,6 +58,8 @@ static int ibs_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); +static int rapl_allocate_pmc(enum pmc_event _pe, char *_ctrspec, + struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__arm__) static int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, @@ -191,6 +193,11 @@ static const struct pmc_event_descr tsc_event_table[] = __PMC_EV_ALIAS_TSC() }; +static const struct pmc_event_descr rapl_event_table[] = +{ + __PMC_EV_RAPL() +}; + #undef PMC_CLASS_TABLE_DESC #define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ static const struct pmc_class_descr NAME##_class_table_descr = \ @@ -208,6 +215,7 @@ static const struct pmc_class_descr NAME##_class_table_descr = \ PMC_CLASS_TABLE_DESC(k8, K8, k8, k8); PMC_CLASS_TABLE_DESC(ibs, IBS, ibs, ibs); PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); +PMC_CLASS_TABLE_DESC(rapl, RAPL, rapl, rapl); #endif #if defined(__arm__) PMC_CLASS_TABLE_DESC(cortex_a8, ARMV7, cortex_a8, armv7); @@ -879,6 +887,22 @@ tsc_allocate_pmc(enum pmc_event pe, char *ctrspec, return (0); } + +static int +rapl_allocate_pmc(enum pmc_event pe, char *ctrspec, + struct pmc_op_pmcallocate *pmc_config) +{ + if (pe < PMC_EV_RAPL_FIRST || pe > PMC_EV_RAPL_LAST) + return (-1); + + /* RAPL events must be unqualified. */ + if (ctrspec != NULL && *ctrspec != '\0') + return (-1); + + pmc_config->pm_caps |= PMC_CAP_READ; + + return (0); +} #endif static struct pmc_event_alias generic_aliases[] = { @@ -1435,6 +1459,10 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, ev = tsc_event_table; count = PMC_EVENT_TABLE_SIZE(tsc); break; + case PMC_CLASS_RAPL: + ev = rapl_event_table; + count = PMC_EVENT_TABLE_SIZE(rapl); + break; case PMC_CLASS_K8: ev = k8_event_table; count = PMC_EVENT_TABLE_SIZE(k8); @@ -1643,6 +1671,10 @@ pmc_init(void) pmc_class_table[n++] = &tsc_class_table_descr; break; + case PMC_CLASS_RAPL: + pmc_class_table[n++] = &rapl_class_table_descr; + break; + case PMC_CLASS_K8: pmc_class_table[n++] = &k8_class_table_descr; break; @@ -1915,6 +1947,9 @@ _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) } else if (pe == PMC_EV_TSC_TSC) { ev = tsc_event_table; evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); + } else if (pe >= PMC_EV_RAPL_FIRST && pe <= PMC_EV_RAPL_LAST) { + ev = rapl_event_table; + evfence = rapl_event_table + PMC_EVENT_TABLE_SIZE(rapl); } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { ev = soft_event_table; evfence = soft_event_table + soft_event_info.pm_nevent; diff --git a/lib/libpmc/pmc.3 b/lib/libpmc/pmc.3 index cb28e0b786b9..b04c2d39cf69 100644 --- a/lib/libpmc/pmc.3 +++ b/lib/libpmc/pmc.3 @@ -233,6 +233,12 @@ Family 10h and above. Programmable hardware counters present in .Tn "AMD Athlon64" CPUs. +.It Li PMC_CLASS_RAPL +RAPL energy counters present in +.Tn AMD +and +.Tn Intel +CPUs. .It Li PMC_CLASS_TSC The timestamp counter on i386 and amd64 architecture CPUs. .It Li PMC_CLASS_ARMV7 @@ -498,6 +504,7 @@ following manual pages: .It Li PMC_CLASS_IAP Ta Xr pmc.atom 3 , Xr pmc.core 3 , Xr pmc.core2 3 .It Li PMC_CLASS_IBS Ta Xr pmc.ibs 3 .It Li PMC_CLASS_K8 Ta Xr pmc.amd 3 +.It Li PMC_CLASS_RAPL Ta Xr pmc.rapl 3 .It Li PMC_CLASS_TSC Ta Xr pmc.tsc 3 .El .Ss Event Name Aliases @@ -551,6 +558,7 @@ Doing otherwise is unsupported. .Xr pmc.ibs 3 , .Xr pmc.ivybridge 3 , .Xr pmc.ivybridgexeon 3 , +.Xr pmc.rapl 3 , .Xr pmc.sandybridge 3 , .Xr pmc.sandybridgeuc 3 , .Xr pmc.sandybridgexeon 3 , diff --git a/lib/libpmc/pmc.rapl.3 b/lib/libpmc/pmc.rapl.3 new file mode 100644 index 000000000000..e49d9845bbba --- /dev/null +++ b/lib/libpmc/pmc.rapl.3 @@ -0,0 +1,138 @@ +.\" +.\" Copyright (c) 2026 Advanced Micro Devices, Inc. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd July 6, 2026 +.Dt PMC.RAPL 3 +.Os +.Sh NAME +.Nm pmc.rapl +.Nd measurements using RAPL energy counters +.Sh LIBRARY +.Lb libpmc +.Sh SYNOPSIS +.In pmc.h +.Sh DESCRIPTION +.Tn AMD +and +.Tn Intel +processors report cumulative energy consumption through the RAPL +(Running Average Power Limit) machine specific registers. +The +.Li PMC_CLASS_RAPL +class exposes these registers as read-only 64-bit counters that may +only be allocated in system-wide counting mode +.Pq Li PMC_MODE_SC . +Counter values are cumulative energy in microjoules. +The kernel scales the raw hardware counts by the hardware energy unit, +so no further conversion is required. +.Pp +A counter's accumulator is not reset when a PMC is allocated or +released; it reflects energy consumed since the counters began +accumulating and is reset only when the +.Xr hwpmc 4 +module is unloaded. +An individual reading is therefore meaningful only as a difference +between two samples. +.Pp +The hardware counters are 32 bits wide and wrap frequently under load. +The RAPL PMC class instead provides virtual 64-bit counters that are +guaranteed to be monotonic, by periodically sampling the hardware +counters while at least one RAPL PMC is allocated. +.Pp +RAPL events do not support further event qualifiers. +.Ss Event Specifiers +The following event names are supported: +.Bl -tag -width indent +.It Li rapl-energy-pkg +Energy consumed by the processor package (socket) the counter is bound +to. +.It Li rapl-energy-cores +On +.Tn AMD +processors, energy consumed by the physical core the counter is bound +to. +On +.Tn Intel +processors, energy consumed by the PP0 (all cores) power plane of the +package, i.e. a package-scoped value. +.It Li rapl-energy-dram +Energy consumed by the DRAM domain of the package. +Present only on +.Tn Intel +processors that implement the DRAM domain, typically server parts. +.El +.Ss Counter Scope +RAPL counters measure package or core power domains, not individual +CPUs: every CPU of a domain reads the same underlying counter. +Consumers should bind one PMC per domain and must not sum readings +from CPUs that share a domain. +.Pp +The class advertises the +.Li PMC_CAP_DOMWIDE +capability, which makes +.Xr pmcstat 8 +allocate one counter per NUMA domain instead of one per CPU. +NUMA domains follow the firmware memory policy and need not match +packages, in either direction: +.Bl -bullet +.It +With several NUMA domains per package (for example +.Tn AMD +NPS2/NPS4 or +.Tn Intel +Sub-NUMA Clustering), +.Xr pmcstat 8 +allocates one counter per domain, so package-scoped counters within +one package alias each other: each reading is correct on its own, +but they must not be summed. +.It +With a single NUMA domain spanning several packages (for example +.Tn AMD +NPS0 memory interleaving, NUMA disabled in firmware, or a kernel +built without NUMA support), +.Xr pmcstat 8 +allocates only one counter, on the first configured CPU, and the +remaining packages are silently not measured. +.El +.Pp +For explicit placement, allocate one system-scope PMC per package +with +.Xr pmc_allocate 3 , +or give +.Xr pmcstat 8 +one +.Fl c Ar cpu +and +.Fl s Ar event +pair per package, for example on a two-socket system whose second +package starts at CPU 64: +.Dl pmcstat -c 0 -s rapl-energy-pkg -c 64 -s rapl-energy-pkg +A single +.Fl c +list naming several CPUs does not achieve this: for +.Li PMC_CAP_DOMWIDE +counters +.Xr pmcstat 8 +honors only the first CPU of the list. +.Ss Privilege +Allocating a RAPL PMC always requires the +.Li PRIV_PMC_SYSTEM +privilege, regardless of the +.Va security.bsd.unprivileged_syspmcs +sysctl: fine-grained energy readings form a power side channel +(PLATYPUS, CVE-2020-8694 and CVE-2020-12912). +Unprivileged allocation requests fail with +.Er EPERM . +.Sh SEE ALSO +.Xr pmc 3 , +.Xr pmc.tsc 3 , +.Xr pmc_allocate 3 , +.Xr pmc_read 3 , +.Xr pmclog 3 , +.Xr hwpmc 4 , +.Xr pmcstat 8 +.Sh HISTORY +The RAPL PMC class first appeared in +.Fx 16.0 .