From e9788e22adc7f8f621f4c6dcff2881c63ed3201f Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Tue, 30 Jul 2024 17:15:40 +0200 Subject: [PATCH] Add test kernel ring overflow test for nOS-V MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a problem in the way we are reading the buffer in nOS-V, which fails when the ring buffer gets full. This regression test ensures it is fixed. Reported-by: David Álvarez --- test/rt/nosv/CMakeLists.txt | 1 + test/rt/nosv/overflow-kernel-ring.c | 77 +++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 test/rt/nosv/overflow-kernel-ring.c diff --git a/test/rt/nosv/CMakeLists.txt b/test/rt/nosv/CMakeLists.txt index 5e785be..00d3b80 100644 --- a/test/rt/nosv/CMakeLists.txt +++ b/test/rt/nosv/CMakeLists.txt @@ -44,6 +44,7 @@ nosv_test(parallel-tasks.c SORT) nosv_test(inline.c SORT) nosv_test(mutex.c SORT LEVEL 3) nosv_test(barrier.c SORT LEVEL 3) +nosv_test(overflow-kernel-ring.c SORT LEVEL 3) # Test multiple instrumentation levels nosv_test(several-tasks.c SORT NAME several-tasks-level-0 LEVEL 0) diff --git a/test/rt/nosv/overflow-kernel-ring.c b/test/rt/nosv/overflow-kernel-ring.c new file mode 100644 index 0000000..03a070f --- /dev/null +++ b/test/rt/nosv/overflow-kernel-ring.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include +#include +#include + +#include "common.h" +#include "compat.h" + +int done = 0; + +/* https://gitlab.bsc.es/nos-v/nos-v/-/blob/master/src/include/instr.h?ref_type=heads#L542 */ +#define NOSV_INSTR_KBUFLEN (4UL * 1024UL * 1024UL) // 4 MB + +static void +task_run(nosv_task_t task) +{ + UNUSED(task); + + /* Cause enough context switches for the kernel ring to be full, + * which wouldn't fail if nosv_waitfor() flushes the kernel + * events. */ + + unsigned long fill = 3 * NOSV_INSTR_KBUFLEN / 4; + unsigned long n = fill / 16; + + struct timespec one_ns = { .tv_sec = 0, .tv_nsec = 1 }; + + for (unsigned long run = 0; run < 3; run++) { + info("starting run %lu", run); + for (unsigned long i = 0; i < n; i++) + nanosleep(&one_ns, NULL); + + info("starting waitfor"); + + if (nosv_waitfor(1, NULL) != 0) + die("nosv_waitfor failed"); + + info("end run %lu", run); + } + + done = 1; +} + +int main(void) +{ + if (nosv_init()) + die("nosv_init failed"); + + nosv_task_type_t task_type; + if (nosv_type_init(&task_type, task_run, NULL, NULL, "task", NULL, NULL, NOSV_TYPE_INIT_NONE)) + die("nosv_type_init failed"); + + nosv_task_t task; + if (nosv_create(&task, task_type, 0, NOSV_CREATE_NONE)) + die("nosv_create failed"); + + if (nosv_submit(task, NOSV_SUBMIT_IMMEDIATE)) + die("nosv_submit failed"); + + /* Wait for the task to finish */ + while (!done) + sleep_us(10000); + + if (nosv_destroy(task, NOSV_DESTROY_NONE)) + die("nosv_destroy failed"); + + if (nosv_type_destroy(task_type, NOSV_TYPE_DESTROY_NONE)) + die("nosv_type_destroy failed"); + + if (nosv_shutdown()) + die("nosv_shutdown failed"); + + return 0; +}