169 lines
3.6 KiB
C
169 lines
3.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
|
|
* Copyright (c) 2024 David Vernet <dvernet@meta.com>
|
|
*/
|
|
#include <bpf/bpf.h>
|
|
#include <sched.h>
|
|
#include <scx/common.h>
|
|
#include <sched.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
#include "hotplug_test.h"
|
|
#include "hotplug.bpf.skel.h"
|
|
#include "scx_test.h"
|
|
#include "util.h"
|
|
|
|
const char *online_path = "/sys/devices/system/cpu/cpu1/online";
|
|
|
|
static bool is_cpu_online(void)
|
|
{
|
|
return file_read_long(online_path) > 0;
|
|
}
|
|
|
|
static void toggle_online_status(bool online)
|
|
{
|
|
long val = online ? 1 : 0;
|
|
int ret;
|
|
|
|
ret = file_write_long(online_path, val);
|
|
if (ret != 0)
|
|
fprintf(stderr, "Failed to bring CPU %s (%s)",
|
|
online ? "online" : "offline", strerror(errno));
|
|
}
|
|
|
|
static enum scx_test_status setup(void **ctx)
|
|
{
|
|
if (!is_cpu_online())
|
|
return SCX_TEST_SKIP;
|
|
|
|
return SCX_TEST_PASS;
|
|
}
|
|
|
|
static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
|
|
{
|
|
struct hotplug *skel;
|
|
struct bpf_link *link;
|
|
long kind, code;
|
|
|
|
SCX_ASSERT(is_cpu_online());
|
|
|
|
skel = hotplug__open_and_load();
|
|
SCX_ASSERT(skel);
|
|
|
|
/* Testing the offline -> online path, so go offline before starting */
|
|
if (onlining)
|
|
toggle_online_status(0);
|
|
|
|
if (cbs_defined) {
|
|
kind = SCX_KIND_VAL(SCX_EXIT_UNREG_BPF);
|
|
code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) | HOTPLUG_EXIT_RSN;
|
|
if (onlining)
|
|
code |= HOTPLUG_ONLINING;
|
|
} else {
|
|
kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
|
|
code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
|
|
SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
|
|
}
|
|
|
|
if (cbs_defined)
|
|
link = bpf_map__attach_struct_ops(skel->maps.hotplug_cb_ops);
|
|
else
|
|
link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
|
|
|
|
if (!link) {
|
|
SCX_ERR("Failed to attach scheduler");
|
|
hotplug__destroy(skel);
|
|
return SCX_TEST_FAIL;
|
|
}
|
|
|
|
toggle_online_status(onlining ? 1 : 0);
|
|
|
|
while (!UEI_EXITED(skel, uei))
|
|
sched_yield();
|
|
|
|
SCX_EQ(skel->data->uei.kind, kind);
|
|
SCX_EQ(UEI_REPORT(skel, uei), code);
|
|
|
|
if (!onlining)
|
|
toggle_online_status(1);
|
|
|
|
bpf_link__destroy(link);
|
|
hotplug__destroy(skel);
|
|
|
|
return SCX_TEST_PASS;
|
|
}
|
|
|
|
static enum scx_test_status test_hotplug_attach(void)
|
|
{
|
|
struct hotplug *skel;
|
|
struct bpf_link *link;
|
|
enum scx_test_status status = SCX_TEST_PASS;
|
|
long kind, code;
|
|
|
|
SCX_ASSERT(is_cpu_online());
|
|
SCX_ASSERT(scx_hotplug_seq() > 0);
|
|
|
|
skel = SCX_OPS_OPEN(hotplug_nocb_ops, hotplug);
|
|
SCX_ASSERT(skel);
|
|
|
|
SCX_OPS_LOAD(skel, hotplug_nocb_ops, hotplug, uei);
|
|
|
|
/*
|
|
* Take the CPU offline to increment the global hotplug seq, which
|
|
* should cause attach to fail due to us setting the hotplug seq above
|
|
*/
|
|
toggle_online_status(0);
|
|
link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
|
|
|
|
toggle_online_status(1);
|
|
|
|
SCX_ASSERT(link);
|
|
while (!UEI_EXITED(skel, uei))
|
|
sched_yield();
|
|
|
|
kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
|
|
code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
|
|
SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
|
|
SCX_EQ(skel->data->uei.kind, kind);
|
|
SCX_EQ(UEI_REPORT(skel, uei), code);
|
|
|
|
bpf_link__destroy(link);
|
|
hotplug__destroy(skel);
|
|
|
|
return status;
|
|
}
|
|
|
|
static enum scx_test_status run(void *ctx)
|
|
{
|
|
|
|
#define HP_TEST(__onlining, __cbs_defined) ({ \
|
|
if (test_hotplug(__onlining, __cbs_defined) != SCX_TEST_PASS) \
|
|
return SCX_TEST_FAIL; \
|
|
})
|
|
|
|
HP_TEST(true, true);
|
|
HP_TEST(false, true);
|
|
HP_TEST(true, false);
|
|
HP_TEST(false, false);
|
|
|
|
#undef HP_TEST
|
|
|
|
return test_hotplug_attach();
|
|
}
|
|
|
|
static void cleanup(void *ctx)
|
|
{
|
|
toggle_online_status(1);
|
|
}
|
|
|
|
struct scx_test hotplug_test = {
|
|
.name = "hotplug",
|
|
.description = "Verify hotplug behavior",
|
|
.setup = setup,
|
|
.run = run,
|
|
.cleanup = cleanup,
|
|
};
|
|
REGISTER_SCX_TEST(&hotplug_test)
|