Add support for runtime tests

This commit is contained in:
Rodrigo Arias 2022-08-22 16:40:08 +02:00
parent 158f2b6ea6
commit c3c7aa730e
8 changed files with 335 additions and 52 deletions

67
nix/nosv.nix Normal file
View File

@ -0,0 +1,67 @@
# Build with `nix-build nix/old-glibc.nix`
let
# Pin the nixpkgs
nixpkgsPath = builtins.fetchTarball {
# Descriptive name to make the store path easier to identify
name = "nixos-20.09";
# Commit hash for nixos-20.09 as of 2021-01-11
url = "https://github.com/nixos/nixpkgs/archive/41dddb1283733c4993cb6be9573d5cef937c1375.tar.gz";
# Hash obtained using `nix-prefetch-url --unpack <url>`
sha256 = "1blbidbmxhaxar2x76nz72bazykc5yxi0algsbrhxgrsvijs4aiw";
};
pkgs = import nixpkgsPath { };
ovni = pkgs.stdenv.mkDerivation rec {
name = "ovni";
buildInputs = with pkgs; [ cmake openmpi ];
# Prevent accidental reutilization of previous builds, as we are taking the
# current directory as-is
preConfigure = ''
rm -rf build install
# There is no /bin/bash
patchShebangs test/*.sh
'';
cmakeBuildType = "Debug";
cmakeFlags = [ "-DCMAKE_SKIP_BUILD_RPATH=OFF" ];
buildFlags = [ "VERBOSE=1" ];
preCheck = ''
export CTEST_OUTPUT_ON_FAILURE=1
'';
dontStrip = true;
doCheck = true;
checkTarget = "test";
src = ../.;
};
nosv = pkgs.stdenv.mkDerivation rec {
pname = "nosv";
version = src.shortRev;
buildInputs = with pkgs; [ autoreconfHook pkg-config numactl ovni ];
configureFlags = [ "--with-ovni=${ovni}" ];
dontStrip = true;
src = builtins.fetchGit {
url = "ssh://git@gitlab-internal.bsc.es/nos-v/nos-v.git";
ref = "master";
};
};
# Quick fix to avoid rebuilding every time the ovni source changes.
# Use this nosv' version below as dependency of ovni-rt
nosv' = /nix/store/rvnrbc7ibpw06jdilz6mha7szzxcr2mi-nosv-8936f3e;
ovni-rt = ovni.overrideAttrs (old: {
__impure = true;
__noChroot = true;
buildInputs = old.buildInputs ++ [ nosv pkgs.strace ];
cmakeFlags = old.cmakeFlags ++ [ "-DBUILD_RT_TESTING=ON" ];
});
in
ovni-rt

View File

@ -17,31 +17,22 @@
set(OVNI_TEST_SOURCE_DIR "${CMAKE_SOURCE_DIR}/test") set(OVNI_TEST_SOURCE_DIR "${CMAKE_SOURCE_DIR}/test")
set(OVNI_TEST_BUILD_DIR "${CMAKE_BINARY_DIR}/test") set(OVNI_TEST_BUILD_DIR "${CMAKE_BINARY_DIR}/test")
macro(ovni_test name driver) include(macros.cmake)
add_executable("${name}" "${name}.c")
target_link_libraries("${name}" ovni)
add_test(NAME "${name}"
COMMAND "${OVNI_TEST_SOURCE_DIR}/${driver}" "${name}"
WORKING_DIRECTORY "${OVNI_TEST_BUILD_DIR}")
set_property(TEST "${name}" PROPERTY RUN_SERIAL TRUE)
if("${name}" MATCHES ".*-bad")
set_property(TEST "${name}" PROPERTY WILL_FAIL TRUE)
endif()
endmacro()
# Only run performance sensitive tests on Release builds # Only run performance sensitive tests on Release builds
if(CMAKE_BUILD_TYPE STREQUAL "Release") if(CMAKE_BUILD_TYPE STREQUAL "Release")
ovni_test("flush-overhead" "driver.sh") ovni_test(NAME flush-overhead)
endif() endif()
ovni_test("flush" "driver.sh") ovni_test(NAME flush)
ovni_test("mp-simple" "mp-driver.sh") ovni_test(NAME mp-simple MP)
ovni_test("mp-rank" "mp-driver.sh") ovni_test(NAME mp-rank MP)
ovni_test("nosv-nested-tasks" "driver.sh") ovni_test(NAME nosv-nested-tasks)
ovni_test("nosv-nested-tasks-bad" "driver.sh") ovni_test(NAME nosv-nested-tasks-bad
ovni_test("nosv-task-types" "mp-driver.sh") SHOULD_FAIL REGEX "fatal: unknown task type id 1")
ovni_test("nosv-pause" "mp-driver.sh") ovni_test(NAME nosv-task-types MP)
ovni_test(NAME nosv-pause MP)
if(BUILD_RT_TESTING)
add_subdirectory(rt)
endif()

70
test/macros.cmake Normal file
View File

@ -0,0 +1,70 @@
include(CMakeParseArguments)
function(ovni_test)
set(switches MP SHOULD_FAIL)
set(single NPROC NAME REGEX)
set(multi SOURCE ENV)
cmake_parse_arguments(
OVNI_TEST "${switches}" "${single}" "${multi}" ${ARGN})
if(NOT OVNI_TEST_NAME)
message(FATAL_ERROR "You must provide a test NAME")
endif(NOT OVNI_TEST_NAME)
set(OVNI_TEST_NAME ${OVNI_TEST_NAME} PARENT_SCOPE)
# Set default source if not given
if(NOT OVNI_TEST_SOURCE)
set(OVNI_TEST_SOURCE "${OVNI_TEST_NAME}.c")
#message("Setting default source to ${OVNI_TEST_SOURCE}")
endif()
if(NOT OVNI_TEST_NPROC)
if(NOT OVNI_TEST_MP)
set(OVNI_TEST_NPROC 1)
else()
set(OVNI_TEST_NPROC 4)
endif()
endif()
list(APPEND OVNI_TEST_ENV
"OVNI_NPROCS=${OVNI_TEST_NPROC}")
list(APPEND OVNI_TEST_ENV
"OVNI_BUILD_DIR=${CMAKE_BINARY_DIR}")
list(APPEND OVNI_TEST_ENV
"OVNI_CURRENT_DIR=${CMAKE_CURRENT_BINARY_DIR}")
add_executable("${OVNI_TEST_NAME}" "${OVNI_TEST_SOURCE}")
target_link_libraries("${OVNI_TEST_NAME}" ovni)
set(driver "${OVNI_TEST_SOURCE_DIR}/ovni-driver.sh")
if(OVNI_TEST_SHOULD_FAIL)
if(NOT OVNI_TEST_REGEX)
message(FATAL_ERROR "You must provide a REGEX for a failing test")
endif()
# Custom error handler, as ctest doesn't behave as one would expect.
add_test(NAME "${OVNI_TEST_NAME}"
COMMAND
"${OVNI_TEST_SOURCE_DIR}/match-error.sh"
"${OVNI_TEST_REGEX}"
"${driver}"
"${OVNI_TEST_NAME}"
WORKING_DIRECTORY "${OVNI_TEST_BUILD_DIR}")
else()
add_test(NAME "${OVNI_TEST_NAME}"
COMMAND
"${driver}"
"${OVNI_TEST_NAME}"
WORKING_DIRECTORY "${OVNI_TEST_BUILD_DIR}")
endif()
set_tests_properties("${OVNI_TEST_NAME}"
PROPERTIES
RUN_SERIAL TRUE
ENVIRONMENT "${OVNI_TEST_ENV}"
WORKING_DIRECTORY "${OVNI_TEST_BUILD_DIR}")
endfunction(ovni_test)

29
test/match-error.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
# This script return 0 if and only if the given program returns non-zero
# AND the regex matches the output
# $1 = the regex as grep
# $2... The program
regex="$1"
shift
"${@}" 2>&1 | stdbuf -i0 -o0 tee /dev/stderr | grep -q "${regex}"
rcprog=${PIPESTATUS[0]} rcgrep=${PIPESTATUS[2]}
echo "rcprog='$rcprog' rcgrep='$rcgrep'"
if [ "$rcprog" != 0 ] && [ "$rcgrep" = 0 ]; then
echo "ok: program failed and grep matched the error line"
exit 0
else
if [ "$rcprog" = 0 ]; then
echo "error: program exited with 0 rather than failure"
fi
if [ "$rcgrep" != 0 ]; then
echo "error: regex \"${regex}\" not matched"
fi
exit 1
fi

View File

@ -17,25 +17,30 @@
set -e set -e
testname="$1" dir=$(readlink -f "${OVNI_CURRENT_DIR}")
testname="$dir/$1"
workdir="${testname}.trace"
tracedir="${workdir}/ovni"
emubin="${OVNI_BUILD_DIR}/ovniemu"
if [ -z "$2" ]; then mkdir -p "${workdir}"
NPROCS=4 cd "${workdir}"
else
NPROCS="$2"
fi
tracedir="ovni"
emubin=../ovniemu
rm -rf "$tracedir" rm -rf "$tracedir"
for i in $(seq 1 $NPROCS); do if [ -z "$OVNI_NPROCS" ]; then
# Run the test in the background OVNI_NPROCS=1
OVNI_RANK=$(($i-1)) OVNI_NRANKS=$NPROCS "./$testname" & fi
done
wait if [ "$OVNI_NPROCS" -gt 1 ]; then
for i in $(seq 1 "$OVNI_NPROCS"); do
# Run the test in the background
OVNI_RANK=$(($i-1)) OVNI_NRANKS=$OVNI_NPROCS "$testname" &
done
wait
else
"$testname"
fi
# Then launch the emulator in lint mode # Then launch the emulator in lint mode
"$emubin" -l "$tracedir" "$emubin" -l "$tracedir"

28
test/driver.sh → test/rt/CMakeLists.txt Executable file → Normal file
View File

@ -1,6 +1,5 @@
#!/bin/sh
# #
# Copyright (c) 2021 Barcelona Supercomputing Center (BSC) # Copyright (c) 2022 Barcelona Supercomputing Center (BSC)
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -15,18 +14,17 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
set -e find_library(nosv libnosv)
find_path(NOSV_INCLUDE_DIR nosv.h)
testname="$1" function(nosv_test)
tracedir="ovni" ovni_test(${ARGN})
emubin=../ovniemu target_link_libraries("${OVNI_TEST_NAME}" nosv)
target_include_directories("${OVNI_TEST_NAME}"
PUBLIC ${NOSV_INCLUDE_DIR})
set_property(TEST "${OVNI_TEST_NAME}" APPEND
PROPERTY
ENVIRONMENT "NOSV_CONFIG=${OVNI_TEST_SOURCE_DIR}/rt/nosv.toml")
endfunction()
rm -rf "$tracedir" nosv_test(NAME nosv-attach SOURCE nosv/attach.c)
# Run the test
"./$testname"
# Then launch the emulator in lint mode
"$emubin" -l "$tracedir"
#rm -rf $tracedir

90
test/rt/nosv.toml Normal file
View File

@ -0,0 +1,90 @@
# This file is part of nOS-V and is licensed under the terms contained in the COPYING file
#
# Copyright (C) 2021-2022 Barcelona Supercomputing Center (BSC)
# Default nOS-V configuration file.
# Note that every process in the same nOS-V instance should load an identical configuration file,
# otherwise, the behaviour is unspecified
# Shared memory configuration
[shared_memory]
# Name of the shared memory section. This can be leveraged to create two separate nOS-V instances
# in the same system. Generally this has to remain unchanged
name = "nosv"
# Size of the shared memory section. Choose powers of two
size = "2G"
# Start of the shared memory mapping
# This option should be memory address codified in hexadecimal (start with 0x)
start = 0x0000200000000000
# Scheduler configuration
# These parameters allow to fine tune the scheduler's behaviour
[scheduler]
# Number of logical CPUs mapped to a single scheduler SPSC for ready tasks
# Minimum is 1, there is no maximum. Try to choose numbers that divide evenly the number
# of CPUs in the system.
# A lower number will yield more scheduling throughput and is adequate when using
# multiple task creator processes.
# A higher number will yield lower scheduling latency and is adequate when using one or few
# task creator processes
cpus_per_queue = 1
# Number of tasks that are grabbed off of a queue when processing ready tasks.
# Lowering the number may be better if there are very few ready tasks during execution.
# Increasing the batch may help if your CPU has bad single-thread performance.
# In general, the default value of 64 should result in a good trade-off
queue_batch = 64
# Scheduler quantum in ns. This is a guideline for how long should we execute one process' tasks
# until we have to switch to the next one. However, as nOS-V tasks are not preemptable, it isn't enforced.
# This parameter is specially relevant for the nosv_schedpoint function, which will try to schedule
# each quantum ns.
# A lower value will cause more inter-process context switches but may provide more uniform progress,
# while a higher value will minimize context switches but may stall applications for longer
quantum_ns = 20000000 # nanoseconds
# Size of the queues that are used to place tasks into the scheduler
# A good value should be a multiple of queue_batch
in_queue_size = 256
# CPU Governor configuration
# Controls the policy that nOS-V follows to block idle CPUs to save energy and resources
[governor]
# There is a choice between three different governor policies:
# - hybrid: CPUs will spin for governor.spins before going to sleep when no work is available
# - idle: CPUs will sleep immediately when no work is available
# - busy: CPUs will never sleep
# In general, use idle when targeting minimum power usage, and busy when targeting maximum performance
# The default is hybrid as it provides a good balance between power and performance.
policy = "hybrid"
# Number of times a CPU will spin without sleeping in the "hybrid" policy.
# When "idle" or "busy" are selected, this setting is ignored
spins = 10000
# Debug options
[debug]
# Dump all the configuration options nOS-V is running with, its final parsed values and the
# path of the config file being used
dump_config = false
# Hardware Counters configuration
[hwcounters]
# Whether to print verbose information if a backend is enabled
verbose = false
# The enabled HWCounter backends. Possible options: "papi", "none"
backend = "none"
# The list of PAPI counters to read. By default only "PAPI_TOT_INS" and "PAPI_TOT_CYC"
papi_events = [
"PAPI_TOT_INS",
"PAPI_TOT_CYC"
]
# Enabling turbo will cause nOS-V to set architecture-specific optimization flags on every created
# or attached threads. In x86, this will cause the FTZ and DAZ flags of the SSE FPU to be enabled,
# causing a significant performance increase in floating-point applications, but disabling IEEE-754
# compatibility.
[turbo]
enabled = false
# Monitoring cappabilities and configuration.
[monitoring]
enabled = false
# Whether to print verbose information if monitoring is enabled
verbose = false

33
test/rt/nosv/attach.c Normal file
View File

@ -0,0 +1,33 @@
#define _DEFAULT_SOURCE
#include <unistd.h>
#include <nosv.h>
#include "common.h"
int main(void)
{
nosv_init();
nosv_task_type_t type;
if(nosv_type_init(&type, NULL, NULL, NULL, "adopted", NULL,
NULL, NOSV_TYPE_INIT_EXTERNAL) != 0)
die("nosv_type_init failed\n");
nosv_task_t task;
if(nosv_attach(&task, type, 0, NULL, 0) != 0)
die("nosv_attach failed\n");
usleep(100);
if(nosv_detach(0) != 0)
die("nosv_detach failed\n");
if(nosv_type_destroy(type, 0) != 0)
die("nosv_type_destroy failed\n");
if(nosv_shutdown() != 0)
die("nosv_shutdown failed\n");
return 0;
}