Page MenuHomeFreeBSD

D61374.1794362440.diff
No OneTemporary

Authored By
Unknown
Size
5 KB
Referenced Files
None
Subscribers
None

D61374.1794362440.diff

diff --git a/share/man/man4/hwpmc.4 b/share/man/man4/hwpmc.4
--- a/share/man/man4/hwpmc.4
+++ b/share/man/man4/hwpmc.4
@@ -503,6 +503,13 @@
.It Va kern.hwpmc.nsamples Pq integer, read-only
The number of entries in the per-CPU ring buffer used during sampling.
The default is 256.
+.It Va kern.hwpmc.throttle_pconly Pq integer, read-write
+If set to non-zero, a PMC that reached
+.Va kern.hwpmc.max_sample_rate
+in the previous clock tick records only the program counter.
+The driver does not walk the call stack for these samples.
+This decreases the cost of each interrupt while the sample rate is high.
+The default is 1.
.It Va security.bsd.unprivileged_syspmcs Pq boolean, read-write
If set to non-zero, allow unprivileged processes to allocate system-wide
PMCs.
diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c
--- a/sys/dev/hwpmc/hwpmc_mod.c
+++ b/sys/dev/hwpmc/hwpmc_mod.c
@@ -340,6 +340,12 @@
pmc_max_sample_rate_sysctl_handler, "IU",
"maximum samples per second for one PMC on one CPU (0: no limit)");
+/* Skip callchains after a rate stop. */
+static int pmc_throttle_pconly = 1;
+SYSCTL_INT(_kern_hwpmc, OID_AUTO, throttle_pconly, CTLFLAG_RWTUN,
+ &pmc_throttle_pconly, 0,
+ "record only the PC after a tick at the sample rate limit");
+
/* Interrupt CPU budget. Zero and 100 disable it. */
static u_int pmc_cpu_time_max_percent = PMC_CPU_TIME_MAX_PERCENT;
static u_int pmc_intr_allowed_ns; /* 0: limit disabled */
@@ -5108,8 +5114,8 @@
ps->ps_flags = inuserspace ? PMC_CC_F_USERSPACE : 0;
ps->ps_nsamples_actual = 0;
- callchaindepth = (pm->pm_flags & PMC_F_CALLCHAIN) != 0 ?
- pmc_callchaindepth : 1;
+ callchaindepth = (pm->pm_flags & PMC_F_CALLCHAIN) != 0 &&
+ pm->pm_pcpu_state[cpu].pps_pconly == 0 ? pmc_callchaindepth : 1;
MPASS(ps->ps_pc != NULL);
@@ -5122,7 +5128,9 @@
}
if (callchaindepth == 1) {
+ /* Keep multipart data before the PC. */
ps->ps_pc[ps->ps_nsamples_actual] = PMC_TRAPFRAME_TO_PC(tf);
+ callchaindepth = ps->ps_nsamples_actual + 1;
} else {
/*
* Kernel stack traversals can be done immediately, while we
@@ -5181,6 +5189,10 @@
pps = &pm->pm_pcpu_state[curcpu];
seq = DPCPU_GET(pmc_tick_seq);
if (pps->pps_intr_tick != seq) {
+ /* Skip stack walks after a rate stop. */
+ pps->pps_pconly = pmc_throttle_pconly != 0 &&
+ pps->pps_intr_tick == seq - 1 &&
+ pps->pps_intr_count > limit;
pps->pps_intr_tick = seq;
pps->pps_intr_count = 0;
}
@@ -5191,6 +5203,8 @@
DPCPU_SET(pmc_sampled, 1);
return (EBUSY);
}
+ } else {
+ pm->pm_pcpu_state[curcpu].pps_pconly = 0;
}
td = curthread;
diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h
--- a/sys/sys/pmc.h
+++ b/sys/sys/pmc.h
@@ -756,6 +756,7 @@
u_int pps_lost; /* Drop flags and count. */
uint8_t pps_stalled;
uint8_t pps_cpustate;
+ uint8_t pps_pconly; /* PC only. */
} __aligned(CACHE_LINE_SIZE);
struct pmc {
LIST_HEAD(,pmc_target) pm_targets; /* list of target processes */
diff --git a/tests/sys/pmc/pmc_throttle_test.c b/tests/sys/pmc/pmc_throttle_test.c
--- a/tests/sys/pmc/pmc_throttle_test.c
+++ b/tests/sys/pmc/pmc_throttle_test.c
@@ -637,6 +637,78 @@
sysctls_restore();
}
+/* Keep IBS data in PC-only samples. */
+ATF_TC_WITH_CLEANUP(pconly_ibs);
+ATF_TC_HEAD(pconly_ibs, tc)
+{
+ atf_tc_set_md_var(tc, "require.user", "root");
+ atf_tc_set_md_var(tc, "timeout", "30");
+}
+ATF_TC_BODY(pconly_ibs, tc)
+{
+ struct pmclog_ev ev;
+ uint64_t bad, nrec, throttled;
+ pmc_id_t id;
+ uint8_t *hdr;
+ void *parser;
+ u_int i, len;
+ int fd;
+
+ if (hwpmc_get("throttle_pconly") == 0)
+ atf_tc_skip("kern.hwpmc.throttle_pconly is 0");
+ (void)throttle_setup(10);
+ test_event = "ibs-op";
+ test_flags = PMC_F_CALLCHAIN;
+ test_period = 65536;
+
+ (void)measure_log(&throttled, "ibs.log", &id);
+
+ sysctls_restore();
+
+ fd = open("ibs.log", O_RDONLY);
+ ATF_REQUIRE(fd >= 0);
+ parser = pmclog_open(fd);
+ ATF_REQUIRE(parser != NULL);
+ bad = nrec = 0;
+ while (pmclog_read(parser, &ev) == 0) {
+ if (ev.pl_type != PMCLOG_TYPE_CALLCHAIN ||
+ ev.pl_u.pl_cc.pl_pmcid != id)
+ continue;
+ nrec++;
+ if ((ev.pl_u.pl_cc.pl_cpuflags & PMC_CC_F_MULTIPART) == 0) {
+ bad++;
+ continue;
+ }
+ /* Check data and a PC. */
+ len = PMC_MULTIPART_HEADER_LENGTH / sizeof(uintptr_t);
+ hdr = (uint8_t *)&ev.pl_u.pl_cc.pl_pc[0];
+ for (i = 0; i < PMC_MULTIPART_HEADER_ENTRIES; i++) {
+ if (hdr[2 * i] == PMC_CC_MULTIPART_NONE)
+ break;
+ len += hdr[2 * i + 1];
+ }
+ if (ev.pl_u.pl_cc.pl_npc <= len)
+ bad++;
+ }
+ ATF_CHECK_MSG(ev.pl_state == PMCLOG_EOF, "log state %d",
+ ev.pl_state);
+ pmclog_close(parser);
+ close(fd);
+
+ printf("throttled %ju, records %ju, bad %ju\n", (uintmax_t)throttled,
+ (uintmax_t)nrec, (uintmax_t)bad);
+ ATF_CHECK_MSG(throttled > 0, "the PMC never reached the limit");
+ ATF_CHECK_MSG(nrec > 0, "no sample in the log");
+ ATF_CHECK_EQ_MSG(bad, 0, "%ju of %ju samples lost the IBS data",
+ (uintmax_t)bad, (uintmax_t)nrec);
+}
+
+ATF_TC_CLEANUP(pconly_ibs, tc)
+{
+
+ sysctls_restore();
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, rate_limited);
@@ -646,5 +718,6 @@
ATF_TP_ADD_TC(tp, drop_records_process);
ATF_TP_ADD_TC(tp, short_period);
ATF_TP_ADD_TC(tp, flush_loop);
+ ATF_TP_ADD_TC(tp, pconly_ibs);
return (atf_no_error());
}

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 11, 2:00 AM (11 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41652416
Default Alt Text
D61374.1794362440.diff (5 KB)

Event Timeline