xref: /freebsd/tests/sys/pmc/pmc_detach_test.c (revision 3c3f886e4bc7619f7847ad0d0f996088ddf5915a)
1*3c3f886eSAlexander Leidinger /*-
2*3c3f886eSAlexander Leidinger  * SPDX-License-Identifier: BSD-2-Clause
3*3c3f886eSAlexander Leidinger  *
4*3c3f886eSAlexander Leidinger  * Copyright (c) 2026 Alexander Leidinger <netchild@FreeBSD.org>
5*3c3f886eSAlexander Leidinger  *
6*3c3f886eSAlexander Leidinger  * Redistribution and use in source and binary forms, with or without
7*3c3f886eSAlexander Leidinger  * modification, are permitted provided that the following conditions
8*3c3f886eSAlexander Leidinger  * are met:
9*3c3f886eSAlexander Leidinger  * 1. Redistributions of source code must retain the above copyright
10*3c3f886eSAlexander Leidinger  *    notice, this list of conditions and the following disclaimer.
11*3c3f886eSAlexander Leidinger  * 2. Redistributions in binary form must reproduce the above copyright
12*3c3f886eSAlexander Leidinger  *    notice, this list of conditions and the following disclaimer in the
13*3c3f886eSAlexander Leidinger  *    documentation and/or other advertising materials provided with the
14*3c3f886eSAlexander Leidinger  *    distribution.
15*3c3f886eSAlexander Leidinger  *
16*3c3f886eSAlexander Leidinger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*3c3f886eSAlexander Leidinger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*3c3f886eSAlexander Leidinger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*3c3f886eSAlexander Leidinger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*3c3f886eSAlexander Leidinger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*3c3f886eSAlexander Leidinger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*3c3f886eSAlexander Leidinger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*3c3f886eSAlexander Leidinger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*3c3f886eSAlexander Leidinger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*3c3f886eSAlexander Leidinger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*3c3f886eSAlexander Leidinger  * SUCH DAMAGE.
27*3c3f886eSAlexander Leidinger  */
28*3c3f886eSAlexander Leidinger 
29*3c3f886eSAlexander Leidinger /*
30*3c3f886eSAlexander Leidinger  * Regression tests for detaching a process-mode PMC from a target that
31*3c3f886eSAlexander Leidinger  * still has it loaded on hardware.  The runcount reference for a live
32*3c3f886eSAlexander Leidinger  * PMC is dropped only by the context-switch-out reclaim, which the
33*3c3f886eSAlexander Leidinger  * scheduler gates on P_HWPMC; detaching used to clear P_HWPMC without
34*3c3f886eSAlexander Leidinger  * draining the reference, so the following release spun forever in
35*3c3f886eSAlexander Leidinger  * pmc_wait_for_pmc_idle() - a panic ("waiting too long for pmc to be
36*3c3f886eSAlexander Leidinger  * free") on an INVARIANTS kernel, an unkillable loop holding the hwpmc
37*3c3f886eSAlexander Leidinger  * lock otherwise.
38*3c3f886eSAlexander Leidinger  *
39*3c3f886eSAlexander Leidinger  * The failure is deterministic: attaching a counting PMC to the current
40*3c3f886eSAlexander Leidinger  * (running) thread and detaching it before release always left the
41*3c3f886eSAlexander Leidinger  * reference live.  On a kernel that carries the fix these tests complete
42*3c3f886eSAlexander Leidinger  * immediately; run against a kernel that lacks it they would wedge, so
43*3c3f886eSAlexander Leidinger  * (like any hwpmc regression test) they ship alongside the fix.
44*3c3f886eSAlexander Leidinger  *
45*3c3f886eSAlexander Leidinger  * They need an allocatable process-mode counting event, and skip where
46*3c3f886eSAlexander Leidinger  * none is available (hwpmc(4) not loaded, or a VM without a vPMU).
47*3c3f886eSAlexander Leidinger  */
48*3c3f886eSAlexander Leidinger 
49*3c3f886eSAlexander Leidinger #include <sys/types.h>
50*3c3f886eSAlexander Leidinger 
51*3c3f886eSAlexander Leidinger #include <errno.h>
52*3c3f886eSAlexander Leidinger #include <pmc.h>
53*3c3f886eSAlexander Leidinger #include <pthread.h>
54*3c3f886eSAlexander Leidinger #include <stdio.h>
55*3c3f886eSAlexander Leidinger #include <string.h>
56*3c3f886eSAlexander Leidinger #include <unistd.h>
57*3c3f886eSAlexander Leidinger 
58*3c3f886eSAlexander Leidinger #include <atf-c.h>
59*3c3f886eSAlexander Leidinger 
60*3c3f886eSAlexander Leidinger static const char *counting_events[] = {
61*3c3f886eSAlexander Leidinger 	"instructions",
62*3c3f886eSAlexander Leidinger 	"cycles",
63*3c3f886eSAlexander Leidinger 	"branches",
64*3c3f886eSAlexander Leidinger 	"unhalted-core-cycles",
65*3c3f886eSAlexander Leidinger 	"inst_retired.any",
66*3c3f886eSAlexander Leidinger 	"cpu_clk_unhalted.thread",
67*3c3f886eSAlexander Leidinger 	"ls_not_halted_cyc",
68*3c3f886eSAlexander Leidinger 	NULL
69*3c3f886eSAlexander Leidinger };
70*3c3f886eSAlexander Leidinger 
71*3c3f886eSAlexander Leidinger static volatile int spin_stop;
72*3c3f886eSAlexander Leidinger 
73*3c3f886eSAlexander Leidinger static void *
spinner(void * arg __unused)74*3c3f886eSAlexander Leidinger spinner(void *arg __unused)
75*3c3f886eSAlexander Leidinger {
76*3c3f886eSAlexander Leidinger 	volatile unsigned long s = 0;
77*3c3f886eSAlexander Leidinger 
78*3c3f886eSAlexander Leidinger 	while (spin_stop == 0)
79*3c3f886eSAlexander Leidinger 		s += 1;
80*3c3f886eSAlexander Leidinger 	return (NULL);
81*3c3f886eSAlexander Leidinger }
82*3c3f886eSAlexander Leidinger 
83*3c3f886eSAlexander Leidinger static void
burn_cpu(void)84*3c3f886eSAlexander Leidinger burn_cpu(void)
85*3c3f886eSAlexander Leidinger {
86*3c3f886eSAlexander Leidinger 	volatile unsigned long s = 0;
87*3c3f886eSAlexander Leidinger 	int i;
88*3c3f886eSAlexander Leidinger 
89*3c3f886eSAlexander Leidinger 	for (i = 0; i < 1000000; i++)
90*3c3f886eSAlexander Leidinger 		s += i;
91*3c3f886eSAlexander Leidinger }
92*3c3f886eSAlexander Leidinger 
93*3c3f886eSAlexander Leidinger /* Allocate the first available process-mode counting PMC, or skip. */
94*3c3f886eSAlexander Leidinger static pmc_id_t
alloc_counting_pmc(void)95*3c3f886eSAlexander Leidinger alloc_counting_pmc(void)
96*3c3f886eSAlexander Leidinger {
97*3c3f886eSAlexander Leidinger 	pmc_id_t id;
98*3c3f886eSAlexander Leidinger 	int i;
99*3c3f886eSAlexander Leidinger 
100*3c3f886eSAlexander Leidinger 	if (pmc_init() != 0)
101*3c3f886eSAlexander Leidinger 		atf_tc_skip("hwpmc(4) is not available: %s", strerror(errno));
102*3c3f886eSAlexander Leidinger 
103*3c3f886eSAlexander Leidinger 	for (i = 0; counting_events[i] != NULL; i++) {
104*3c3f886eSAlexander Leidinger 		id = PMC_ID_INVALID;
105*3c3f886eSAlexander Leidinger 		if (pmc_allocate(counting_events[i], PMC_MODE_TC, 0,
106*3c3f886eSAlexander Leidinger 		    PMC_CPU_ANY, &id, 0) == 0)
107*3c3f886eSAlexander Leidinger 			return (id);
108*3c3f886eSAlexander Leidinger 	}
109*3c3f886eSAlexander Leidinger 	atf_tc_skip("no allocatable process-mode counting event "
110*3c3f886eSAlexander Leidinger 	    "(no vPMU?)");
111*3c3f886eSAlexander Leidinger 	return (PMC_ID_INVALID); /* not reached */
112*3c3f886eSAlexander Leidinger }
113*3c3f886eSAlexander Leidinger 
114*3c3f886eSAlexander Leidinger ATF_TC(detach_live_self);
ATF_TC_HEAD(detach_live_self,tc)115*3c3f886eSAlexander Leidinger ATF_TC_HEAD(detach_live_self, tc)
116*3c3f886eSAlexander Leidinger {
117*3c3f886eSAlexander Leidinger 	atf_tc_set_md_var(tc, "descr",
118*3c3f886eSAlexander Leidinger 	    "Detaching a running counting PMC from the current thread and "
119*3c3f886eSAlexander Leidinger 	    "then releasing it does not leak its runcount reference");
120*3c3f886eSAlexander Leidinger 	atf_tc_set_md_var(tc, "require.user", "root");
121*3c3f886eSAlexander Leidinger }
ATF_TC_BODY(detach_live_self,tc)122*3c3f886eSAlexander Leidinger ATF_TC_BODY(detach_live_self, tc)
123*3c3f886eSAlexander Leidinger {
124*3c3f886eSAlexander Leidinger 	pmc_id_t id;
125*3c3f886eSAlexander Leidinger 
126*3c3f886eSAlexander Leidinger 	id = alloc_counting_pmc();
127*3c3f886eSAlexander Leidinger 
128*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_attach(id, 0) == 0);	/* 0 == current process */
129*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_start(id) == 0);
130*3c3f886eSAlexander Leidinger 	burn_cpu();				/* make the counter live */
131*3c3f886eSAlexander Leidinger 
132*3c3f886eSAlexander Leidinger 	/* Detach while still loaded on this CPU, then release. */
133*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_detach(id, 0) == 0);
134*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_release(id) == 0);	/* wedged before the fix */
135*3c3f886eSAlexander Leidinger }
136*3c3f886eSAlexander Leidinger 
137*3c3f886eSAlexander Leidinger ATF_TC(detach_live_multithread);
ATF_TC_HEAD(detach_live_multithread,tc)138*3c3f886eSAlexander Leidinger ATF_TC_HEAD(detach_live_multithread, tc)
139*3c3f886eSAlexander Leidinger {
140*3c3f886eSAlexander Leidinger 	atf_tc_set_md_var(tc, "descr",
141*3c3f886eSAlexander Leidinger 	    "Detaching a running process-scope counting PMC drains the "
142*3c3f886eSAlexander Leidinger 	    "references held by the process' other threads");
143*3c3f886eSAlexander Leidinger 	atf_tc_set_md_var(tc, "require.user", "root");
144*3c3f886eSAlexander Leidinger }
ATF_TC_BODY(detach_live_multithread,tc)145*3c3f886eSAlexander Leidinger ATF_TC_BODY(detach_live_multithread, tc)
146*3c3f886eSAlexander Leidinger {
147*3c3f886eSAlexander Leidinger 	pthread_t th[3];
148*3c3f886eSAlexander Leidinger 	pmc_id_t id;
149*3c3f886eSAlexander Leidinger 	int i, n;
150*3c3f886eSAlexander Leidinger 
151*3c3f886eSAlexander Leidinger 	id = alloc_counting_pmc();
152*3c3f886eSAlexander Leidinger 
153*3c3f886eSAlexander Leidinger 	/* Sibling threads keep the process-scope PMC live on other CPUs. */
154*3c3f886eSAlexander Leidinger 	spin_stop = 0;
155*3c3f886eSAlexander Leidinger 	for (n = 0; n < 3; n++)
156*3c3f886eSAlexander Leidinger 		ATF_REQUIRE(pthread_create(&th[n], NULL, spinner, NULL) == 0);
157*3c3f886eSAlexander Leidinger 
158*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_attach(id, 0) == 0);
159*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_start(id) == 0);
160*3c3f886eSAlexander Leidinger 	burn_cpu();
161*3c3f886eSAlexander Leidinger 	/* Let the siblings be scheduled and pick up the PMC. */
162*3c3f886eSAlexander Leidinger 	usleep(200 * 1000);
163*3c3f886eSAlexander Leidinger 
164*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_detach(id, 0) == 0);
165*3c3f886eSAlexander Leidinger 	ATF_REQUIRE(pmc_release(id) == 0);	/* must drain the siblings */
166*3c3f886eSAlexander Leidinger 
167*3c3f886eSAlexander Leidinger 	spin_stop = 1;
168*3c3f886eSAlexander Leidinger 	for (i = 0; i < n; i++)
169*3c3f886eSAlexander Leidinger 		pthread_join(th[i], NULL);
170*3c3f886eSAlexander Leidinger }
171*3c3f886eSAlexander Leidinger 
ATF_TP_ADD_TCS(tp)172*3c3f886eSAlexander Leidinger ATF_TP_ADD_TCS(tp)
173*3c3f886eSAlexander Leidinger {
174*3c3f886eSAlexander Leidinger 	ATF_TP_ADD_TC(tp, detach_live_self);
175*3c3f886eSAlexander Leidinger 	ATF_TP_ADD_TC(tp, detach_live_multithread);
176*3c3f886eSAlexander Leidinger 
177*3c3f886eSAlexander Leidinger 	return (atf_no_error());
178*3c3f886eSAlexander Leidinger }
179