diff --git a/tools/testing/selftests/scx/.gitignore b/tools/testing/selftests/scx/.gitignore index 53d7057113aa..ae5491a114c0 100644 --- a/tools/testing/selftests/scx/.gitignore +++ b/tools/testing/selftests/scx/.gitignore @@ -1,15 +1,6 @@ -ddsp_bogus_dsq_fail -ddsp_vtimelocal_fail -enq_last_no_enq_fails -enq_select_cpu_fails -init_enable_count -maximal -minimal -runner -select_cpu_dfl -select_cpu_dfl_nodispatch -select_cpu_dispatch -select_cpu_dispatch_dbl_dsp -select_cpu_dispatch_bad_dsq -select_cpu_vtime -build/ +* +!*.c +!*.h +!Makefile +!.gitignore +!config diff --git a/tools/testing/selftests/scx/Makefile b/tools/testing/selftests/scx/Makefile index 4e8e5fe525ef..c8d5231af31d 100644 --- a/tools/testing/selftests/scx/Makefile +++ b/tools/testing/selftests/scx/Makefile @@ -155,22 +155,28 @@ override define CLEAN rm -f runner endef +# Every testcase takes all of the BPF progs are dependencies by default. This +# allows testcases to load any BPF scheduler, which is useful for testcases +# that don't need their own prog to run their test. +all_test_bpfprogs := $(foreach prog,$(wildcard *.bpf.c),$(INCLUDE_DIR)/$(patsubst %.c,%.skel.h,$(prog))) + auto-test-targets := \ enq_last_no_enq_fails \ enq_select_cpu_fails \ ddsp_bogus_dsq_fail \ ddsp_vtimelocal_fail \ init_enable_count \ - maybe_null \ maximal \ + maybe_null \ minimal \ + reload_loop \ 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 + test_example \ testcase-targets := $(addsuffix .o,$(addprefix $(SCXOBJ_DIR)/,$(auto-test-targets))) @@ -183,11 +189,7 @@ $(SCXOBJ_DIR)/runner.o: runner.c | $(SCXOBJ_DIR) # Note that we must do double expansion here in order to support conditionally # compiling BPF object files only if one is present, as the wildcard Make # function doesn't support using implicit rules otherwise. -.SECONDEXPANSION: -$(testcase-targets): $(SCXOBJ_DIR)/%.o: %.c $(SCXOBJ_DIR)/runner.o \ - $$(if $$(wildcard $$*.bpf.c), $(INCLUDE_DIR)/%.bpf.skel.h) \ - $$(if $$(wildcard $$*_fail.bpf.c), $(INCLUDE_DIR)/%_fail.bpf.skel.h) \ - | $(SCXOBJ_DIR) +$(testcase-targets): $(SCXOBJ_DIR)/%.o: %.c $(SCXOBJ_DIR)/runner.o $(all_test_bpfprogs) | $(SCXOBJ_DIR) $(eval test=$(patsubst %.o,%.c,$(notdir $@))) $(CC) $(CFLAGS) -c $< -o $@ $(SCXOBJ_DIR)/runner.o diff --git a/tools/testing/selftests/scx/maximal.bpf.c b/tools/testing/selftests/scx/maximal.bpf.c index 1f563ef40084..00bfa9cb95d3 100644 --- a/tools/testing/selftests/scx/maximal.bpf.c +++ b/tools/testing/selftests/scx/maximal.bpf.c @@ -6,7 +6,6 @@ * * Copyright (c) 2024 Meta Platforms, Inc. and affiliates. * Copyright (c) 2024 David Vernet - * Copyright (c) 2024 Tejun Heo */ #include diff --git a/tools/testing/selftests/scx/maximal.c b/tools/testing/selftests/scx/maximal.c index cd69c42c8185..f38fc973c380 100644 --- a/tools/testing/selftests/scx/maximal.c +++ b/tools/testing/selftests/scx/maximal.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2024 Meta Platforms, Inc. and affiliates. * Copyright (c) 2024 David Vernet - * Copyright (c) 2024 Tejun Heo */ #include #include diff --git a/tools/testing/selftests/scx/reload_loop.c b/tools/testing/selftests/scx/reload_loop.c new file mode 100644 index 000000000000..5cfba2d6e056 --- /dev/null +++ b/tools/testing/selftests/scx/reload_loop.c @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Meta Platforms, Inc. and affiliates. + * Copyright (c) 2024 David Vernet + */ +#include +#include +#include +#include +#include +#include "maximal.bpf.skel.h" +#include "scx_test.h" + +static struct maximal *skel; +static pthread_t threads[2]; + +bool force_exit = false; + +static enum scx_test_status setup(void **ctx) +{ + skel = maximal__open_and_load(); + if (!skel) { + SCX_ERR("Failed to open and load skel"); + return SCX_TEST_FAIL; + } + + return SCX_TEST_PASS; +} + +static void *do_reload_loop(void *arg) +{ + u32 i; + + for (i = 0; i < 1024 && !force_exit; i++) { + struct bpf_link *link; + + link = bpf_map__attach_struct_ops(skel->maps.maximal_ops); + if (link) + bpf_link__destroy(link); + } + + return NULL; +} + +static enum scx_test_status run(void *ctx) +{ + int err; + void *ret; + + err = pthread_create(&threads[0], NULL, do_reload_loop, NULL); + SCX_FAIL_IF(err, "Failed to create thread 0"); + + err = pthread_create(&threads[1], NULL, do_reload_loop, NULL); + SCX_FAIL_IF(err, "Failed to create thread 1"); + + SCX_FAIL_IF(pthread_join(threads[0], &ret), "thread 0 failed"); + SCX_FAIL_IF(pthread_join(threads[1], &ret), "thread 1 failed"); + + return SCX_TEST_PASS; +} + +static void cleanup(void *ctx) +{ + force_exit = true; + maximal__destroy(skel); +} + +struct scx_test reload_loop = { + .name = "reload_loop", + .description = "Stress test loading and unloading schedulers repeatedly in a tight loop", + .setup = setup, + .run = run, + .cleanup = cleanup, +}; +REGISTER_SCX_TEST(&reload_loop)