diff --git a/unit_tests/utils/Makefile b/unit_tests/utils/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0f170c3318e64eb7884f453ce26889da3765d2a1 --- /dev/null +++ b/unit_tests/utils/Makefile @@ -0,0 +1,14 @@ +include ${FSLCONFDIR}/default.mk + +PROJNAME = utils_tests +XFILES = test_fslStartup +USRCXXFLAGS = -fopenmp +LIBS = -lfsl-utils + +all: ${XFILES} + +%: %.cc + ${CXX} ${CXXFLAGS} -o $@ $< + +test_fslStartup: test_fslStartup.cc + ${CXX} ${CXXFLAGS} -o $@ $< ${LDFLAGS} diff --git a/unit_tests/utils/feedsRun.fslStartup b/unit_tests/utils/feedsRun.fslStartup new file mode 100755 index 0000000000000000000000000000000000000000..d3076929e83184ee95018337aacf088debbb9c9c --- /dev/null +++ b/unit_tests/utils/feedsRun.fslStartup @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +import os +import shlex +import tempfile + +import subprocess as sp + +def run(cmd, **kwargs): + + result = sp.run(shlex.split(cmd), check=True, text=True, + stdout=sp.PIPE, stderr=sp.STDOUT, **kwargs) + + print(f'Called {cmd}') + print(f' exit code: {result.returncode}') + print(f' stdout: {result.stdout.strip()}') + + return result.stdout.strip() + + +def main(): + + blacklist = ['OMP', 'GOTO', 'BLAS', 'FSL'] + env = os.environ.copy() + for varname in list(env.keys()): + if any(b in varname for b in blacklist): + env.pop(varname) + + env['OMP_NUM_THREADS'] = '8' + env['BLAS_NUM_THREADS'] = '8' + + run('make') + + # Default behaviour should be: OMP multi-threaded, BLAS single threaded. + assert run('./test_fslStartup', env=env) == '8 1 8' + + # With FSL_SKIP_GLOBAL, BLAS should be multi-threaded + env['FSL_SKIP_GLOBAL'] = '1' + assert run('./test_fslStartup', env=env) == '8 8 8' + + +if __name__ == '__main__': + main() diff --git a/unit_tests/utils/test_fslStartup.cc b/unit_tests/utils/test_fslStartup.cc new file mode 100644 index 0000000000000000000000000000000000000000..325509d448930392b352e97c7f96d8833472bbd6 --- /dev/null +++ b/unit_tests/utils/test_fslStartup.cc @@ -0,0 +1,41 @@ +#include <iostream> +#include "omp.h" +#include "cblas.h" + +#include "utils/options.h" + +using namespace std; + +/* + * Interrogate and print out the number of threads used by OpenMP, and the + * number of threads used by OpenBLAS. + * + * The utils/fslStartup.cc file contains some global initialisation logic + * which controls the number of threads used by OpenBLAS. All we need to do + * to induce the fslStartup.cc code is link against libfsl-utils.so. + */ +int main(int argc, char *argv[]) { + + // Use something from libfsl-utils.so + // to ensure that it gets linked. + Utilities::OptionParser opts("test", "test"); + + int omp_threads; + int blas_threads; + int sum = 0; + + // omp num threads should not be + // affected by the FSL startup logic. + // Sum should be equal to omp num threads. + #pragma omp parallel + { + sum += 1; + omp_threads = omp_get_num_threads(); + } + + // blas num threads should be controlled + // by FSL startup logic. + blas_threads = openblas_get_num_threads(); + + cout << omp_threads << " " << blas_threads << " " << sum << endl; +}