Test worker fleet
include/test/fleet.h View source View on GitHubWorker thread fleets
The idea here: we have a pointer to one of these in struct test_context.
When a test needs a fleet, it simply test_fleet_init()’s the ctx
fleet, and the runner will handle cleanup.
Tests must not free their fleets, and
Add mechanisms to track the running context (test, harness, etc.) so in the future, we can detect and panic if a test tries to free its fleet
Structs
Section titled “Structs”test_fleet_worker_opts
Section titled “test_fleet_worker_opts” struct test_fleet_worker_opts (5 fields) source
Options for spawning individual workers in a fleet
bool pinned void *arg enum thread_prio_class prio_class enum thread_flags flags test_fleet_opts
Section titled “test_fleet_opts” struct test_fleet_opts (4 fields) source
test_fleet
Section titled “test_fleet” struct test_fleet (19 fields) source
struct test_context *ctx struct test_conc_worker workers[TEST_FLEET_MAX_WORKERS] test_worker_fn bodies[TEST_FLEET_MAX_WORKERS] size_t count struct test_fleet_opts opts struct test_fleet_alloc *allocs This is a wrapper to prevent tests from manually managing their memory. It’s the head of a SLIST of nodes, and at test exit, we iterate over it and free everything
We really need to make such abstractions a global primitive to embed allocators instead of making them ad-hoc.
size_t subject_count workers[0, subject_count) are subjects, and the rest are perturbers
bool has_perturbers struct test_perturb_env perturb_env const char *fail_file uint32_t fail_line atomic_size_t started atomic_size_t finished struct test_liveness_state liveness bool hard_armed bool joined Type Aliases
Section titled “Type Aliases”test_worker_fn
Section titled “test_worker_fn”typedef bool (*test_worker_fn)(
struct test_fleet * f,
struct test_conc_worker * self
) source Worker threads return false to say “I tripped some assertion”, and the outer loop captures that
Functions
Section titled “Functions”test_fleet_init_full
Section titled “test_fleet_init_full”struct test_fleet * test_fleet_init_full(
struct test_context *ctx,
const struct test_fleet_opts opts
) source test_fleet_alloc
Section titled “test_fleet_alloc”void * test_fleet_alloc(struct test_fleet *f, size_t size) source test_fleet_spawn_full
Section titled “test_fleet_spawn_full”struct test_conc_worker * test_fleet_spawn_full(
struct test_fleet *f,
const char *role,
test_worker_fn body,
const struct test_fleet_worker_opts opts
) source Spawn with custom worker options (affinity, priority class, flags)
test_fleet_worker_thread
Section titled “test_fleet_worker_thread”struct thread * test_fleet_worker_thread(
struct test_fleet *f,
const char *role
) source Look up a worker thread by its role name
test_fleet_spawn_per_core
Section titled “test_fleet_spawn_per_core”size_t test_fleet_spawn_per_core(
struct test_fleet *f,
const char *role,
test_worker_fn body,
void *arg,
size_t per_core
) source Spawn N many per CPU
test_fleet_spawn_perturbers
Section titled “test_fleet_spawn_perturbers”size_t test_fleet_spawn_perturbers(
struct test_fleet *f,
const char *const *names,
int64_t victim_cpu
) source Background noise against every worker, one perturber per name
test_fleet_start_all
Section titled “test_fleet_start_all”void test_fleet_start_all(struct test_fleet *f) source Open the gates for the workers
test_fleet_join
Section titled “test_fleet_join”struct test_verdict test_fleet_join(struct test_fleet *f) source test_fleet_must_stop
Section titled “test_fleet_must_stop”bool test_fleet_must_stop(const struct test_fleet *f) source test_fleet_must_park
Section titled “test_fleet_must_park”bool test_fleet_must_park(const struct test_fleet *f) source test_fleet_park
Section titled “test_fleet_park”void test_fleet_park(struct test_fleet *f, struct test_conc_worker *w) source test_fleet_stop
Section titled “test_fleet_stop”void test_fleet_stop(struct test_fleet *f, enum test_stop reason) source test_run_on_core
Section titled “test_run_on_core”Runs a singular function on a given CPU from another thread’s context, and then waits to join
test_fleet_teardown
Section titled “test_fleet_teardown”bool test_fleet_teardown(struct test_context *ctx) source runner context only, NOT in the test
Macros
Section titled “Macros”TEST_FLEET_MAX_WORKERS
Section titled “TEST_FLEET_MAX_WORKERS”TEST_FLEET_SOFT_MS
Section titled “TEST_FLEET_SOFT_MS”#define TEST_FLEET_SOFT_MS 30000 source TEST_FLEET_DRAIN_MS
Section titled “TEST_FLEET_DRAIN_MS”#define TEST_FLEET_DRAIN_MS 10000 source Give some leeway for the workers to calm down
test_fleet_opts_with_defaults
Section titled “test_fleet_opts_with_defaults”#define test_fleet_opts_with_defaults(...) source Expansion
#define test_fleet_opts_with_defaults(...) \
cc_wno_override_init_expr( \
struct test_fleet_opts, \
((struct test_fleet_opts) {.soft_ms = TEST_FLEET_SOFT_MS, \
.drain_ms = TEST_FLEET_DRAIN_MS, \
##__VA_ARGS__})) test_fleet_init
Section titled “test_fleet_init”#define test_fleet_init(ctx, ...) source Expansion
#define test_fleet_init(ctx, ...) \
test_fleet_init_full((ctx), test_fleet_opts_with_defaults(__VA_ARGS__)) test_fleet_worker_opts_with_defaults
Section titled “test_fleet_worker_opts_with_defaults”#define test_fleet_worker_opts_with_defaults(...) source Expansion
#define test_fleet_worker_opts_with_defaults(...) \
cc_wno_override_init_expr(struct test_fleet_worker_opts, \
((struct test_fleet_worker_opts) { \
.core_id = CPU_ID_MAX, \
.prio_class = THREAD_PRIO_CLASS_TIMESHARE, \
.pinned = false, \
##__VA_ARGS__})) test_fleet_spawn
Section titled “test_fleet_spawn”#define test_fleet_spawn(f, role, body, ...) source Expansion
#define test_fleet_spawn(f, role, body, ...) \
test_fleet_spawn_full((f), (role), (body), \
test_fleet_worker_opts_with_defaults(__VA_ARGS__))