From c847ec19adbed5e8cf7b7e25032263d26cbc0d8a Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Thu, 20 Mar 2025 13:13:01 +0100 Subject: [PATCH] Add noisy yield test in nOS-V Ensure we can call nosv_yield in a loop without generating a lot of events when using the level 3 instrumentation level. Noisy events are now moved to level 4, so they shouldn't appear on the trace. Additionally, make sure that the noisy events appear on level 4. --- test/rt/nosv/CMakeLists.txt | 4 +- test/rt/nosv/yield-noisy-l3.driver.sh | 30 +++++++++ test/rt/nosv/yield-noisy-l4.driver.sh | 38 ++++++++++++ test/rt/nosv/yield-noisy.c | 89 +++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 test/rt/nosv/yield-noisy-l3.driver.sh create mode 100644 test/rt/nosv/yield-noisy-l4.driver.sh create mode 100644 test/rt/nosv/yield-noisy.c diff --git a/test/rt/nosv/CMakeLists.txt b/test/rt/nosv/CMakeLists.txt index 47c95e2..8588273 100644 --- a/test/rt/nosv/CMakeLists.txt +++ b/test/rt/nosv/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2024 Barcelona Supercomputing Center (BSC) +# Copyright (c) 2021-2025 Barcelona Supercomputing Center (BSC) # SPDX-License-Identifier: GPL-3.0-or-later find_package(Nosv) @@ -45,6 +45,8 @@ nosv_test(inline.c SORT) nosv_test(mutex.c SORT LEVEL 3) nosv_test(barrier.c SORT LEVEL 3) nosv_test(cond.c SORT LEVEL 3) +nosv_test(yield-noisy.c NAME "yield-noisy-l3" DRIVER "yield-noisy-l3.driver.sh") +nosv_test(yield-noisy.c NAME "yield-noisy-l4" DRIVER "yield-noisy-l4.driver.sh") # Test multiple instrumentation levels nosv_test(several-tasks.c SORT NAME several-tasks-level-0 LEVEL 0) diff --git a/test/rt/nosv/yield-noisy-l3.driver.sh b/test/rt/nosv/yield-noisy-l3.driver.sh new file mode 100644 index 0000000..e145900 --- /dev/null +++ b/test/rt/nosv/yield-noisy-l3.driver.sh @@ -0,0 +1,30 @@ +target=$OVNI_TEST_BIN + +# We will set our own +unset NOSV_CONFIG +unset NOSV_CONFIG_OVERRIDE + +export NOSV_APPID=1 + +cat > nosv.toml << EOF +instrumentation.version = "ovni" +ovni.level = 3 +EOF + +$target + +. ./vars.sh + +# We need to sort the trace as it has unsorted regions +ovnisort ovni + +# Ensure that we don't find any noisy events by using the limit of 5% of +# nosv_yield calls. It is fine if some events don't appear. +ovnitop ovni | awk -v n=$nyields \ + '/^V(AY|Ay|Sh|Sf|S\[|S\]|SN|Sn|Pr|Pp)/ { \ + if ($2 < 0.05 * n) { print $0, "OK" } + else { print $0, "BAD"; bad++ } + } END { if (bad != 0) { exit 1 } }' + +# Perform the emulation with breakdown enabled +ovniemu -b ovni diff --git a/test/rt/nosv/yield-noisy-l4.driver.sh b/test/rt/nosv/yield-noisy-l4.driver.sh new file mode 100644 index 0000000..b481b8a --- /dev/null +++ b/test/rt/nosv/yield-noisy-l4.driver.sh @@ -0,0 +1,38 @@ +target=$OVNI_TEST_BIN + +# We will set our own +unset NOSV_CONFIG +unset NOSV_CONFIG_OVERRIDE + +export NOSV_APPID=1 + +cat > nosv.toml << EOF +instrumentation.version = "ovni" +ovni.level = 4 +EOF + +$target + +. ./vars.sh + +# We need to sort the trace as it has unsorted regions +ovnisort ovni + +# Ensure we get a lot of VA[yY] and VS[nN] events. We need to make sure that all +# events are matched. +ovnitop ovni | awk -v n=$nyields \ + '/^VA[Yy]/ { \ + /* Match the number or nosv_yield calls exactly */ + if ($2 == n) { print $0, "OK"; ok++ } + else { print $0, "BAD" } + } \ + /^VS[Nn]/ { \ + /* Use 2% for the non-blocking scheduler events */ + if ($2 > 0.02 * n) { print $0, "OK"; ok++ } + else { print $0, "BAD" } + } END { + /* Be sure we matched the 4 rules */ + if (ok != 4) { exit 1 } + }' + +# Avoid emulation as may be huge diff --git a/test/rt/nosv/yield-noisy.c b/test/rt/nosv/yield-noisy.c new file mode 100644 index 0000000..c20b0fa --- /dev/null +++ b/test/rt/nosv/yield-noisy.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2025 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "compat.h" + +#define NITERS 1000L + +atomic_int ncompleted = 0; + +static void +busywait(long iter) +{ + for (volatile long i = 0; i < iter; i++) + ; +} + +static void +task_body(nosv_task_t task) +{ + UNUSED(task); + + /* Yield a lot of times to try to generate several events */ + for (long i = 0; i < NITERS; i++) { + nosv_yield(0); + busywait(10000L); + } +} + +static void +task_done(nosv_task_t task) +{ + UNUSED(task); + atomic_fetch_add(&ncompleted, 1); +} + +int +main(void) +{ + nosv_init(); + + uint64_t ncpus; + + if (alpi_cpu_count(&ncpus)) + die("alpi_cpu_count failed"); + + nosv_task_t *tasks = calloc((size_t) ncpus, sizeof(nosv_task_t)); + if (tasks == NULL) + die("calloc failed:"); + + int ntasks = (int) ncpus; + info("ntasks = %d", ntasks); + + FILE *f = fopen("vars.sh", "w"); + if (f == NULL) + die("fopen failed:"); + + fprintf(f, "nyields=%ld\n", (long) ntasks * NITERS); + fclose(f); + + nosv_task_type_t task_type; + nosv_type_init(&task_type, task_body, NULL, task_done, "task", NULL, NULL, 0); + + for (int i = 0; i < ntasks; i++) + nosv_create(&tasks[i], task_type, 0, 0); + + for (int i = 0; i < ntasks; i++) + nosv_submit(tasks[i], 0); + + while (atomic_load(&ncompleted) != ntasks) + sleep_us(1000); + + for (int i = 0; i < ntasks; i++) + nosv_destroy(tasks[i], 0); + + nosv_type_destroy(task_type, 0); + + free(tasks); + + nosv_shutdown(); + + return 0; +}