Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F163306911
D56914.id177522.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D56914.id177522.diff
View Options
diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c
--- a/lib/libpmc/libpmc.c
+++ b/lib/libpmc/libpmc.c
@@ -39,6 +39,7 @@
#include <ctype.h>
#include <errno.h>
#include <err.h>
+#include <stdbool.h>
#include <fcntl.h>
#include <pmc.h>
#include <stdio.h>
@@ -700,13 +701,14 @@
struct pmc_op_pmcallocate *pmc_config)
{
char *e, *p, *q;
- uint64_t ctl, ldlat;
- u_int ibs_features;
- u_int regs[4];
+ uint64_t ctl, ctl2, ldlat, addr63, fetchlat;
+ bool seen_l3miss, seen_randomize, seen_ldlat, seen_fetchlat;
+ bool seen_opcount, seen_addr63, seen_streamstore;
pmc_config->pm_caps |=
(PMC_CAP_SYSTEM | PMC_CAP_EDGE | PMC_CAP_PRECISE);
pmc_config->pm_md.pm_ibs.ibs_ctl = 0;
+ pmc_config->pm_md.pm_ibs.ibs_ctl2 = 0;
/* setup parsing tables */
switch (pe) {
@@ -725,25 +727,79 @@
return (-1);
}
- /* Read the ibs feature flags */
- ibs_features = 0;
- do_cpuid(0x80000000, regs);
- if (regs[0] >= CPUID_IBSID) {
- do_cpuid(CPUID_IBSID, regs);
- ibs_features = regs[0];
- }
+ /*
+ * Capability gating is kernel-side; we only check syntax
+ * and value ranges here.
+ */
- /* parse parameters */
ctl = 0;
+ ctl2 = 0;
+ seen_l3miss = false;
+ seen_randomize = false;
+ seen_ldlat = false;
+ seen_fetchlat = false;
+ seen_opcount = false;
+ seen_addr63 = false;
+ seen_streamstore = false;
if (pe == PMC_EV_IBS_FETCH) {
while ((p = strsep(&ctrspec, ",")) != NULL) {
if (KWMATCH(p, "l3miss")) {
- if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) == 0)
+ if (seen_l3miss)
return (-1);
+ seen_l3miss = true;
ctl |= IBS_FETCH_CTL_L3MISSONLY;
} else if (KWMATCH(p, "randomize")) {
+ if (seen_randomize)
+ return (-1);
+ seen_randomize = true;
ctl |= IBS_FETCH_CTL_RANDOMIZE;
+ } else if (KWPREFIXMATCH(p, "fetchlat=")) {
+ if (seen_fetchlat)
+ return (-1);
+ seen_fetchlat = true;
+
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return (-1);
+
+ fetchlat = strtoull(q, &e, 0);
+ if (e == q || *e != '\0')
+ return (-1);
+
+ if (fetchlat < IBS_FETCH_CTL2_LAT_MIN ||
+ fetchlat > IBS_FETCH_CTL2_LAT_MAX)
+ return (-1);
+ if ((fetchlat % IBS_FETCH_CTL2_LAT_STEP) != 0)
+ return (-1);
+
+ ctl2 |= IBS_FETCH_CTL2_LAT_TO_CTL(fetchlat);
+ /*
+ * Defence-in-depth round-trip check: catch any
+ * future macro/range drift that would silently
+ * truncate fetchlat to the "no filter" encoding.
+ */
+ if ((ctl2 & IBS_FETCH_CTL2_LATFILTERMASK) == 0)
+ return (-1);
+ } else if (KWPREFIXMATCH(p, "addr63=")) {
+ if (seen_addr63)
+ return (-1);
+ seen_addr63 = true;
+
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return (-1);
+
+ addr63 = strtoull(q, &e, 0);
+ if (e == q || *e != '\0')
+ return (-1);
+
+ if (addr63 == 0)
+ ctl2 |= IBS_FETCH_CTL2_EXCLADDR63EQ1;
+ else if (addr63 == 1)
+ ctl2 |= IBS_FETCH_CTL2_EXCLADDR63EQ0;
+ else
+ return (-1);
} else {
return (-1);
}
@@ -757,10 +813,14 @@
} else {
while ((p = strsep(&ctrspec, ",")) != NULL) {
if (KWMATCH(p, "l3miss")) {
+ if (seen_l3miss)
+ return (-1);
+ seen_l3miss = true;
ctl |= IBS_OP_CTL_L3MISSONLY;
} else if (KWPREFIXMATCH(p, "ldlat=")) {
- if ((ibs_features & CPUID_IBSID_IBSLOADLATENCYFILT) == 0)
+ if (seen_ldlat)
return (-1);
+ seen_ldlat = true;
q = strchr(p, '=');
if (*++q == '\0') /* skip '=' */
@@ -786,10 +846,35 @@
ctl |= IBS_OP_CTL_LDLAT_TO_CTL(ldlat);
ctl |= IBS_OP_CTL_L3MISSONLY | IBS_OP_CTL_LATFLTEN;
} else if (KWMATCH(p, "opcount")) {
- if ((ibs_features & CPUID_IBSID_OPCNT) == 0)
+ if (seen_opcount)
return (-1);
+ seen_opcount = true;
ctl |= IBS_OP_CTL_COUNTERCONTROL;
+ } else if (KWPREFIXMATCH(p, "addr63=")) {
+ if (seen_addr63)
+ return (-1);
+ seen_addr63 = true;
+
+ q = strchr(p, '=');
+ if (*++q == '\0') /* skip '=' */
+ return (-1);
+
+ addr63 = strtoull(q, &e, 0);
+ if (e == q || *e != '\0')
+ return (-1);
+
+ if (addr63 == 0)
+ ctl2 |= IBS_OP_CTL2_EXCLRIP63EQ1;
+ else if (addr63 == 1)
+ ctl2 |= IBS_OP_CTL2_EXCLRIP63EQ0;
+ else
+ return (-1);
+ } else if (KWMATCH(p, "streamstore")) {
+ if (seen_streamstore)
+ return (-1);
+ seen_streamstore = true;
+ ctl2 |= IBS_OP_CTL2_STRMSTFILTER;
} else {
return (-1);
}
@@ -799,15 +884,12 @@
pmc_config->pm_count > IBS_OP_MAX_RATE)
return (-1);
- if (((ibs_features & CPUID_IBSID_OPCNTEXT) == 0) &&
- (pmc_config->pm_count > IBS_OP_MAX_RATE_PREEXT))
- return (-1);
-
ctl |= IBS_OP_INTERVAL_TO_CTL(pmc_config->pm_count);
}
pmc_config->pm_md.pm_ibs.ibs_ctl |= ctl;
+ pmc_config->pm_md.pm_ibs.ibs_ctl2 |= ctl2;
return (0);
}
diff --git a/lib/libpmc/pmc.ibs.3 b/lib/libpmc/pmc.ibs.3
--- a/lib/libpmc/pmc.ibs.3
+++ b/lib/libpmc/pmc.ibs.3
@@ -98,24 +98,81 @@
Event specifiers for AMD IBS can have the following optional
qualifiers:
.Bl -tag -width "ldlat=value"
+.It Li addr63= Ns Ar bit
+Valid for both
+.Ar ibs-fetch
+and
+.Ar ibs-op
+events.
+Configure the counter to only sample events whose virtual address has bit 63
+equal to
+.Ar bit
+.Pq Li 0 No or Li 1 .
+Requires Zen6 IBS extensions
+.Pq CPUID Fn Fn8000_0001B
+.Va EAX[IbsAddrBit63Filtering] ,
+and is rejected when the CPU does not advertise support.
+.It Li fetchlat= Ns Ar value
+Valid only for
+.Ar ibs-fetch
+events.
+Configure the counter to only sample fetches whose latency is greater than or
+equal to
+.Ar value
+core clock cycles.
+The valid range is 128 to 1920 in steps of 128.
+Requires Zen6 IBS extensions
+.Pq CPUID Fn Fn8000_0001B
+.Va EAX[IbsFetchLatencyFiltering] ,
+and is rejected when the CPU does not advertise support.
.It Li l3miss
+Valid for both
+.Ar ibs-fetch
+and
+.Ar ibs-op
+events.
Configure IBS to only sample if an l3miss occurred.
.It Li ldlat= Ns Ar value
+Valid only for
+.Ar ibs-op
+events.
Configure the counter to only sample events with load latencies above
.Ar ldlat .
IBS only supports filtering latencies that are a multiple of 128 and between
128 and 2048.
-Load latency filtering can only be used with ibs-op events and imply the
-l3miss qualifier.
+On pre-Zen6 hardware this qualifier implies the
+.Li l3miss
+qualifier; on Zen6 and later, latency-only filtering without
+.Li l3miss
+is permitted.
.It Li opcount
+Valid only for
+.Ar ibs-op
+events.
Count ops rather than cycles.
.It Li randomize
+Valid only for
+.Ar ibs-fetch
+events.
Randomize the sampling rate.
+.It Li streamstore
+Valid only for
+.Ar ibs-op
+events.
+Configure the counter to only sample streaming
+.Pq non-temporal
+store operations.
+Requires Zen6 IBS extensions
+.Pq CPUID Fn Fn8000_0001B
+.Va EAX[IbsStrmStAndRmtSocket] ,
+and is rejected when the CPU does not advertise support.
.El
.Ss AMD IBS Events Specifiers
The IBS event class provides only two event specifiers:
.Bl -tag -width indent
.It Li ibs-fetch Xo
+.Op ,addr63= Ns Ar bit
+.Op ,fetchlat= Ns Ar value
.Op ,l3miss
.Op ,randomize
.Xc
@@ -124,9 +181,11 @@
.Ar randomize
qualifier randomly sets the bottom four bits of the sample rate.
.It Li ibs-op Xo
+.Op ,addr63= Ns Ar bit
.Op ,l3miss
.Op ,ldlat= Ns Ar ldlat
.Op ,opcount
+.Op ,streamstore
.Xc
Collect performance samples during instruction execution.
The
diff --git a/sys/dev/hwpmc/hwpmc_ibs.h b/sys/dev/hwpmc/hwpmc_ibs.h
--- a/sys/dev/hwpmc/hwpmc_ibs.h
+++ b/sys/dev/hwpmc/hwpmc_ibs.h
@@ -50,6 +50,12 @@
#define CPUID_IBSID_IBSOPDATA4 0x00000400 /* IBS OP DATA4 */
#define CPUID_IBSID_ZEN4IBSEXTENSIONS 0x00000800 /* IBS Zen 4 Extensions */
#define CPUID_IBSID_IBSLOADLATENCYFILT 0x00001000 /* Load Latency Filtering */
+#define CPUID_IBSID_IBSDIS 0x00002000 /* Alternate IBS Disable */
+#define CPUID_IBSID_FETCHLATFILTERING 0x00004000 /* Fetch Latency Filter */
+#define CPUID_IBSID_ADDRBIT63FILTERING 0x00008000 /* Addr Bit 63 Filter */
+#define CPUID_IBSID_STRMSTANDRMTSOCKET 0x00010000 /* StrmSt + RmtSocket */
+#define CPUID_IBSID_BUFFERV1 0x00020000 /* IBS Buffering V1 */
+#define CPUID_IBSID_MEMPROFILERV1 0x00040000 /* IBS Memory Profiler V1 */
#define CPUID_IBSID_IBSUPDTDDTLBSTATS 0x00080000 /* Simplified DTLB Stats */
/*
@@ -107,11 +113,27 @@
#define IBS_FETCH_PHYSADDR 0xC0011032 /* Fetch Physical Address */
#define IBS_FETCH_EXTCTL 0xC001103C /* Fetch Control Extended */
+/* IBS Fetch Control 2 (Zen6) */
+#define IBS_FETCH_CTL2 0xC001103F /* IBS Fetch Control 2 */
+#define IBS_FETCH_CTL2_DISABLE (1ULL << 0) /* IBS Fetch Disable */
+#define IBS_FETCH_CTL2_LATFILTERMASK (0xFULL << 1) /* Fetch Latency Filter */
+#define IBS_FETCH_CTL2_EXCLADDR63EQ1 (1ULL << 5) /* Exclude addr bit63=1 */
+#define IBS_FETCH_CTL2_EXCLADDR63EQ0 (1ULL << 6) /* Exclude addr bit63=0 */
+#define IBS_FETCH_CTL2_ADDR63MASK (IBS_FETCH_CTL2_EXCLADDR63EQ0 | \
+ IBS_FETCH_CTL2_EXCLADDR63EQ1)
+
+#define IBS_FETCH_CTL2_LAT_MIN 128
+#define IBS_FETCH_CTL2_LAT_MAX 1920
+#define IBS_FETCH_CTL2_LAT_STEP 128
+#define IBS_FETCH_CTL2_LAT_TO_CTL(_l) ((((_l) >> 7) & 0xFULL) << 1)
+#define IBS_FETCH_CTL2_CTL_TO_LAT(_c) ((((_c) >> 1) & 0xFULL) << 7)
+
#define PMC_MPIDX_FETCH_CTL 0
#define PMC_MPIDX_FETCH_EXTCTL 1
#define PMC_MPIDX_FETCH_LINADDR 2
#define PMC_MPIDX_FETCH_PHYSADDR 3
#define PMC_MPIDX_FETCH_MAX (PMC_MPIDX_FETCH_PHYSADDR + 1)
+#define PMC_MPIDX_FETCH_CTL2 4
/* IBS Execution Control */
#define IBS_OP_CTL 0xC0011033 /* IBS Execution Control */
@@ -148,6 +170,8 @@
#define IBS_OP_DATA_RETURN (1ULL << 34) /* Return */
#define IBS_OP_DATA2 0xC0011036 /* IBS Op Data 2 */
+#define IBS_OP_DATA2_RMTSOCKET (1ULL << 9) /* Remote Socket */
+#define IBS_OP_DATA2_STRMST (1ULL << 8) /* Streaming Store */
#define IBS_OP_DATA3 0xC0011037 /* IBS Op Data 3 */
#define IBS_OP_DATA3_DCPHYADDRVALID (1ULL << 18) /* DC Physical Address */
#define IBS_OP_DATA3_DCLINADDRVALID (1ULL << 17) /* DC Linear Address */
@@ -169,6 +193,15 @@
#define IBS_OP_DATA4 0xC001103D /* IBS Op Data 4 */
#define IBS_OP_DATA4_LDRESYNC (1ULL << 0) /* Load Resync */
+/* IBS Execution Control 2 (Zen6) */
+#define IBS_OP_CTL2 0xC001103E /* IBS Execution Control 2 */
+#define IBS_OP_CTL2_DISABLE (1ULL << 0) /* IBS Execution Disable */
+#define IBS_OP_CTL2_EXCLRIP63EQ0 (1ULL << 1) /* Exclude RIP bit63=0 */
+#define IBS_OP_CTL2_EXCLRIP63EQ1 (1ULL << 2) /* Exclude RIP bit63=1 */
+#define IBS_OP_CTL2_STRMSTFILTER (1ULL << 3) /* Streaming Store Filter */
+#define IBS_OP_CTL2_RIP63MASK (IBS_OP_CTL2_EXCLRIP63EQ0 | \
+ IBS_OP_CTL2_EXCLRIP63EQ1)
+
#define PMC_MPIDX_OP_CTL 0
#define PMC_MPIDX_OP_RIP 1
#define PMC_MPIDX_OP_DATA 2
@@ -179,6 +212,7 @@
#define PMC_MPIDX_OP_TGT_RIP 7
#define PMC_MPIDX_OP_DATA4 8
#define PMC_MPIDX_OP_MAX (PMC_MPIDX_OP_DATA4 + 1)
+#define PMC_MPIDX_OP_CTL2 9
/*
* IBS data is encoded as using the multipart flag in the existing callchain
diff --git a/sys/dev/hwpmc/hwpmc_ibs.c b/sys/dev/hwpmc/hwpmc_ibs.c
--- a/sys/dev/hwpmc/hwpmc_ibs.c
+++ b/sys/dev/hwpmc/hwpmc_ibs.c
@@ -60,9 +60,15 @@
static uint64_t ibs_features;
static uint64_t ibs_fetch_allowed_mask;
static uint64_t ibs_op_allowed_mask;
+static uint64_t ibs_fetch_ctl2_allowed_mask;
+static uint64_t ibs_op_ctl2_allowed_mask;
+static bool ibs_fetch_ctl2_supported;
+static bool ibs_op_ctl2_supported;
static uint64_t ibs_fetch_extra_mask;
static uint64_t ibs_op_extra_mask;
+static uint64_t ibs_fetch_ctl2_extra_mask;
+static uint64_t ibs_op_ctl2_extra_mask;
SYSCTL_DECL(_kern_hwpmc);
@@ -74,6 +80,14 @@
&ibs_op_extra_mask, 0,
"Extra allowed bits in the IBS op control MSR (override; default 0)");
+SYSCTL_U64(_kern_hwpmc, OID_AUTO, ibs_fetch_ctl2_extra_mask, CTLFLAG_RDTUN,
+ &ibs_fetch_ctl2_extra_mask, 0,
+ "Extra allowed bits in the IBS fetch control 2 MSR (override; default 0)");
+
+SYSCTL_U64(_kern_hwpmc, OID_AUTO, ibs_op_ctl2_extra_mask, CTLFLAG_RDTUN,
+ &ibs_op_ctl2_extra_mask, 0,
+ "Extra allowed bits in the IBS op control 2 MSR (override; default 0)");
+
/*
* Per-processor information
*/
@@ -92,8 +106,10 @@
{
ibs_fetch_allowed_mask = IBS_FETCH_ALLOWED_MASK_BASE;
+ ibs_fetch_ctl2_allowed_mask = 0;
ibs_op_allowed_mask = IBS_OP_CTL_MAXCNTBASEMASK;
+ ibs_op_ctl2_allowed_mask = 0;
if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) != 0)
ibs_fetch_allowed_mask |= IBS_FETCH_CTL_L3MISSONLY;
@@ -106,6 +122,29 @@
if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) != 0)
ibs_op_allowed_mask |= IBS_OP_CTL_L3MISSONLY;
+
+ if ((ibs_features & CPUID_IBSID_FETCHLATFILTERING) != 0)
+ ibs_fetch_ctl2_allowed_mask |= IBS_FETCH_CTL2_LATFILTERMASK;
+
+ if ((ibs_features & CPUID_IBSID_ADDRBIT63FILTERING) != 0) {
+ ibs_fetch_ctl2_allowed_mask |= IBS_FETCH_CTL2_ADDR63MASK;
+ ibs_op_ctl2_allowed_mask |= IBS_OP_CTL2_RIP63MASK;
+ }
+
+ if ((ibs_features & CPUID_IBSID_STRMSTANDRMTSOCKET) != 0)
+ ibs_op_ctl2_allowed_mask |= IBS_OP_CTL2_STRMSTFILTER;
+
+ if ((ibs_features & CPUID_IBSID_IBSDIS) != 0) {
+ ibs_fetch_ctl2_allowed_mask |= IBS_FETCH_CTL2_DISABLE;
+ ibs_op_ctl2_allowed_mask |= IBS_OP_CTL2_DISABLE;
+ }
+
+ /*
+ * ctl2 MSRs only exist on Zen6; writing them on older silicon
+ * would #GP.
+ */
+ ibs_fetch_ctl2_supported = (ibs_fetch_ctl2_allowed_mask != 0);
+ ibs_op_ctl2_supported = (ibs_op_ctl2_allowed_mask != 0);
}
static int
@@ -128,7 +167,12 @@
if ((config & IBS_OP_CTL_LATFLTEN) != 0) {
if ((ibs_features & CPUID_IBSID_IBSLOADLATENCYFILT) == 0)
return (EINVAL);
- if ((config & IBS_OP_CTL_L3MISSONLY) == 0)
+ /*
+ * Zen6 decouples L3MISSONLY from load-latency filtering
+ * (AMD pub 69205); enforce the pairing only on older parts.
+ */
+ if ((ibs_features & CPUID_IBSID_IBSDIS) == 0 &&
+ (config & IBS_OP_CTL_L3MISSONLY) == 0)
return (EINVAL);
allowed_mask |= IBS_OP_CTL_LDLATMASK | IBS_OP_CTL_L3MISSONLY;
@@ -143,16 +187,84 @@
}
static int
-ibs_validate_pmc_config(int ri, uint64_t config)
+ibs_validate_fetch_ctl2_config(uint64_t config)
+{
+ uint64_t allowed_mask;
+
+ if (config == 0)
+ return (0);
+
+ if (!ibs_fetch_ctl2_supported)
+ return (EXTERROR(EINVAL,
+ "IBS fetch ctl2 features are not supported on this CPU"));
+
+ allowed_mask = ibs_fetch_ctl2_allowed_mask | ibs_fetch_ctl2_extra_mask;
+
+ if ((config & ~allowed_mask) != 0)
+ return (EXTERROR(EINVAL,
+ "IBS fetch ctl2 config 0x%jx has bits outside allowed"
+ " mask 0x%jx", (uint64_t)config, (uint64_t)allowed_mask));
+
+ if ((config & IBS_FETCH_CTL2_DISABLE) != 0)
+ return (EXTERROR(EINVAL,
+ "IBS fetch ctl2 DISABLE bit is reserved for the kernel"));
+
+ if ((config & IBS_FETCH_CTL2_ADDR63MASK) == IBS_FETCH_CTL2_ADDR63MASK)
+ return (EXTERROR(EINVAL,
+ "IBS fetch ctl2 cannot exclude both addr63=0 and"
+ " addr63=1"));
+
+ return (0);
+}
+
+static int
+ibs_validate_op_ctl2_config(uint64_t config)
+{
+ uint64_t allowed_mask;
+
+ if (config == 0)
+ return (0);
+
+ if (!ibs_op_ctl2_supported)
+ return (EXTERROR(EINVAL,
+ "IBS op ctl2 features are not supported on this CPU"));
+
+ allowed_mask = ibs_op_ctl2_allowed_mask | ibs_op_ctl2_extra_mask;
+
+ if ((config & ~allowed_mask) != 0)
+ return (EXTERROR(EINVAL,
+ "IBS op ctl2 config 0x%jx has bits outside allowed mask"
+ " 0x%jx", (uint64_t)config, (uint64_t)allowed_mask));
+
+ if ((config & IBS_OP_CTL2_DISABLE) != 0)
+ return (EXTERROR(EINVAL,
+ "IBS op ctl2 DISABLE bit is reserved for the kernel"));
+
+ if ((config & IBS_OP_CTL2_RIP63MASK) == IBS_OP_CTL2_RIP63MASK)
+ return (EXTERROR(EINVAL,
+ "IBS op ctl2 cannot exclude both addr63=0 and addr63=1"));
+
+ return (0);
+}
+
+static int
+ibs_validate_pmc_config(int ri, uint64_t config, uint64_t config2)
{
+ int error;
switch (ri) {
case IBS_PMC_FETCH:
- return (ibs_validate_fetch_config(config));
+ error = ibs_validate_fetch_config(config);
+ if (error != 0)
+ return (error);
+ return (ibs_validate_fetch_ctl2_config(config2));
case IBS_PMC_OP:
- return (ibs_validate_op_config(config));
+ error = ibs_validate_op_config(config);
+ if (error != 0)
+ return (error);
+ return (ibs_validate_op_ctl2_config(config2));
default:
- return (EINVAL);
+ return (EXTERROR(EINVAL, "invalid IBS PMC index %d", ri));
}
}
@@ -266,7 +378,7 @@
ibs_allocate_pmc(int cpu __unused, int ri, struct pmc *pm,
const struct pmc_op_pmcallocate *a)
{
- uint64_t caps, config;
+ uint64_t caps, config, config2;
int error;
KASSERT(ri >= 0 && ri < IBS_NPMCS,
@@ -291,13 +403,16 @@
return (EINVAL);
config = a->pm_md.pm_ibs.ibs_ctl;
- error = ibs_validate_pmc_config(ri, config);
+ config2 = a->pm_md.pm_ibs.ibs_ctl2;
+ error = ibs_validate_pmc_config(ri, config, config2);
if (error != 0)
return (error);
pm->pm_md.pm_ibs.ibs_ctl = config;
+ pm->pm_md.pm_ibs.ibs_ctl2 = config2;
- PMCDBG2(MDP, ALL, 2, "ibs-allocate ri=%d -> config=0x%jx", ri,
- config);
+ PMCDBG3(MDP, ALL, 2,
+ "ibs-allocate ri=%d -> config=0x%jx config2=0x%jx", ri,
+ config, config2);
return (0);
}
@@ -326,13 +441,52 @@
return (0);
}
+/*
+ * Strip the alternate disable bit from a stored ctl2 config so it can be
+ * written for a running counter.
+ */
+static uint64_t
+ibs_fetch_ctl2_start_config(struct pmc *pm)
+{
+ return (pm->pm_md.pm_ibs.ibs_ctl2 & ~IBS_FETCH_CTL2_DISABLE);
+}
+
+static uint64_t
+ibs_op_ctl2_start_config(struct pmc *pm)
+{
+ return (pm->pm_md.pm_ibs.ibs_ctl2 & ~IBS_OP_CTL2_DISABLE);
+}
+
+static void
+ibs_write_fetch_start(struct pmc *pm)
+{
+ uint64_t config;
+
+ wrmsr(IBS_FETCH_CTL, 0);
+ if (ibs_fetch_ctl2_supported)
+ wrmsr(IBS_FETCH_CTL2, ibs_fetch_ctl2_start_config(pm));
+ config = pm->pm_md.pm_ibs.ibs_ctl | IBS_FETCH_CTL_ENABLE;
+ wrmsr(IBS_FETCH_CTL, config);
+}
+
+static void
+ibs_write_op_start(struct pmc *pm)
+{
+ uint64_t config;
+
+ wrmsr(IBS_OP_CTL, 0);
+ if (ibs_op_ctl2_supported)
+ wrmsr(IBS_OP_CTL2, ibs_op_ctl2_start_config(pm));
+ config = pm->pm_md.pm_ibs.ibs_ctl | IBS_OP_CTL_ENABLE;
+ wrmsr(IBS_OP_CTL, config);
+}
+
/*
* Start a PMC.
*/
static int
ibs_start_pmc(int cpu __diagused, int ri, struct pmc *pm)
{
- uint64_t config;
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
("[ibs,%d] illegal CPU value %d", __LINE__, cpu));
@@ -347,20 +501,12 @@
*/
atomic_store_int(&ibs_pcpu[cpu]->pc_status, IBS_CPU_RUNNING);
- /*
- * Turn on the ENABLE bit. Zeroing out the control register eliminates
- * stale valid bits from spurious NMIs and it resets the counter.
- */
switch (ri) {
case IBS_PMC_FETCH:
- wrmsr(IBS_FETCH_CTL, 0);
- config = pm->pm_md.pm_ibs.ibs_ctl | IBS_FETCH_CTL_ENABLE;
- wrmsr(IBS_FETCH_CTL, config);
+ ibs_write_fetch_start(pm);
break;
case IBS_PMC_OP:
- wrmsr(IBS_OP_CTL, 0);
- config = pm->pm_md.pm_ibs.ibs_ctl | IBS_OP_CTL_ENABLE;
- wrmsr(IBS_OP_CTL, config);
+ ibs_write_op_start(pm);
break;
}
@@ -374,7 +520,8 @@
ibs_stop_pmc(int cpu __diagused, int ri, struct pmc *pm)
{
int i;
- uint64_t config;
+ uint64_t config, config2;
+ bool use_alt_disable;
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
("[ibs,%d] illegal CPU value %d", __LINE__, cpu));
@@ -394,23 +541,47 @@
* are stopping and discard spurious NMIs. We then retry clearing the
* control register for 50us. This gives us enough time and ensures
* that the valid bit is not accidently stuck after a spurious NMI.
+ *
+ * On Zen6 with the alternate disable bit (CPUID IbsDis), assert the
+ * ctl2 DISABLE bit first. This avoids an RMW hazard in ctl1 that the
+ * processor may update concurrently while sampling.
*/
config = pm->pm_md.pm_ibs.ibs_ctl;
+ config2 = pm->pm_md.pm_ibs.ibs_ctl2;
+ use_alt_disable = (ibs_features & CPUID_IBSID_IBSDIS) != 0;
atomic_store_int(&ibs_pcpu[cpu]->pc_status, IBS_CPU_STOPPING);
+ /*
+ * On Zen6, ctl2 DISABLE is the authoritative stop switch; skip
+ * the legacy ctl1 RMW and clear it directly
+ */
switch (ri) {
case IBS_PMC_FETCH:
- wrmsr(IBS_FETCH_CTL, config & ~IBS_FETCH_CTL_MAXCNTMASK);
- DELAY(1);
- config &= ~IBS_FETCH_CTL_ENABLE;
- wrmsr(IBS_FETCH_CTL, config);
+ if (use_alt_disable) {
+ wrmsr(IBS_FETCH_CTL2,
+ config2 | IBS_FETCH_CTL2_DISABLE);
+ wrmsr(IBS_FETCH_CTL, config & ~IBS_FETCH_CTL_ENABLE);
+ } else {
+ wrmsr(IBS_FETCH_CTL,
+ config & ~IBS_FETCH_CTL_MAXCNTMASK);
+ DELAY(1);
+ config &= ~IBS_FETCH_CTL_ENABLE;
+ wrmsr(IBS_FETCH_CTL, config);
+ }
break;
case IBS_PMC_OP:
- wrmsr(IBS_OP_CTL, config & ~IBS_OP_CTL_MAXCNTMASK);
- DELAY(1);
- config &= ~IBS_OP_CTL_ENABLE;
- wrmsr(IBS_OP_CTL, config);
+ if (use_alt_disable) {
+ wrmsr(IBS_OP_CTL2,
+ config2 | IBS_OP_CTL2_DISABLE);
+ wrmsr(IBS_OP_CTL, config & ~IBS_OP_CTL_ENABLE);
+ } else {
+ wrmsr(IBS_OP_CTL,
+ config & ~IBS_OP_CTL_MAXCNTMASK);
+ DELAY(1);
+ config &= ~IBS_OP_CTL_ENABLE;
+ wrmsr(IBS_OP_CTL, config);
+ }
break;
}
@@ -420,9 +591,13 @@
switch (ri) {
case IBS_PMC_FETCH:
wrmsr(IBS_FETCH_CTL, 0);
+ if (ibs_fetch_ctl2_supported)
+ wrmsr(IBS_FETCH_CTL2, 0);
break;
case IBS_PMC_OP:
wrmsr(IBS_OP_CTL, 0);
+ if (ibs_op_ctl2_supported)
+ wrmsr(IBS_OP_CTL2, 0);
break;
}
}
@@ -446,7 +621,8 @@
memset(&mpd, 0, sizeof(mpd));
mpd.pl_type = PMC_CC_MULTIPART_IBS_FETCH;
- mpd.pl_length = PMC_MPIDX_FETCH_MAX;
+ mpd.pl_length = ibs_fetch_ctl2_supported ?
+ (PMC_MPIDX_FETCH_CTL2 + 1) : PMC_MPIDX_FETCH_MAX;
mpd.pl_mpdata[PMC_MPIDX_FETCH_CTL] = config;
if ((ibs_features & CPUID_IBSID_IBSFETCHCTLEXTD) != 0) {
mpd.pl_mpdata[PMC_MPIDX_FETCH_EXTCTL] = rdmsr(IBS_FETCH_EXTCTL);
@@ -456,10 +632,13 @@
mpd.pl_mpdata[PMC_MPIDX_FETCH_PHYSADDR] =
rdmsr(IBS_FETCH_PHYSADDR);
}
+ if (ibs_fetch_ctl2_supported) {
+ mpd.pl_mpdata[PMC_MPIDX_FETCH_CTL2] = rdmsr(IBS_FETCH_CTL2);
+ }
pmc_process_interrupt_mp(PMC_HR, pm, tf, &mpd);
- wrmsr(IBS_FETCH_CTL, pm->pm_md.pm_ibs.ibs_ctl | IBS_FETCH_CTL_ENABLE);
+ ibs_write_fetch_start(pm);
}
static void
@@ -476,7 +655,8 @@
memset(&mpd, 0, sizeof(mpd));
mpd.pl_type = PMC_CC_MULTIPART_IBS_OP;
- mpd.pl_length = PMC_MPIDX_OP_MAX;
+ mpd.pl_length = ibs_op_ctl2_supported ?
+ (PMC_MPIDX_OP_CTL2 + 1) : PMC_MPIDX_OP_MAX;
mpd.pl_mpdata[PMC_MPIDX_OP_CTL] = config;
mpd.pl_mpdata[PMC_MPIDX_OP_RIP] = rdmsr(IBS_OP_RIP);
mpd.pl_mpdata[PMC_MPIDX_OP_DATA] = rdmsr(IBS_OP_DATA);
@@ -490,10 +670,13 @@
if ((ibs_features & CPUID_IBSID_IBSOPDATA4) != 0) {
mpd.pl_mpdata[PMC_MPIDX_OP_DATA4] = rdmsr(IBS_OP_DATA4);
}
+ if (ibs_op_ctl2_supported) {
+ mpd.pl_mpdata[PMC_MPIDX_OP_CTL2] = rdmsr(IBS_OP_CTL2);
+ }
pmc_process_interrupt_mp(PMC_HR, pm, tf, &mpd);
- wrmsr(IBS_OP_CTL, pm->pm_md.pm_ibs.ibs_ctl | IBS_OP_CTL_ENABLE);
+ ibs_write_op_start(pm);
}
/*
@@ -644,6 +827,10 @@
*/
wrmsr(IBS_FETCH_CTL, 0);
wrmsr(IBS_OP_CTL, 0);
+ if (ibs_fetch_ctl2_supported)
+ wrmsr(IBS_FETCH_CTL2, 0);
+ if (ibs_op_ctl2_supported)
+ wrmsr(IBS_OP_CTL2, 0);
/*
* Free up allocated space.
diff --git a/usr.sbin/pmcstat/pmcstat_log.c b/usr.sbin/pmcstat/pmcstat_log.c
--- a/usr.sbin/pmcstat/pmcstat_log.c
+++ b/usr.sbin/pmcstat/pmcstat_log.c
@@ -371,10 +371,10 @@
#if defined(__amd64__) || defined(__i386__)
static void
-pmcstat_print_ibs_fetch(struct pmclog_ev_callchain *cc, int offset)
+pmcstat_print_ibs_fetch(struct pmclog_ev_callchain *cc, int offset, int len64)
{
uint64_t *ibsbuf = (uint64_t *)&cc->pl_pc[offset];
- uint64_t ctl;
+ uint64_t ctl, ctl2;
ctl = ibsbuf[PMC_MPIDX_FETCH_CTL];
PMCSTAT_PRINT_ENTRY("ibs-fetch", "%s%s%s%s",
@@ -390,15 +390,28 @@
PMCSTAT_PRINT_ENTRY("IBS", "Physical Address %" PRIx64,
ibsbuf[PMC_MPIDX_FETCH_PHYSADDR]);
}
+ if (len64 > PMC_MPIDX_FETCH_CTL2) {
+ ctl2 = ibsbuf[PMC_MPIDX_FETCH_CTL2];
+ if ((ctl2 & IBS_FETCH_CTL2_EXCLADDR63EQ1) != 0)
+ PMCSTAT_PRINT_ENTRY("ibs-fetch", "addr63=0");
+ if ((ctl2 & IBS_FETCH_CTL2_EXCLADDR63EQ0) != 0)
+ PMCSTAT_PRINT_ENTRY("ibs-fetch", "addr63=1");
+ if ((ctl2 & IBS_FETCH_CTL2_LATFILTERMASK) != 0) {
+ PMCSTAT_PRINT_ENTRY("ibs-fetch",
+ "fetchlat>=%" PRIu64,
+ (uint64_t)IBS_FETCH_CTL2_CTL_TO_LAT(ctl2));
+ }
+ }
}
static void
-pmcstat_print_ibs_op(struct pmclog_ev_callchain *cc, int offset)
+pmcstat_print_ibs_op(struct pmclog_ev_callchain *cc, int offset, int len64)
{
uint64_t *ibsbuf = (uint64_t *)&cc->pl_pc[offset];
- uint64_t data, data3;
+ uint64_t data, data2, data3, ctl2;
data = ibsbuf[PMC_MPIDX_OP_DATA];
+ data2 = ibsbuf[PMC_MPIDX_OP_DATA2];
data3 = ibsbuf[PMC_MPIDX_OP_DATA3];
if ((data & IBS_OP_DATA_RIPINVALID) == 0) {
@@ -416,6 +429,11 @@
(data3 & IBS_OP_DATA3_LOCKEDOP) ? "lock " : "",
(data3 & IBS_OP_DATA3_DCL1TLBMISS) ? "l1tlbmiss " : "",
(data3 & IBS_OP_DATA3_DCMISS) ? "dcmiss " : "");
+ if ((data2 & (IBS_OP_DATA2_STRMST | IBS_OP_DATA2_RMTSOCKET)) != 0) {
+ PMCSTAT_PRINT_ENTRY("ibs-op", "%s%s",
+ (data2 & IBS_OP_DATA2_STRMST) ? "streamstore " : "",
+ (data2 & IBS_OP_DATA2_RMTSOCKET) ? "remotesocket" : "");
+ }
PMCSTAT_PRINT_ENTRY("ibs-op", "Latency %" PRIu64,
IBS_OP_DATA3_TO_DCLAT(data3));
if ((data3 & IBS_OP_DATA3_DCLINADDRVALID) != 0) {
@@ -426,6 +444,15 @@
PMCSTAT_PRINT_ENTRY("ibs-op", "Physical Address %" PRIx64,
ibsbuf[PMC_MPIDX_OP_DC_PHYSADDR]);
}
+ if (len64 > PMC_MPIDX_OP_CTL2) {
+ ctl2 = ibsbuf[PMC_MPIDX_OP_CTL2];
+ if ((ctl2 & IBS_OP_CTL2_EXCLRIP63EQ1) != 0)
+ PMCSTAT_PRINT_ENTRY("ibs-op", "addr63=0");
+ if ((ctl2 & IBS_OP_CTL2_EXCLRIP63EQ0) != 0)
+ PMCSTAT_PRINT_ENTRY("ibs-op", "addr63=1");
+ if ((ctl2 & IBS_OP_CTL2_STRMSTFILTER) != 0)
+ PMCSTAT_PRINT_ENTRY("ibs-op", "streamstore");
+ }
}
#endif
@@ -446,9 +473,11 @@
return (offset);
#if defined(__amd64__) || defined(__i386__)
} else if (type == PMC_CC_MULTIPART_IBS_FETCH) {
- pmcstat_print_ibs_fetch(cc, offset);
+ pmcstat_print_ibs_fetch(cc, offset,
+ len / (sizeof(uint64_t) / sizeof(uintptr_t)));
} else if (type == PMC_CC_MULTIPART_IBS_OP) {
- pmcstat_print_ibs_op(cc, offset);
+ pmcstat_print_ibs_op(cc, offset,
+ len / (sizeof(uint64_t) / sizeof(uintptr_t)));
#endif
} else {
PMCSTAT_PRINT_ENTRY("unsupported multipart type!");
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jul 22, 10:27 PM (16 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35384187
Default Alt Text
D56914.id177522.diff (25 KB)
Attached To
Mode
D56914: hwpmc: Add Zen6 IBS ctl2 filters and alternate disable
Attached
Detach File
Event Timeline
Log In to Comment