diff --git a/test/rt/nosv/CMakeLists.txt b/test/rt/nosv/CMakeLists.txt index a4dcc9e..4af2d9d 100644 --- a/test/rt/nosv/CMakeLists.txt +++ b/test/rt/nosv/CMakeLists.txt @@ -24,7 +24,7 @@ function(nosv_test) cmake_parse_arguments( NOSV_TEST "${switches}" "${single}" "${multi}" ${ARGN}) ovni_test(${ARGN}) - target_link_libraries("${OVNI_TEST_NAME}" PRIVATE PkgConfig::NOSV) + target_link_libraries("${OVNI_TEST_NAME}" PRIVATE PkgConfig::NOSV m) set_property(TEST "${OVNI_TEST_NAME}" APPEND PROPERTY ENVIRONMENT "NOSV_CONFIG=${OVNI_TEST_SOURCE_DIR}/rt/nosv/nosv.toml") @@ -65,6 +65,9 @@ nosv_test(several-tasks.c SORT NAME several-tasks-breakdown-level-2 LEVEL 2 BREA nosv_test(several-tasks.c SORT NAME several-tasks-breakdown-level-3 LEVEL 3 BREAKDOWN) nosv_test(several-tasks.c SORT NAME several-tasks-breakdown-level-4 LEVEL 4 BREAKDOWN) +nosv_test(several-tasks.c NAME hwc-tasks DRIVER "hwc.driver.sh") +nosv_test(hwc-stride.c DRIVER "hwc-stride.driver.sh") + if (PERF_PARANOID_KERNEL) message(STATUS "Enabling perf paranoid tests for nOS-V") nosv_test(kernel.c NAME kernel-overflow DRIVER "kernel-overflow.driver.sh") diff --git a/test/rt/nosv/hwc-stride.c b/test/rt/nosv/hwc-stride.c new file mode 100644 index 0000000..b2c4fa6 --- /dev/null +++ b/test/rt/nosv/hwc-stride.c @@ -0,0 +1,117 @@ +/* Copyright (c) 2025 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +/* + * This test creates several tasks that all perform the computation with the + * same instructions. However, the access to the memory is done differently. The + * first set of tasks use a stride 1, the next 2, the next 4 and so on until + * 2^(NSTRIDE-1). This access causes more L3 cache misses, which increases the + * execution time, typically directly proportional to the stride number. + * + * The number of instructions given by PAPI_TOT_INS should remain constant + * across tasks, but it is expected that PAPI_L3_TCM increases with the + * stride. + */ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "compat.h" + +#define NTASKS 200 +atomic_int ncompleted = 0; + +nosv_task_t tasks[NTASKS]; + +#define NRUNS 2 +#define NSTRIDE 4 +#define MAXN (256L * 1024L) /* Adjust this for larger L3 */ + +struct meta { + long n; + long stride; + double *vec; +}; + +static double +get_time(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double) ts.tv_sec + (double) ts.tv_nsec * 1.0e-9; +} + +static void +task_body(nosv_task_t task) +{ + struct meta *meta = nosv_get_task_metadata(task); + + long stride = meta->stride; + + /* Stride access, some computation */ + for (long i = 0; i < stride; i++) + for (long j = i; j < meta->n; j += stride) + meta->vec[j] = sqrt(meta->vec[j]); + + atomic_fetch_add(&ncompleted, 1); +} + +int +main(void) +{ + nosv_init(); + + nosv_task_type_t task_type; + nosv_type_init(&task_type, task_body, NULL, NULL, "task", NULL, NULL, 0); + + for (int i = 0; i < NTASKS; i++) { + nosv_create(&tasks[i], task_type, sizeof(struct meta), 0); + struct meta *meta = nosv_get_task_metadata(tasks[i]); + meta->n = MAXN; + meta->vec = calloc(MAXN, sizeof(double)); + for (long i = 0; i < MAXN; i++) + meta->vec[i] = (double) i; + } + + fprintf(stderr, "%8s %8s %8s\n", "run", "stride", "time"); + + /* Repeat for warmup */ + for (int run = 0; run < NRUNS; run++) { + for (int s = 0; s < NSTRIDE; s++) { + long stride = 1L << s; + + atomic_store(&ncompleted, 0); /* reset */ + + double t0 = get_time(); + + for (int i = 0; i < NTASKS; i++) { + struct meta *meta = nosv_get_task_metadata(tasks[i]); + meta->stride = stride; + nosv_submit(tasks[i], 0); + } + + while (atomic_load(&ncompleted) != NTASKS) + sleep_us(1000); + + double t1 = get_time(); + + printf("%8d %8ld %8.3f\n", run, stride, t1 - t0); + } + } + + for (int i = 0; i < NTASKS; i++) { + struct meta *meta = nosv_get_task_metadata(tasks[i]); + free(meta->vec); + nosv_destroy(tasks[i], 0); + } + + nosv_type_destroy(task_type, 0); + + nosv_shutdown(); + + return 0; +} diff --git a/test/rt/nosv/hwc-stride.driver.sh b/test/rt/nosv/hwc-stride.driver.sh new file mode 100644 index 0000000..8ca1a99 --- /dev/null +++ b/test/rt/nosv/hwc-stride.driver.sh @@ -0,0 +1,18 @@ +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 = 2 +hwcounters.backend = "papi" +hwcounters.papi_events = [ "PAPI_TOT_INS", "PAPI_TOT_CYC", "PAPI_L3_TCM" ] +EOF + +$target + +ovniemu -l ovni diff --git a/test/rt/nosv/hwc.driver.sh b/test/rt/nosv/hwc.driver.sh new file mode 100644 index 0000000..cd76157 --- /dev/null +++ b/test/rt/nosv/hwc.driver.sh @@ -0,0 +1,18 @@ +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 = 2 +hwcounters.backend = "papi" +hwcounters.papi_events = [ "PAPI_TOT_INS", "PAPI_TOT_CYC" ] +EOF + +$target + +ovniemu -l ovni