From 547d484dfd5f530826a0eebef47cc08aff167aaa Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauldmccarthy@gmail.com>
Date: Fri, 28 Jul 2023 11:04:48 +0100
Subject: [PATCH] TEST: Test fslStartup logic

---
 unit_tests/utils/Makefile            | 14 +++++++++
 unit_tests/utils/feedsRun.fslStartup | 43 ++++++++++++++++++++++++++++
 unit_tests/utils/test_fslStartup.cc  | 41 ++++++++++++++++++++++++++
 3 files changed, 98 insertions(+)
 create mode 100644 unit_tests/utils/Makefile
 create mode 100755 unit_tests/utils/feedsRun.fslStartup
 create mode 100644 unit_tests/utils/test_fslStartup.cc

diff --git a/unit_tests/utils/Makefile b/unit_tests/utils/Makefile
new file mode 100644
index 0000000..0f170c3
--- /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 0000000..d307692
--- /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 0000000..325509d
--- /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;
+}
-- 
GitLab