Linux Audio

Check our new training course

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