Repository: oneapi-src/unified-memory-framework (language: python)

Issue:
Cannot run ctest on WSL2 due to the lack of NUMA
<!--
Before creating new issue, ensure that similar issue wasn't already created
  * Search: https://github.com/oneapi-src/unified-memory-framework/issues

Note that if you do not provide enough information to reproduce the issue, we may not be able to take action on your report.
Remember this is just a minimal template. You can extend it with data you think may be useful.
-->

<!-- fill the title of issue with short description -->

## Environment Information

- UMF version (hash commit or a tag):                         2c608df489bc818dacd35b8ed9951b8f8ea615ae
- OS(es) version(s):                                          (WSL2) Ubuntu 22.04.4
- kernel version(s):                                          (WSL2, Linux kernel) 5.15.153.1-microsoft-standard-WSL2
- compiler, libraries, and other related tools version(s):    libnuma-dev (2.0.14-3ubuntu2)

### Additional environment information
- WSL2
- no NUMA support

## Reproduction of the bug:

When the unmodified project is built, enter the build directory and execute:

```bash
$ ctest --output-on-failure
```

## How often bug is revealed:

Always

## Actual behavior:

Failing tests:
```
8 - umf-provider_os_memory_multiple_numa_nodes (Subprocess aborted)
9 - umf-memspace_numa (Failed)
11 - umf-memspace_host_all (Failed)
12 - umf-memspace_highest_capacity (Failed)
13 - umf-memspace_highest_bandwidth (SEGFAULT)
14 - umf-memspace_lowest_latency (SEGFAULT)
```

Tests output log include information:
```Failed to initialize libnuma```

```numa_available()``` in ```provider_os_memory_multiple_numa_nodes.cpp``` returns -1

## Expected behavior:

All tests pass

## Details

Additionally, with ```numactl``` installed on the system, running ```numactl --show``` in the terminal shows:
```No NUMA support available on this system.```

## Additional information about Priority and Help Requested:

Are you willing to submit a pull request with a proposed change? Yes

Requested priority:                         Low



Discussion / hints:

Fix patch:
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index d06e51755..8b61c82a5 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -167,6 +167,8 @@ else()
 endif()
 
 if(LINUX)
+    set(UMF_TEST_SKIP_RETURN_CODE 125)
+
     set(EXAMPLE_NAME umf_example_memspace_numa)
 
     add_umf_executable(
@@ -175,8 +177,10 @@ if(LINUX)
         LIBS umf ${LIBHWLOC_LIBRARIES} numa)
 
     target_include_directories(
-        ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils
-                                ${UMF_CMAKE_SOURCE_DIR}/include)
+        ${EXAMPLE_NAME}
+        PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils
+                ${UMF_CMAKE_SOURCE_DIR}/include
+                ${UMF_CMAKE_SOURCE_DIR}/examples/common)
 
     target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS})
 
@@ -185,6 +189,9 @@ if(LINUX)
         COMMAND ${EXAMPLE_NAME}
         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
 
+    set_tests_properties(${EXAMPLE_NAME} PROPERTIES
+                         SKIP_RETURN_CODE ${UMF_TEST_SKIP_RETURN_CODE})
+
     set(EXAMPLE_NAME umf_example_memspace_hmat)
 
     add_umf_executable(
@@ -193,8 +200,10 @@ if(LINUX)
         LIBS umf ${LIBHWLOC_LIBRARIES} numa)
 
     target_include_directories(
-        ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils
-                                ${UMF_CMAKE_SOURCE_DIR}/include)
+        ${EXAMPLE_NAME}
+        PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils
+                ${UMF_CMAKE_SOURCE_DIR}/include
+                ${UMF_CMAKE_SOURCE_DIR}/examples/common)
 
     target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS})
 
@@ -203,7 +212,8 @@ if(LINUX)
         COMMAND ${EXAMPLE_NAME}
         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
 
