diff --git a/tools/testing/selftests/scx/Makefile b/tools/testing/selftests/scx/Makefile index c28f23c0442cc5..c3bf6c19dccf08 100644 --- a/tools/testing/selftests/scx/Makefile +++ b/tools/testing/selftests/scx/Makefile @@ -147,20 +147,6 @@ $(INCLUDE_DIR)/%.bpf.skel.h: $(SCXOBJ_DIR)/%.bpf.o $(INCLUDE_DIR)/vmlinux.h $(BP ################ # C schedulers # ################ -c-sched-targets := \ - select_cpu_dfl \ - select_cpu_dfl_nodispatch \ - select_cpu_dispatch \ - select_cpu_dispatch_bad_dsq \ - select_cpu_dispatch_dbl_dsp \ - select_cpu_vtime - -$(c-sched-targets): %: $(filter-out %.bpf.c,%.c) $(INCLUDE_DIR)/%.bpf.skel.h - $(eval sched=$(notdir $@)) - $(CC) $(CFLAGS) -c $(sched).c -o $(SCXOBJ_DIR)/$(sched).o - $(CC) -o $@ $(SCXOBJ_DIR)/$(sched).o $(LIBBPF_OUTPUT) $(LDFLAGS) - -TEST_GEN_PROGS := $(c-sched-targets) override define CLEAN rm -rf $(OUTPUT_DIR) @@ -176,6 +162,12 @@ auto-test-targets := \ ddsp_vtimelocal_fail \ init_enable_count \ minimal \ + select_cpu_dfl \ + select_cpu_dfl_nodispatch \ + select_cpu_dispatch \ + select_cpu_dispatch_bad_dsq \ + select_cpu_dispatch_dbl_dsp \ + select_cpu_vtime \ test_example testcase-targets := $(addsuffix .o,$(addprefix $(SCXOBJ_DIR)/,$(auto-test-targets))) @@ -198,6 +190,8 @@ runner: $(SCXOBJ_DIR)/runner.o $(BPFOBJ) $(testcase-targets) @echo "$(testcase-targets)" $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ +TEST_GEN_PROGS := runner + all: runner .PHONY: all clean help diff --git a/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.bpf.c b/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.bpf.c index 78bd8feace0503..dd32b189911ef7 100644 --- a/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.bpf.c +++ b/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.bpf.c @@ -8,6 +8,8 @@ char _license[] SEC("license") = "GPL"; +struct user_exit_info uei; + s32 BPF_STRUCT_OPS(ddsp_bogus_dsq_fail_select_cpu, struct task_struct *p, s32 prev_cpu, u64 wake_flags) { @@ -26,6 +28,11 @@ s32 BPF_STRUCT_OPS(ddsp_bogus_dsq_fail_select_cpu, struct task_struct *p, return prev_cpu; } +void BPF_STRUCT_OPS(ddsp_bogus_dsq_fail_exit, struct scx_exit_info *ei) +{ + uei_record(&uei, ei); +} + s32 BPF_STRUCT_OPS(ddsp_bogus_dsq_fail_init) { scx_bpf_switch_all(); @@ -36,6 +43,7 @@ s32 BPF_STRUCT_OPS(ddsp_bogus_dsq_fail_init) SEC(".struct_ops.link") struct sched_ext_ops ddsp_bogus_dsq_fail_ops = { .select_cpu = ddsp_bogus_dsq_fail_select_cpu, + .exit = ddsp_bogus_dsq_fail_exit, .init = ddsp_bogus_dsq_fail_init, .name = "ddsp_bogus_dsq_fail", .timeout_ms = 1000U, diff --git a/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.c b/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.c index b12e804a0b6640..ef8ee04ff98716 100644 --- a/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.c +++ b/tools/testing/selftests/scx/ddsp_bogus_dsq_fail.c @@ -31,6 +31,8 @@ static enum scx_test_status run(void *ctx) SCX_FAIL_IF(!link, "Failed to attach struct_ops"); sleep(1); + + SCX_EQ(skel->bss->uei.kind, SCX_EXIT_ERROR); bpf_link__destroy(link); return SCX_TEST_PASS; diff --git a/tools/testing/selftests/scx/ddsp_vtimelocal_fail.bpf.c b/tools/testing/selftests/scx/ddsp_vtimelocal_fail.bpf.c index 14a40be192c5d3..9b21c1d57861cf 100644 --- a/tools/testing/selftests/scx/ddsp_vtimelocal_fail.bpf.c +++ b/tools/testing/selftests/scx/ddsp_vtimelocal_fail.bpf.c @@ -8,6 +8,8 @@ char _license[] SEC("license") = "GPL"; +struct user_exit_info uei; + s32 BPF_STRUCT_OPS(ddsp_vtimelocal_fail_select_cpu, struct task_struct *p, s32 prev_cpu, u64 wake_flags) { @@ -23,6 +25,11 @@ s32 BPF_STRUCT_OPS(ddsp_vtimelocal_fail_select_cpu, struct task_struct *p, return prev_cpu; } +void BPF_STRUCT_OPS(ddsp_vtimelocal_fail_exit, struct scx_exit_info *ei) +{ + uei_record(&uei, ei); +} + s32 BPF_STRUCT_OPS(ddsp_vtimelocal_fail_init) { scx_bpf_switch_all(); @@ -34,6 +41,7 @@ SEC(".struct_ops.link") struct sched_ext_ops ddsp_vtimelocal_fail_ops = { .select_cpu = ddsp_vtimelocal_fail_select_cpu, .init = ddsp_vtimelocal_fail_init, + .exit = ddsp_vtimelocal_fail_exit, .name = "ddsp_vtimelocal_fail", .timeout_ms = 1000U, }; diff --git a/tools/testing/selftests/scx/ddsp_vtimelocal_fail.c b/tools/testing/selftests/scx/ddsp_vtimelocal_fail.c index 03bbadfaaf2f19..b55611cd0b1fba 100644 --- a/tools/testing/selftests/scx/ddsp_vtimelocal_fail.c +++ b/tools/testing/selftests/scx/ddsp_vtimelocal_fail.c @@ -30,6 +30,8 @@ static enum scx_test_status run(void *ctx) SCX_FAIL_IF(!link, "Failed to attach struct_ops"); sleep(1); + + SCX_EQ(skel->bss->uei.kind, SCX_EXIT_ERROR); bpf_link__destroy(link); return SCX_TEST_PASS; diff --git a/tools/testing/selftests/scx/scx_test.h b/tools/testing/selftests/scx/scx_test.h index e402031c2a84ed..4b70bf75fa8140 100644 --- a/tools/testing/selftests/scx/scx_test.h +++ b/tools/testing/selftests/scx/scx_test.h @@ -17,6 +17,19 @@ enum scx_test_status { SCX_TEST_FAIL, }; +/* Copied from include/linux/sched/ext.h */ +enum scx_test_exit_kind { + SCX_EXIT_NONE, + SCX_EXIT_DONE, + + SCX_EXIT_UNREG = 64, /* BPF unregistration */ + SCX_EXIT_SYSRQ, /* requested by 'S' sysrq */ + + SCX_EXIT_ERROR = 1024, /* runtime error, error msg contains details */ + SCX_EXIT_ERROR_BPF, /* ERROR but triggered through scx_bpf_error() */ + SCX_EXIT_ERROR_STALL, /* watchdog detected stalled runnable tasks */ +}; + struct scx_test { /** * name - The name of the testcase. diff --git a/tools/testing/selftests/scx/select_cpu_dfl.c b/tools/testing/selftests/scx/select_cpu_dfl.c index 2962be1bec5181..a53a40c2d2f0fe 100644 --- a/tools/testing/selftests/scx/select_cpu_dfl.c +++ b/tools/testing/selftests/scx/select_cpu_dfl.c @@ -4,32 +4,35 @@ * Copyright (c) 2023 David Vernet * Copyright (c) 2023 Tejun Heo */ -#include -#include -#include -#include #include #include #include +#include #include "select_cpu_dfl.bpf.skel.h" #include "scx_test.h" #define NUM_CHILDREN 1028 -int main(int argc, char **argv) +static enum scx_test_status setup(void **ctx) { struct select_cpu_dfl *skel; + + skel = select_cpu_dfl__open_and_load(); + SCX_FAIL_IF(!skel, "Failed to open and load skel"); + *ctx = skel; + + return SCX_TEST_PASS; +} + +static enum scx_test_status run(void *ctx) +{ + struct select_cpu_dfl *skel = ctx; struct bpf_link *link; pid_t pids[NUM_CHILDREN]; int i, status; - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - - skel = select_cpu_dfl__open_and_load(); - SCX_BUG_ON(!skel, "Failed to open and load skel"); - link = bpf_map__attach_struct_ops(skel->maps.select_cpu_dfl_ops); - SCX_BUG_ON(!link, "Failed to attach struct_ops"); + SCX_FAIL_IF(!link, "Failed to attach scheduler"); for (i = 0; i < NUM_CHILDREN; i++) { pids[i] = fork(); @@ -45,8 +48,25 @@ int main(int argc, char **argv) } SCX_ASSERT(!skel->bss->saw_local); + bpf_link__destroy(link); - select_cpu_dfl__destroy(skel); - return 0; + return SCX_TEST_PASS; } + +static void cleanup(void *ctx) +{ + struct select_cpu_dfl *skel = ctx; + + select_cpu_dfl__destroy(skel); +} + +struct scx_test select_cpu_dfl = { + .name = "select_cpu_dfl", + .description = "Verify the default ops.select_cpu() dispatches tasks " + "when idles cores are found, and skips ops.enqueue()", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&select_cpu_dfl) diff --git a/tools/testing/selftests/scx/select_cpu_dfl_nodispatch.c b/tools/testing/selftests/scx/select_cpu_dfl_nodispatch.c index 3121b28c81ed03..1d85bf4bf3a39b 100644 --- a/tools/testing/selftests/scx/select_cpu_dfl_nodispatch.c +++ b/tools/testing/selftests/scx/select_cpu_dfl_nodispatch.c @@ -1,35 +1,38 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. - * Copyright (c) 2023 Tejun Heo * Copyright (c) 2023 David Vernet + * Copyright (c) 2023 Tejun Heo */ -#include -#include -#include -#include #include #include #include +#include #include "select_cpu_dfl_nodispatch.bpf.skel.h" #include "scx_test.h" #define NUM_CHILDREN 1028 -int main(int argc, char **argv) +static enum scx_test_status setup(void **ctx) { struct select_cpu_dfl_nodispatch *skel; + + skel = select_cpu_dfl_nodispatch__open_and_load(); + SCX_FAIL_IF(!skel, "Failed to open and load skel"); + *ctx = skel; + + return SCX_TEST_PASS; +} + +static enum scx_test_status run(void *ctx) +{ + struct select_cpu_dfl_nodispatch *skel = ctx; struct bpf_link *link; pid_t pids[NUM_CHILDREN]; int i, status; - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - - skel = select_cpu_dfl_nodispatch__open_and_load(); - SCX_BUG_ON(!skel, "Failed to open and load skel"); - link = bpf_map__attach_struct_ops(skel->maps.select_cpu_dfl_nodispatch_ops); - SCX_BUG_ON(!link, "Failed to attach struct_ops"); + SCX_FAIL_IF(!link, "Failed to attach scheduler"); for (i = 0; i < NUM_CHILDREN; i++) { pids[i] = fork(); @@ -45,8 +48,25 @@ int main(int argc, char **argv) } SCX_ASSERT(skel->bss->saw_local); + bpf_link__destroy(link); - select_cpu_dfl_nodispatch__destroy(skel); - return 0; + return SCX_TEST_PASS; +} + +static void cleanup(void *ctx) +{ + struct select_cpu_dfl_nodispatch *skel = ctx; + + select_cpu_dfl_nodispatch__destroy(skel); } + +struct scx_test select_cpu_dfl_nodispatch = { + .name = "select_cpu_dfl_nodispatch", + .description = "Verify behavior of scx_bpf_select_cpu_dfl() in " + "ops.select_cpu()", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&select_cpu_dfl_nodispatch) diff --git a/tools/testing/selftests/scx/select_cpu_dispatch.c b/tools/testing/selftests/scx/select_cpu_dispatch.c index a3625f75db720d..0309ca8785b362 100644 --- a/tools/testing/selftests/scx/select_cpu_dispatch.c +++ b/tools/testing/selftests/scx/select_cpu_dispatch.c @@ -4,32 +4,35 @@ * Copyright (c) 2023 David Vernet * Copyright (c) 2023 Tejun Heo */ -#include -#include -#include -#include #include #include #include +#include #include "select_cpu_dispatch.bpf.skel.h" #include "scx_test.h" #define NUM_CHILDREN 1028 -int main(int argc, char **argv) +static enum scx_test_status setup(void **ctx) { struct select_cpu_dispatch *skel; + + skel = select_cpu_dispatch__open_and_load(); + SCX_FAIL_IF(!skel, "Failed to open and load skel"); + *ctx = skel; + + return SCX_TEST_PASS; +} + +static enum scx_test_status run(void *ctx) +{ + struct select_cpu_dispatch *skel = ctx; struct bpf_link *link; pid_t pids[NUM_CHILDREN]; int i, status; - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - - skel = select_cpu_dispatch__open_and_load(); - SCX_BUG_ON(!skel, "Failed to open and load skel"); - link = bpf_map__attach_struct_ops(skel->maps.select_cpu_dispatch_ops); - SCX_BUG_ON(!link, "Failed to attach struct_ops"); + SCX_FAIL_IF(!link, "Failed to attach scheduler"); for (i = 0; i < NUM_CHILDREN; i++) { pids[i] = fork(); @@ -44,9 +47,24 @@ int main(int argc, char **argv) SCX_EQ(status, 0); } - bpf_link__destroy(link); - select_cpu_dispatch__destroy(skel); - return 0; + return SCX_TEST_PASS; } + +static void cleanup(void *ctx) +{ + struct select_cpu_dispatch *skel = ctx; + + select_cpu_dispatch__destroy(skel); +} + +struct scx_test select_cpu_dispatch = { + .name = "select_cpu_dispatch", + .description = "Test direct dispatching to built-in DSQs from " + "ops.select_cpu()", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&select_cpu_dispatch) diff --git a/tools/testing/selftests/scx/select_cpu_dispatch_bad_dsq.c b/tools/testing/selftests/scx/select_cpu_dispatch_bad_dsq.c index f1094e3645d619..a7b91d58cb3188 100644 --- a/tools/testing/selftests/scx/select_cpu_dispatch_bad_dsq.c +++ b/tools/testing/selftests/scx/select_cpu_dispatch_bad_dsq.c @@ -4,54 +4,53 @@ * Copyright (c) 2023 David Vernet * Copyright (c) 2023 Tejun Heo */ -#include -#include -#include -#include #include #include #include +#include #include "select_cpu_dispatch_bad_dsq.bpf.skel.h" #include "scx_test.h" -#define NUM_CHILDREN 1028 -#define SCX_EXIT_ERROR 1024 - -int main(int argc, char **argv) +static enum scx_test_status setup(void **ctx) { struct select_cpu_dispatch_bad_dsq *skel; - struct bpf_link *link; - pid_t pids[NUM_CHILDREN]; - int i, status; - - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); skel = select_cpu_dispatch_bad_dsq__open_and_load(); - SCX_BUG_ON(!skel, "Failed to open and load skel"); + SCX_FAIL_IF(!skel, "Failed to open and load skel"); + *ctx = skel; - /* - * The scheduler is expected to gracefully exit after bad_dsqoneously - * double-dispatching from ops.selec_cpu(). - */ - link = bpf_map__attach_struct_ops(skel->maps.select_cpu_dispatch_bad_dsq_ops); - SCX_BUG_ON(!link, "Failed to attach struct_ops"); + return SCX_TEST_PASS; +} + +static enum scx_test_status run(void *ctx) +{ + struct select_cpu_dispatch_bad_dsq *skel = ctx; + struct bpf_link *link; - for (i = 0; i < NUM_CHILDREN; i++) { - pids[i] = fork(); - if (pids[i] == 0) { - sleep(1); - exit(0); - } - } + link = bpf_map__attach_struct_ops(skel->maps.select_cpu_dispatch_bad_dsq_ops); + SCX_FAIL_IF(!link, "Failed to attach scheduler"); - for (i = 0; i < NUM_CHILDREN; i++) { - SCX_EQ(waitpid(pids[i], &status, 0), pids[i]); - SCX_EQ(status, 0); - } + sleep(1); SCX_EQ(skel->bss->uei.kind, SCX_EXIT_ERROR); bpf_link__destroy(link); - select_cpu_dispatch_bad_dsq__destroy(skel); - return 0; + return SCX_TEST_PASS; } + +static void cleanup(void *ctx) +{ + struct select_cpu_dispatch_bad_dsq *skel = ctx; + + select_cpu_dispatch_bad_dsq__destroy(skel); +} + +struct scx_test select_cpu_dispatch_bad_dsq = { + .name = "select_cpu_dispatch_bad_dsq", + .description = "Verify graceful failure if we direct-dispatch to a " + "bogus DSQ in ops.select_cpu()", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&select_cpu_dispatch_bad_dsq) diff --git a/tools/testing/selftests/scx/select_cpu_dispatch_dbl_dsp.c b/tools/testing/selftests/scx/select_cpu_dispatch_dbl_dsp.c index 9736b65f79bd0c..e32b2296374488 100644 --- a/tools/testing/selftests/scx/select_cpu_dispatch_dbl_dsp.c +++ b/tools/testing/selftests/scx/select_cpu_dispatch_dbl_dsp.c @@ -4,54 +4,53 @@ * Copyright (c) 2023 David Vernet * Copyright (c) 2023 Tejun Heo */ -#include -#include -#include -#include #include #include #include +#include #include "select_cpu_dispatch_dbl_dsp.bpf.skel.h" #include "scx_test.h" -#define NUM_CHILDREN 1028 -#define SCX_EXIT_ERROR 1024 - -int main(int argc, char **argv) +static enum scx_test_status setup(void **ctx) { struct select_cpu_dispatch_dbl_dsp *skel; - struct bpf_link *link; - pid_t pids[NUM_CHILDREN]; - int i, status; - - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); skel = select_cpu_dispatch_dbl_dsp__open_and_load(); - SCX_BUG_ON(!skel, "Failed to open and load skel"); + SCX_FAIL_IF(!skel, "Failed to open and load skel"); + *ctx = skel; - /* - * The scheduler is expected to gracefully exit after - * double-dispatching from ops.select_cpu(). - */ - link = bpf_map__attach_struct_ops(skel->maps.select_cpu_dispatch_dbl_dsp_ops); - SCX_BUG_ON(!link, "Failed to attach struct_ops"); + return SCX_TEST_PASS; +} + +static enum scx_test_status run(void *ctx) +{ + struct select_cpu_dispatch_dbl_dsp *skel = ctx; + struct bpf_link *link; - for (i = 0; i < NUM_CHILDREN; i++) { - pids[i] = fork(); - if (pids[i] == 0) { - sleep(1); - exit(0); - } - } + link = bpf_map__attach_struct_ops(skel->maps.select_cpu_dispatch_dbl_dsp_ops); + SCX_FAIL_IF(!link, "Failed to attach scheduler"); - for (i = 0; i < NUM_CHILDREN; i++) { - SCX_EQ(waitpid(pids[i], &status, 0), pids[i]); - SCX_EQ(status, 0); - } + sleep(1); SCX_EQ(skel->bss->uei.kind, SCX_EXIT_ERROR); bpf_link__destroy(link); - select_cpu_dispatch_dbl_dsp__destroy(skel); - return 0; + return SCX_TEST_PASS; } + +static void cleanup(void *ctx) +{ + struct select_cpu_dispatch_dbl_dsp *skel = ctx; + + select_cpu_dispatch_dbl_dsp__destroy(skel); +} + +struct scx_test select_cpu_dispatch_dbl_dsp = { + .name = "select_cpu_dispatch_dbl_dsp", + .description = "Verify graceful failure if we dispatch twice to a " + "DSQ in ops.select_cpu()", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&select_cpu_dispatch_dbl_dsp) diff --git a/tools/testing/selftests/scx/select_cpu_vtime.c b/tools/testing/selftests/scx/select_cpu_vtime.c index 6f72f0625478c7..b4629c2364f5db 100644 --- a/tools/testing/selftests/scx/select_cpu_vtime.c +++ b/tools/testing/selftests/scx/select_cpu_vtime.c @@ -4,36 +4,56 @@ * Copyright (c) 2024 David Vernet * Copyright (c) 2024 Tejun Heo */ -#include -#include -#include #include #include #include +#include #include "select_cpu_vtime.bpf.skel.h" #include "scx_test.h" -int main(int argc, char **argv) +static enum scx_test_status setup(void **ctx) { struct select_cpu_vtime *skel; - struct bpf_link *link; - - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); skel = select_cpu_vtime__open_and_load(); - SCX_BUG_ON(!skel, "Failed to open and load skel"); + SCX_FAIL_IF(!skel, "Failed to open and load skel"); + *ctx = skel; + + return SCX_TEST_PASS; +} + +static enum scx_test_status run(void *ctx) +{ + struct select_cpu_vtime *skel = ctx; + struct bpf_link *link; SCX_ASSERT(!skel->bss->consumed); link = bpf_map__attach_struct_ops(skel->maps.select_cpu_vtime_ops); - SCX_BUG_ON(!link, "Failed to attach struct_ops"); + SCX_FAIL_IF(!link, "Failed to attach scheduler"); sleep(1); SCX_ASSERT(skel->bss->consumed); bpf_link__destroy(link); - select_cpu_vtime__destroy(skel); - return 0; + return SCX_TEST_PASS; +} + +static void cleanup(void *ctx) +{ + struct select_cpu_vtime *skel = ctx; + + select_cpu_vtime__destroy(skel); } + +struct scx_test select_cpu_vtime = { + .name = "select_cpu_vtime", + .description = "Test doing direct vtime-dispatching from " + "ops.select_cpu(), to a non-built-in DSQ", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&select_cpu_vtime)