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 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 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 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 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 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 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 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