xref: /linux/tools/testing/selftests/sched_ext/hotplug.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1*a5db7817SDavid Vernet /* SPDX-License-Identifier: GPL-2.0 */
2*a5db7817SDavid Vernet /*
3*a5db7817SDavid Vernet  * Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
4*a5db7817SDavid Vernet  * Copyright (c) 2024 David Vernet <dvernet@meta.com>
5*a5db7817SDavid Vernet  */
6*a5db7817SDavid Vernet #include <bpf/bpf.h>
7*a5db7817SDavid Vernet #include <sched.h>
8*a5db7817SDavid Vernet #include <scx/common.h>
9*a5db7817SDavid Vernet #include <sched.h>
10*a5db7817SDavid Vernet #include <sys/wait.h>
11*a5db7817SDavid Vernet #include <unistd.h>
12*a5db7817SDavid Vernet 
13*a5db7817SDavid Vernet #include "hotplug_test.h"
14*a5db7817SDavid Vernet #include "hotplug.bpf.skel.h"
15*a5db7817SDavid Vernet #include "scx_test.h"
16*a5db7817SDavid Vernet #include "util.h"
17*a5db7817SDavid Vernet 
18*a5db7817SDavid Vernet const char *online_path = "/sys/devices/system/cpu/cpu1/online";
19*a5db7817SDavid Vernet 
is_cpu_online(void)20*a5db7817SDavid Vernet static bool is_cpu_online(void)
21*a5db7817SDavid Vernet {
22*a5db7817SDavid Vernet 	return file_read_long(online_path) > 0;
23*a5db7817SDavid Vernet }
24*a5db7817SDavid Vernet 
toggle_online_status(bool online)25*a5db7817SDavid Vernet static void toggle_online_status(bool online)
26*a5db7817SDavid Vernet {
27*a5db7817SDavid Vernet 	long val = online ? 1 : 0;
28*a5db7817SDavid Vernet 	int ret;
29*a5db7817SDavid Vernet 
30*a5db7817SDavid Vernet 	ret = file_write_long(online_path, val);
31*a5db7817SDavid Vernet 	if (ret != 0)
32*a5db7817SDavid Vernet 		fprintf(stderr, "Failed to bring CPU %s (%s)",
33*a5db7817SDavid Vernet 			online ? "online" : "offline", strerror(errno));
34*a5db7817SDavid Vernet }
35*a5db7817SDavid Vernet 
setup(void ** ctx)36*a5db7817SDavid Vernet static enum scx_test_status setup(void **ctx)
37*a5db7817SDavid Vernet {
38*a5db7817SDavid Vernet 	if (!is_cpu_online())
39*a5db7817SDavid Vernet 		return SCX_TEST_SKIP;
40*a5db7817SDavid Vernet 
41*a5db7817SDavid Vernet 	return SCX_TEST_PASS;
42*a5db7817SDavid Vernet }
43*a5db7817SDavid Vernet 
test_hotplug(bool onlining,bool cbs_defined)44*a5db7817SDavid Vernet static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
45*a5db7817SDavid Vernet {
46*a5db7817SDavid Vernet 	struct hotplug *skel;
47*a5db7817SDavid Vernet 	struct bpf_link *link;
48*a5db7817SDavid Vernet 	long kind, code;
49*a5db7817SDavid Vernet 
50*a5db7817SDavid Vernet 	SCX_ASSERT(is_cpu_online());
51*a5db7817SDavid Vernet 
52*a5db7817SDavid Vernet 	skel = hotplug__open_and_load();
53*a5db7817SDavid Vernet 	SCX_ASSERT(skel);
54*a5db7817SDavid Vernet 
55*a5db7817SDavid Vernet 	/* Testing the offline -> online path, so go offline before starting */
56*a5db7817SDavid Vernet 	if (onlining)
57*a5db7817SDavid Vernet 		toggle_online_status(0);
58*a5db7817SDavid Vernet 
59*a5db7817SDavid Vernet 	if (cbs_defined) {
60*a5db7817SDavid Vernet 		kind = SCX_KIND_VAL(SCX_EXIT_UNREG_BPF);
61*a5db7817SDavid Vernet 		code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) | HOTPLUG_EXIT_RSN;
62*a5db7817SDavid Vernet 		if (onlining)
63*a5db7817SDavid Vernet 			code |= HOTPLUG_ONLINING;
64*a5db7817SDavid Vernet 	} else {
65*a5db7817SDavid Vernet 		kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
66*a5db7817SDavid Vernet 		code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
67*a5db7817SDavid Vernet 		       SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
68*a5db7817SDavid Vernet 	}
69*a5db7817SDavid Vernet 
70*a5db7817SDavid Vernet 	if (cbs_defined)
71*a5db7817SDavid Vernet 		link = bpf_map__attach_struct_ops(skel->maps.hotplug_cb_ops);
72*a5db7817SDavid Vernet 	else
73*a5db7817SDavid Vernet 		link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
74*a5db7817SDavid Vernet 
75*a5db7817SDavid Vernet 	if (!link) {
76*a5db7817SDavid Vernet 		SCX_ERR("Failed to attach scheduler");
77*a5db7817SDavid Vernet 		hotplug__destroy(skel);
78*a5db7817SDavid Vernet 		return SCX_TEST_FAIL;
79*a5db7817SDavid Vernet 	}
80*a5db7817SDavid Vernet 
81*a5db7817SDavid Vernet 	toggle_online_status(onlining ? 1 : 0);
82*a5db7817SDavid Vernet 
83*a5db7817SDavid Vernet 	while (!UEI_EXITED(skel, uei))
84*a5db7817SDavid Vernet 		sched_yield();
85*a5db7817SDavid Vernet 
86*a5db7817SDavid Vernet 	SCX_EQ(skel->data->uei.kind, kind);
87*a5db7817SDavid Vernet 	SCX_EQ(UEI_REPORT(skel, uei), code);
88*a5db7817SDavid Vernet 
89*a5db7817SDavid Vernet 	if (!onlining)
90*a5db7817SDavid Vernet 		toggle_online_status(1);
91*a5db7817SDavid Vernet 
92*a5db7817SDavid Vernet 	bpf_link__destroy(link);
93*a5db7817SDavid Vernet 	hotplug__destroy(skel);
94*a5db7817SDavid Vernet 
95*a5db7817SDavid Vernet 	return SCX_TEST_PASS;
96*a5db7817SDavid Vernet }
97*a5db7817SDavid Vernet 
test_hotplug_attach(void)98*a5db7817SDavid Vernet static enum scx_test_status test_hotplug_attach(void)
99*a5db7817SDavid Vernet {
100*a5db7817SDavid Vernet 	struct hotplug *skel;
101*a5db7817SDavid Vernet 	struct bpf_link *link;
102*a5db7817SDavid Vernet 	enum scx_test_status status = SCX_TEST_PASS;
103*a5db7817SDavid Vernet 	long kind, code;
104*a5db7817SDavid Vernet 
105*a5db7817SDavid Vernet 	SCX_ASSERT(is_cpu_online());
106*a5db7817SDavid Vernet 	SCX_ASSERT(scx_hotplug_seq() > 0);
107*a5db7817SDavid Vernet 
108*a5db7817SDavid Vernet 	skel = SCX_OPS_OPEN(hotplug_nocb_ops, hotplug);
109*a5db7817SDavid Vernet 	SCX_ASSERT(skel);
110*a5db7817SDavid Vernet 
111*a5db7817SDavid Vernet 	SCX_OPS_LOAD(skel, hotplug_nocb_ops, hotplug, uei);
112*a5db7817SDavid Vernet 
113*a5db7817SDavid Vernet 	/*
114*a5db7817SDavid Vernet 	 * Take the CPU offline to increment the global hotplug seq, which
115*a5db7817SDavid Vernet 	 * should cause attach to fail due to us setting the hotplug seq above
116*a5db7817SDavid Vernet 	 */
117*a5db7817SDavid Vernet 	toggle_online_status(0);
118*a5db7817SDavid Vernet 	link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
119*a5db7817SDavid Vernet 
120*a5db7817SDavid Vernet 	toggle_online_status(1);
121*a5db7817SDavid Vernet 
122*a5db7817SDavid Vernet 	SCX_ASSERT(link);
123*a5db7817SDavid Vernet 	while (!UEI_EXITED(skel, uei))
124*a5db7817SDavid Vernet 		sched_yield();
125*a5db7817SDavid Vernet 
126*a5db7817SDavid Vernet 	kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
127*a5db7817SDavid Vernet 	code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
128*a5db7817SDavid Vernet 	       SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
129*a5db7817SDavid Vernet 	SCX_EQ(skel->data->uei.kind, kind);
130*a5db7817SDavid Vernet 	SCX_EQ(UEI_REPORT(skel, uei), code);
131*a5db7817SDavid Vernet 
132*a5db7817SDavid Vernet 	bpf_link__destroy(link);
133*a5db7817SDavid Vernet 	hotplug__destroy(skel);
134*a5db7817SDavid Vernet 
135*a5db7817SDavid Vernet 	return status;
136*a5db7817SDavid Vernet }
137*a5db7817SDavid Vernet 
run(void * ctx)138*a5db7817SDavid Vernet static enum scx_test_status run(void *ctx)
139*a5db7817SDavid Vernet {
140*a5db7817SDavid Vernet 
141*a5db7817SDavid Vernet #define HP_TEST(__onlining, __cbs_defined) ({				\
142*a5db7817SDavid Vernet 	if (test_hotplug(__onlining, __cbs_defined) != SCX_TEST_PASS)	\
143*a5db7817SDavid Vernet 		return SCX_TEST_FAIL;					\
144*a5db7817SDavid Vernet })
145*a5db7817SDavid Vernet 
146*a5db7817SDavid Vernet 	HP_TEST(true, true);
147*a5db7817SDavid Vernet 	HP_TEST(false, true);
148*a5db7817SDavid Vernet 	HP_TEST(true, false);
149*a5db7817SDavid Vernet 	HP_TEST(false, false);
150*a5db7817SDavid Vernet 
151*a5db7817SDavid Vernet #undef HP_TEST
152*a5db7817SDavid Vernet 
153*a5db7817SDavid Vernet 	return test_hotplug_attach();
154*a5db7817SDavid Vernet }
155*a5db7817SDavid Vernet 
cleanup(void * ctx)156*a5db7817SDavid Vernet static void cleanup(void *ctx)
157*a5db7817SDavid Vernet {
158*a5db7817SDavid Vernet 	toggle_online_status(1);
159*a5db7817SDavid Vernet }
160*a5db7817SDavid Vernet 
161*a5db7817SDavid Vernet struct scx_test hotplug_test = {
162*a5db7817SDavid Vernet 	.name = "hotplug",
163*a5db7817SDavid Vernet 	.description = "Verify hotplug behavior",
164*a5db7817SDavid Vernet 	.setup = setup,
165*a5db7817SDavid Vernet 	.run = run,
166*a5db7817SDavid Vernet 	.cleanup = cleanup,
167*a5db7817SDavid Vernet };
168*a5db7817SDavid Vernet REGISTER_SCX_TEST(&hotplug_test)
169