-    set_tests_properties(${EXAMPLE_NAME} PROPERTIES SKIP_RETURN_CODE 125)
+    set_tests_properties(${EXAMPLE_NAME} PROPERTIES
+                         SKIP_RETURN_CODE ${UMF_TEST_SKIP_RETURN_CODE})
     set(EXAMPLE_NAME umf_example_file_provider)
 
     add_umf_executable(
diff --git a/examples/common/utils_examples.h b/examples/common/utils_examples.h
new file mode 100644
index 000000000..9e4a93bcf
--- /dev/null
+++ b/examples/common/utils_examples.h
@@ -0,0 +1,16 @@
+/*
+ *
+ * Copyright (C) 2024 Intel Corporation
+ *
+ * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ */
+
+#ifndef UMF_EXAMPLE_UTILS_H
+#define UMF_EXAMPLE_UTILS_H
+
+// Needed for CI
+#define TEST_SKIP_ERROR_CODE 125
+
+#endif /* UMF_EXAMPLE_UTILS_H */
diff --git a/examples/memspace/memspace_hmat.c b/examples/memspace/memspace_hmat.c
index 64d869e73..1a4cf154e 100644
--- a/examples/memspace/memspace_hmat.c
+++ b/examples/memspace/memspace_hmat.c
@@ -15,8 +15,7 @@
 #include <stdio.h>
 #include <string.h>
 
-// Needed for CI
-#define test_skip_error_code 125
+#include "utils_examples.h"
 
 // Function to create a memory provider which allocates memory from the specified NUMA node
 int createMemoryProvider(umf_memory_provider_handle_t *hProvider,
@@ -63,13 +62,13 @@ int main(void) {
     // Check if NUMA is available
     if (numa_available() < 0) {
         fprintf(stderr, "NUMA is not available on this system.\n");
-        return -1;
+        return TEST_SKIP_ERROR_CODE;
     }
 
     // Create the memory provider that allocates memory from the highest bandwidth numa nodes
     ret = createMemoryProvider(&hProvider, umfMemspaceHighestBandwidthGet());
     if (ret != UMF_RESULT_SUCCESS) {
-        return ret == 1 ? test_skip_error_code : -1;
+        return ret == 1 ? TEST_SKIP_ERROR_CODE : -1;
     }
 
     // Allocate memory from the memory provider
diff --git a/examples/memspace/memspace_numa.c b/examples/memspace/memspace_numa.c
index 7d328d4a0..8116825ed 100644
--- a/examples/memspace/memspace_numa.c
+++ b/examples/memspace/memspace_numa.c
@@ -15,6 +15,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "utils_examples.h"
+
 // Function to create a memory provider which allocates memory from the specified NUMA node
 int createMemoryProvider(umf_memory_provider_handle_t *hProvider,
                          unsigned numa) {
@@ -65,7 +67,7 @@ int main(void) {
     // Check if NUMA is available
     if (numa_available() < 0) {
         fprintf(stderr, "NUMA is not available on this system.\n");
-        return -1;
+        return TEST_SKIP_ERROR_CODE;
     }
 
     // Create the memory provider that allocates memory from the specified NUMA node


Test patch:
diff --git a/test/common/test_helpers.h b/test/common/test_helpers.h
index e361feba4..df4c3c235 100644
--- a/test/common/test_helpers.h
+++ b/test/common/test_helpers.h
@@ -19,6 +19,9 @@
 extern "C" {
 #endif
 
+// Needed for CI
+#define TEST_SKIP_ERROR_CODE 125
+
 static inline void UT_FATAL(const char *format, ...) {
     va_list args_list;
     va_start(args_list, format);
diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp
index fac50b031..5aaaed787 100644
--- a/test/memspaces/memspace_fixtures.hpp
+++ b/test/memspaces/memspace_fixtures.hpp
@@ -30,7 +30,7 @@ struct numaNodesTest : ::umf_test::test {
         ::umf_test::test::SetUp();
 
         if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) {
-            GTEST_FAIL() << "Failed to initialize libnuma";
+            GTEST_SKIP() << "No available NUMA support; skipped";
         }
 
         int maxNode = numa_max_node();
@@ -59,6 +59,10 @@ struct memspaceGetTest : ::numaNodesTest,
     void SetUp() override {
         ::numaNodesTest::SetUp();
 
+        if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) {
+            GTEST_SKIP() << "No available NUMA support; skipped";
+        }
+
         auto [isQuerySupported, memspaceGet] = this->GetParam();
 
         if (!isQuerySupported(nodeIds.front())) {
diff --git a/test/memspaces/memspace_numa.cpp b/test/memspaces/memspace_numa.cpp
index c8485fadc..180efd9c2 100644
--- a/test/memspaces/memspace_numa.cpp
+++ b/test/memspaces/memspace_numa.cpp
@@ -14,6 +14,10 @@ struct memspaceNumaTest : ::numaNodesTest {
     void SetUp() override {
         ::numaNodesTest::SetUp();
 
+        if (numa_available() == -1) {
+            GTEST_SKIP() << "NUMA not supported on this system; test skipped";
+        }
+
         umf_result_t ret = umfMemspaceCreateFromNumaArray(
             nodeIds.data(), nodeIds.size(), &hMemspace);
         ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
@@ -34,6 +38,10 @@ struct memspaceNumaProviderTest : ::memspaceNumaTest {
     void SetUp() override {
         ::memspaceNumaTest::SetUp();
 
+        if (numa_available() == -1) {
+            GTEST_SKIP() << "NUMA not supported on this system; test skipped";
+        }
+
         umf_result_t ret =
             umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider);
         ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp
index 0f7f0fb2e..91f269e44 100644
--- a/test/provider_os_memory_multiple_numa_nodes.cpp
+++ b/test/provider_os_memory_multiple_numa_nodes.cpp
@@ -18,8 +18,9 @@ static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS_TEST =
     umfOsMemoryProviderParamsDefault();
 
 std::vector<unsigned> get_available_numa_nodes() {
-    UT_ASSERTne(numa_available(), -1);
-    UT_ASSERTne(numa_all_nodes_ptr, nullptr);
+    if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) {
+        return std::vector<unsigned>();
+    }
 
     std::vector<unsigned> available_numa_nodes;
     // Get all available NUMA nodes numbers.
@@ -57,9 +58,6 @@ std::vector<int> get_available_cpus() {
 }
 
 void set_all_available_nodemask_bits(bitmask *nodemask) {
-    UT_ASSERTne(numa_available(), -1);
-    UT_ASSERTne(numa_all_nodes_ptr, nullptr);
-
     numa_bitmask_clearall(nodemask);
 
     // Set all available NUMA nodes numbers.
@@ -124,6 +122,24 @@ struct testNuma : testing::Test {
 struct testNumaOnEachNode : testNuma, testing::WithParamInterface<unsigned> {};
 struct testNumaOnEachCpu : testNuma, testing::WithParamInterface<int> {};
 
+/*
+ - In case of the lack of support for NUMA on the system
+ get_available_numa_nodes() returns an empty vector<unsigned>
+ - Then in INSTANTIATE_TEST_SUITE_P an empty container is passed as the 3rd arg
+ (param_generator)
+ - Therefore INSTANTIATE_TEST_SUITE_P expands to nothing, which causes the test
+ to fail in the test suite GoogleTestVerification
+- GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testNumaOnEachNode) allows the
+test suite testNumaOnEachNode to be uninstantiated, suppressing
+the test failure
+- Additionally, the fixture testNumaOnEachNode uses SetUp from testNuma before
+running every test, thus the test is eventually skipped when the lack of NUMA
+support is determined by numa_available()
+- (Therefore probably a vector with dummy values could be returned instead of
+using the macro)
+*/
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testNumaOnEachNode);
+
 INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocations, testNumaOnEachNode,
                          ::testing::ValuesIn(get_available_numa_nodes()));