Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F175345242
D60563.id189318.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D60563.id189318.diff
View Options
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
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 8, 2023
+.Dd October 9, 2026
.Dt HWPMC 4
.Os
.Sh NAME
@@ -428,7 +428,10 @@
.Bl -tag -width indent
.It Va kern.hwpmc.callchaindepth Pq integer, read-only
The maximum number of call chain records to capture per sample.
-The default is 8.
+The default is 128.
+Each sample slot must also hold the largest multipart payload
+(an 8-byte header, 10 64-bit words and one program counter), so smaller
+values are raised to 12 on 64-bit platforms and 23 on 32-bit platforms.
.It Va kern.hwpmc.debugflags Pq string, read-write
(Only available if the
.Nm
diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c
--- a/sys/dev/hwpmc/hwpmc_logging.c
+++ b/sys/dev/hwpmc/hwpmc_logging.c
@@ -121,6 +121,7 @@
} \
ph = (struct pmclog_header *)_le; \
ph->pl_header =_PMCLOG_TO_HEADER(TYPE,_len); \
+ ph->pl_spare = 0; \
ph->pl_tsc = (TSC); \
_le += sizeof(*ph) / 4 /* skip over timestamp */
@@ -139,6 +140,7 @@
} \
ph = (struct pmclog_header *)_le; \
ph->pl_header =_PMCLOG_TO_HEADER(TYPE,_len); \
+ ph->pl_spare = 0; \
ph->pl_tsc = tsc; \
_le += sizeof(*ph) / 4 /* skip over timestamp */
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
@@ -319,6 +319,12 @@
&pmc_stats.pm_overwrites,
"# of times a sample was overwritten before being logged");
+/* Every sample slot must fit the multipart header, payload, and one PC. */
+#define PMC_CALLCHAIN_DEPTH_MIN \
+ ((int)PMC_MULTIPART_SAMPLE_MIN_WORDS_FOR(sizeof(uintptr_t)))
+CTASSERT(PMC_MULTIPART_MAX_PAYLOAD64 ==
+ nitems(((struct pmc_multipart *)0)->pl_mpdata));
+
static int pmc_callchaindepth = PMC_CALLCHAIN_DEPTH;
SYSCTL_INT(_kern_hwpmc, OID_AUTO, callchaindepth, CTLFLAG_RDTUN,
&pmc_callchaindepth, 0,
@@ -4781,6 +4787,7 @@
MPASS(ps->ps_pc != NULL);
MPASS(ps->ps_nsamples_actual != 0);
+ MPASS(length >= 0 && length <= UCHAR_MAX);
hdr = (uint8_t *)ps->ps_pc;
@@ -4799,18 +4806,19 @@
static void
pmc_multipart_copydata(struct pmc_sample *ps, struct pmc_multipart *mp)
{
- int i, scale;
- uint64_t *ps_pc;
+ int scale;
MPASS(ps->ps_pc != NULL);
MPASS(ps->ps_nsamples_actual != 0);
-
- ps_pc = (uint64_t *)ps->ps_pc;
-
- for (i = 0; i < mp->pl_length; i++)
- ps_pc[i + 1] = mp->pl_mpdata[i];
+ MPASS(mp->pl_length >= 0 && mp->pl_length <=
+ PMC_MULTIPART_MAX_PAYLOAD64);
scale = sizeof(uint64_t) / sizeof(uintptr_t);
+ MPASS(ps->ps_nsamples_actual + scale * mp->pl_length <=
+ pmc_callchaindepth);
+ memcpy(ps->ps_pc + ps->ps_nsamples_actual, mp->pl_mpdata,
+ mp->pl_length * sizeof(uint64_t));
+
pmc_multipart_add(ps, mp->pl_type, scale * mp->pl_length);
}
@@ -4877,15 +4885,18 @@
MPASS(ps->ps_pc != NULL);
if (mp != NULL) {
- /* Set multipart flag, clear header and copy data */
+ /* Set multipart flag, clear the full header, and copy data. */
ps->ps_flags |= PMC_CC_F_MULTIPART;
- ps->ps_pc[0] = 0;
- ps->ps_nsamples_actual = 1;
+ bzero(ps->ps_pc, PMC_MULTIPART_HEADER_LENGTH);
+ ps->ps_nsamples_actual = PMC_MULTIPART_HEADER_WORDS_FOR(
+ sizeof(uintptr_t));
pmc_multipart_copydata(ps, mp);
}
if (callchaindepth == 1) {
ps->ps_pc[ps->ps_nsamples_actual] = PMC_TRAPFRAME_TO_PC(tf);
+ /* Count any multipart words or they are lost at logging. */
+ callchaindepth += ps->ps_nsamples_actual;
} else {
/*
* Kernel stack traversals can be done immediately, while we
@@ -5015,9 +5026,9 @@
* Retrieve the callchain and mark the sample buffer
* as 'processable' by the timer tick sweep code.
*/
- if (__predict_true(nsamples < pmc_callchaindepth - 1))
+ if (__predict_true(nsamples < pmc_callchaindepth))
nsamples += pmc_save_user_callchain(ps->ps_pc + nsamples,
- pmc_callchaindepth - nsamples - 1, tf);
+ pmc_callchaindepth - nsamples, tf);
/*
* We have to prevent hardclock from potentially overwriting
@@ -5145,8 +5156,17 @@
*/
if (pm->pm_flags & PMC_F_ATTACHED_TO_OWNER) {
if (ps->ps_flags & PMC_CC_F_USERSPACE) {
+ uint32_t pcidx;
+
+ pcidx = 0;
+ if ((ps->ps_flags & PMC_CC_F_MULTIPART) != 0 &&
+ !pmclog_multipart_callchain_offset(
+ ps->ps_pc, ps->ps_nsamples, &pcidx))
+ goto entrydone;
+ if (pcidx >= ps->ps_nsamples)
+ goto entrydone;
td = FIRST_THREAD_IN_PROC(po->po_owner);
- addupc_intr(td, ps->ps_pc[0], 1);
+ addupc_intr(td, ps->ps_pc[pcidx], 1);
}
} else
pmclog_process_callchain(pm, ps);
@@ -5728,6 +5748,12 @@
PMC_CALLCHAIN_DEPTH_MAX);
pmc_callchaindepth = PMC_CALLCHAIN_DEPTH_MAX;
}
+ if (pmc_callchaindepth < PMC_CALLCHAIN_DEPTH_MIN) {
+ printf("hwpmc: tunable \"callchaindepth\"=%d too small for "
+ "multipart samples - using %d.\n", pmc_callchaindepth,
+ PMC_CALLCHAIN_DEPTH_MIN);
+ pmc_callchaindepth = PMC_CALLCHAIN_DEPTH_MIN;
+ }
md = pmc_md_initialize();
if (md == NULL) {
diff --git a/sys/sys/pmclog.h b/sys/sys/pmclog.h
--- a/sys/sys/pmclog.h
+++ b/sys/sys/pmclog.h
@@ -127,18 +127,77 @@
/*
* If the multipart flag is set, then pl_pc contains multiple data types. The
- * first 8 bytes is a header made up of a 1 byte type and 1 byte length that
- * describes the use of the remaining pl_pc array.
+ * first 8 bytes are a header made up of four 1 byte type and 1 byte length
+ * tuples that describe the use of the remaining pl_pc array. Lengths are
+ * counted in native pointer-sized pl_pc entries; 64-bit payload values consume
+ * two entries on 32-bit platforms.
*/
#define PMC_MULTIPART_HEADER_LENGTH 8
#define PMC_MULTIPART_HEADER_ENTRIES 4
+#define PMC_MULTIPART_HEADER_WORDS_FOR(SZ) \
+ (PMC_MULTIPART_HEADER_LENGTH / (SZ))
+#define PMC_MULTIPART_64BIT_WORDS_FOR(N, SZ) \
+ ((N) * (sizeof(uint64_t) / (SZ)))
+#define PMC_MULTIPART_HEADER_WORDS \
+ PMC_MULTIPART_HEADER_WORDS_FOR(sizeof(uintfptr_t))
+#define PMC_MULTIPART_PAYLOAD_WORDS(N) \
+ PMC_MULTIPART_64BIT_WORDS_FOR((N), sizeof(uintfptr_t))
+#define PMC_MULTIPART_MAX_PAYLOAD64 10
+#define PMC_MULTIPART_SAMPLE_MIN_WORDS_FOR(SZ) \
+ (PMC_MULTIPART_HEADER_WORDS_FOR(SZ) + \
+ PMC_MULTIPART_64BIT_WORDS_FOR(PMC_MULTIPART_MAX_PAYLOAD64, \
+ (SZ)) + 1)
+#define PMC_MULTIPART_SAMPLE_MIN_WORDS \
+ PMC_MULTIPART_SAMPLE_MIN_WORDS_FOR(sizeof(uintfptr_t))
#define PMC_CC_MULTIPART_NONE 0
#define PMC_CC_MULTIPART_CALLCHAIN 1
#define PMC_CC_MULTIPART_IBS_FETCH 2
#define PMC_CC_MULTIPART_IBS_OP 3
+static __inline int
+pmclog_multipart_callchain_offset(const void *pc, uint32_t npc,
+ uint32_t *offsetp)
+{
+ const uint8_t *hdr;
+ uint32_t i, len, offset, type;
+
+ if (offsetp != NULL)
+ *offsetp = 0;
+ if (pc == NULL || npc < PMC_MULTIPART_HEADER_WORDS)
+ return (0);
+
+ hdr = (const uint8_t *)pc;
+ offset = PMC_MULTIPART_HEADER_WORDS;
+ for (i = 0; i < PMC_MULTIPART_HEADER_ENTRIES; i++) {
+ type = hdr[2 * i];
+ len = hdr[2 * i + 1];
+
+ if (type == PMC_CC_MULTIPART_NONE ||
+ type == PMC_CC_MULTIPART_CALLCHAIN)
+ break;
+ if (len > npc - offset)
+ return (0);
+ offset += len;
+ }
+ if (offset > npc)
+ return (0);
+ if (offsetp != NULL)
+ *offsetp = offset;
+ return (1);
+}
+
+static __inline uint32_t
+pmclog_multipart_offset(const void *pc)
+{
+ uint32_t offset;
+
+ if (!pmclog_multipart_callchain_offset(pc, ~(uint32_t)0, &offset))
+ return (~(uint32_t)0);
+ return (offset);
+}
+
struct pmclog_closelog {
PMCLOG_ENTRY_HEADER
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Oct 11, 4:14 AM (15 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40583810
Default Alt Text
D60563.id189318.diff (7 KB)
Attached To
Mode
D60563: hwpmc: fix multipart sample accounting
Attached
Detach File
Event Timeline
Log In to Comment