]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3883: NUMA memory policy
authorRaza Shafiq (rshafiq) <rshafiq@cisco.com>
Wed, 21 Jun 2023 01:42:26 +0000 (01:42 +0000)
committerSteven Baigal (sbaigal) <sbaigal@cisco.com>
Wed, 21 Jun 2023 01:42:26 +0000 (01:42 +0000)
Merge in SNORT/snort3 from ~RSHAFIQ/snort3:numa_memory_policy to master

Squashed commit of the following:

commit 9078d21f8c3e62519dadb794bd72abcf502b033b
Author: rshafiq <rshafiq@cisco.com>
Date:   Wed Jun 7 15:18:57 2023 -0400

    thread_config: added thread level mempolicy

15 files changed:
CMakeLists.txt
cmake/FindNUMA.cmake [new file with mode: 0644]
cmake/create_pkg_config.cmake
cmake/include_libraries.cmake
cmake/sanity_checks.cmake
config.cmake.h.in
doc/user/snort_user.text
src/CMakeLists.txt
src/main/analyzer.cc
src/main/dev_notes.txt
src/main/test/distill_verdict_stubs.h
src/main/thread_config.cc
src/main/thread_config.h
src/utils/CMakeLists.txt
src/utils/util_numa.h [new file with mode: 0644]

index d3fbf66e7eeaf7e9508bb1986e3d2523af08b063..c96bdab3cd30b3ebfc7f370ee4208be36c771493 100644 (file)
@@ -196,4 +196,12 @@ else ()
     UUID:           OFF")
 endif ()
 
+if (HAVE_NUMA)
+    message("\
+    NUMA:           ON")
+else ()
+    message("\
+    NUMA:           OFF")
+endif ()
+
 message("-------------------------------------------------------\n")
diff --git a/cmake/FindNUMA.cmake b/cmake/FindNUMA.cmake
new file mode 100644 (file)
index 0000000..f518363
--- /dev/null
@@ -0,0 +1,28 @@
+find_path(NUMA_INCLUDE_DIRS numa.h)
+find_library(NUMA_LIBRARIES NAMES numa)
+
+if(NUMA_INCLUDE_DIRS AND NUMA_LIBRARIES)
+    set(NUMA_FOUND TRUE)
+    set(NUMA_LIBRARIES ${NUMA_LIBRARIES})
+    set(NUMA_INCLUDE_DIRS ${NUMA_INCLUDE_DIRS})
+endif()
+
+if (NOT NUMA_FOUND)
+    find_package(PkgConfig)
+    pkg_check_modules(PC_NUMA libnuma)
+
+    if(PC_NUMA_FOUND)
+        set(NUMA_FOUND TRUE)
+        set(NUMA_INCLUDE_DIRS ${PC_NUMA_INCLUDEDIR} ${PC_NUMA_INCLUDE_DIRS})
+        set(NUMA_LIBRARIES ${PC_NUMA_LIBDIR} ${PC_NUMA_LIBRARY_DIRS})
+    endif()
+endif()
+
+if(NUMA_FOUND)
+    set(HAVE_NUMA "1")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(NUMA DEFAULT_MSG NUMA_LIBRARIES NUMA_INCLUDE_DIRS)
+
+mark_as_advanced(NUMA_INCLUDE_DIRS NUMA_LIBRARIES)
\ No newline at end of file
index d7a5667cd533e2604633491143698a6cd42d5f6f..0d12b026f0cd3cf87631e43ef63e406b59d9e08e 100644 (file)
@@ -80,6 +80,9 @@ if(UUID_INCLUDE_DIR)
     set(UUID_CPPFLAGS "-I${UUID_INCLUDE_DIR}")
 endif()
 
+if(NUMA_INCLUDE_DIR)
+    set(NUMA_CPPFLAGS "-I${NUMA_INCLUDE_DIR}")
+endif()
 # create & install pkgconfig file
 
 configure_file(
index b3b4fd4572d4bd6917b1bd5675e659abc51f8681..1a0b197f8d2801c642e3bf3f287dd9eeb5b03dbd 100644 (file)
@@ -27,3 +27,4 @@ endif (ENABLE_SAFEC)
 find_package(ICONV QUIET)
 find_package(UUID QUIET)
 find_package(Libunwind)
+find_package(NUMA QUIET)
index 78ea3879e8b8d139d6916c97291d41d99d64e0ed..898782a5f200d3005f2d1ef546b67d874161bd23 100644 (file)
@@ -150,6 +150,10 @@ if (ICONV_FOUND)
     set (HAVE_ICONV "1")
 endif()
 
+if (NUMA_FOUND)
+    check_library_exists (${NUMA_LIBRARIES} numa_num_possible_cpus "" HAVE_NUMA)
+endif()
+
 if (LIBUNWIND_FOUND)
     # We don't actually use backtrace from libunwind, but it's basically the
     # only symbol guaranteed to be present.
index 867f9996ff5c2dcc1b8a80e91815d8f5cae9c93c..78205f5cf8a832a412d4a2e91cd8124278480aca 100644 (file)
 /* tirpc should be used for RPC database lookups */
 #cmakedefine USE_TIRPC 1
 
+/* numa available */
+#cmakedefine HAVE_NUMA 1
 
 /*  Availability of specific library functions */
 
index badd0446006877f135e28151d4224646396d538b..d57724dd81ada22a1fd2353d4870d3f79f429d8a 100644 (file)
@@ -1063,13 +1063,14 @@ Optional:
     received
   * lzma >= 5.1.2 from http://tukaani.org/xz/ for decompression of
     SWF and PDF files
+  * numa from https://github.com/numactl/numactl for NUMA memory management
   * safec >= 3.5 from https://github.com/rurban/safeclib/ for runtime
     bounds checks on certain legacy C-library calls
   * source-highlight from http://www.gnu.org/software/src-highlite/
     to generate the dev guide
   * w3m from http://sourceforge.net/projects/w3m/ to build the plain
     text manual
-  * uuid from uuid-dev package for unique identifiers
+  * uuid from uuid-dev package for unique identifiers 
 
 
 3.2. Building
index 71ad64cae6edec95cc237cb7fee944a91748c37a..4cf2456cc251d01156a40f46da3cab9dcacd6cf5 100644 (file)
@@ -52,6 +52,11 @@ if ( HAVE_LZMA )
     LIST(APPEND EXTERNAL_LIBRARIES ${LIBLZMA_LIBRARIES})
 endif()
 
+if ( HAVE_NUMA )
+    LIST(APPEND EXTERNAL_INCLUDES ${NUMA_INCLUDE_DIRS})
+    LIST(APPEND EXTERNAL_LIBRARIES ${NUMA_LIBRARIES})
+endif()
+
 if ( HAVE_SAFEC )
     LIST(APPEND EXTERNAL_LIBRARIES ${SAFEC_LIBRARIES})
     LIST(APPEND EXTERNAL_INCLUDES ${SAFEC_INCLUDE_DIR})
index 634d71b642be98a6161b61f42cd5d4f52fcb15f7..68496cb15fa158ef43064736ff273067087412ef 100644 (file)
@@ -746,7 +746,7 @@ void Analyzer::operator()(Swapper* ps, uint16_t run_num)
     SnortConfig::get_conf()->thread_config->set_instance_tid(id);
     // Perform all packet thread initialization actions that need to be taken with escalated
     // privileges prior to starting the DAQ module.
-    SnortConfig::get_conf()->thread_config->implement_thread_affinity(
+    SnortConfig::get_conf()->thread_config->apply_thread_policy(
         STHREAD_TYPE_PACKET, get_instance_id());
 
     SFDAQ::set_local_instance(daq_instance);
index c4a535fd2fa2607d5eda609da08f8655b2c842a5..f4dd2df01190142b5f85c0e72a2ec4fb99c45beb 100644 (file)
@@ -63,3 +63,16 @@ information and management.  Currently it is being used as a cross-platform
 mechanism for managing CPU affinity of threads, but it will be used in the
 future for NUMA (non-uniform memory access) awareness among other things.
 
+Use of libnuma in thread_config.cc:
+
+The libnuma library offers a straightforward programming interface to 
+the NUMA (Non Uniform Memory Access) policy that is supported by 
+the Linux kernel. Preferred memory mode support for NUMA systems 
+has been added. set_mempolicy() is used to establish the memory policy 
+for packet threads operating on different nodes within a NUMA system. 
+The libnuma-dev library must be installed to enable this support. 
+In systems without NUMA architecture, this feature will not affect system 
+performance or behavior. This, alongside with libhwloc, presents an efficient 
+cross-platform mechanism for thread configuration and managing CPU affinity 
+of threads, not only considering CPU architecture but also memory access policies, 
+providing a more balanced and optimized execution environment.
\ No newline at end of file
index 73931fb4cbf45b826cd246e1520a7ba8ec4ed133..649af12bc442ff054e8fcacdb9b96f005221c83b 100644 (file)
@@ -225,6 +225,7 @@ NetworkPolicy* get_network_policy() { return nullptr; }
 InspectionPolicy* get_inspection_policy() { return nullptr; }
 Flow::~Flow() = default;
 void ThreadConfig::implement_thread_affinity(SThreadType, unsigned) { }
+void ThreadConfig::apply_thread_policy(SThreadType , unsigned ) { }
 void ThreadConfig::set_instance_tid(int) { }
 }
 
index 1119c8a998a1f188f82d1bfa696a5278a5f42558..87975c2aee20b13405e66121e26910a0ffb47763 100644 (file)
@@ -24,7 +24,6 @@
 #include "thread_config.h"
 
 #include <atomic>
-#include <hwloc.h>
 
 #include "analyzer_command.h"
 #include "log/messages.h"
 #include "time/periodic.h"
 #include "utils/util.h"
 
+#ifdef HAVE_NUMA
+#include "utils/util_numa.h"
+#endif
+
 #ifdef UNIT_TEST
 #include "catch/snort_catch.h"
 #endif
@@ -46,6 +49,13 @@ static unsigned instance_max = 1;
 static std::mutex instance_mutex;
 static std::map<int, int> instance_id_to_tid;
 
+#ifdef HAVE_NUMA
+
+std::shared_ptr<NumaWrapper> numa;
+std::shared_ptr<HwlocWrapper> hwloc;
+
+#endif
+
 struct CpuSet
 {
     CpuSet(hwloc_cpuset_t set) : cpuset(set) { }
@@ -60,6 +70,13 @@ struct CpuSet
 
 bool ThreadConfig::init()
 {
+#ifdef HAVE_NUMA
+
+    numa = std::make_shared<NumaWrapper>();
+    hwloc = std::make_shared<HwlocWrapper>();
+
+#endif
+
     if (hwloc_topology_init(&topology))
         return false;
     if (hwloc_topology_load(topology))
@@ -125,6 +142,13 @@ void ThreadConfig::term()
         process_cpuset = nullptr;
     }
     topology_support = nullptr;
+
+#ifdef HAVE_NUMA
+
+    numa.reset();
+    hwloc.reset();
+
+#endif
 }
 
 ThreadConfig::~ThreadConfig()
@@ -148,7 +172,10 @@ void ThreadConfig::set_thread_affinity(SThreadType type, unsigned id, CpuSet* cp
         thread_affinity[key] = cpuset;
     }
     else
+    {
+        delete cpuset;
         ParseWarning(WARN_CONF, "This platform does not support setting thread affinity.\n");
+    }
 }
 
 void ThreadConfig::set_named_thread_affinity(const string& name, CpuSet* cpuset)
@@ -193,6 +220,78 @@ static inline string stringify_thread(const SThreadType& type, const unsigned& i
     return info;
 }
 
+void ThreadConfig::apply_thread_policy(SThreadType type, unsigned id)
+{
+    implement_thread_affinity( type, id );
+
+#ifdef HAVE_NUMA
+
+    implement_thread_mempolicy( type, id );
+
+#endif
+}
+
+#ifdef HAVE_NUMA
+
+int ThreadConfig::get_numa_node(hwloc_topology_t topology, hwloc_cpuset_t cpuset)
+{
+    int depth = hwloc->get_type_depth(topology, HWLOC_OBJ_NODE);
+    if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
+        return -1;
+
+    for (unsigned i = 0; i < hwloc->get_nbobjs_by_depth(topology, depth); ++i)
+    {
+        hwloc_obj_t node = hwloc->get_obj_by_depth(topology, depth, i);
+        if (node and hwloc->bitmap_intersects(cpuset, node->cpuset))
+            return node->os_index;
+    }
+    return -1;
+}
+
+bool ThreadConfig::set_preferred_mempolicy(int node) 
+{
+    if (node < 0) 
+        return false;
+
+    unsigned long nodemask = 1UL << (unsigned long)node;
+    int result = numa->set_mem_policy(MPOL_PREFERRED, &nodemask, sizeof(nodemask)*8);
+    if (result != 0) 
+        return false;
+    if(numa->preferred() != node) 
+        return false;
+    
+    return true;
+}
+
+bool ThreadConfig::implement_thread_mempolicy(SThreadType type, unsigned id)
+{
+    if (!topology_support->cpubind->set_thisthread_cpubind or 
+                numa->available() < 0 or numa->max_node() <= 0)
+    {     
+        return false;
+    }
+
+    TypeIdPair key { type, id };
+    auto iter = thread_affinity.find(key);
+    if (iter != thread_affinity.end())
+    {
+        int node_index = get_numa_node(topology, iter->second->cpuset);
+        if(set_preferred_mempolicy(node_index))
+            LogMessage( "Preferred memory policy set for %s to node %d\n",stringify_thread(type, id).c_str(), node_index);
+        else
+            return false;
+        }
+    else
+    {
+        return false;
+    }
+    
+    return true;
+}
+
+#endif
+
 void ThreadConfig::implement_thread_affinity(SThreadType type, unsigned id)
 {
     if (!topology_support->cpubind->set_thisthread_cpubind)
@@ -472,4 +571,143 @@ TEST_CASE("Named thread affinity with type configured", "[ThreadConfig]")
     }
 }
 
+#ifdef HAVE_NUMA
+
+class NumaWrapperMock : public NumaWrapper
+{
+public:
+    int numa_avail = 1;
+    int max_n = 1;
+    int pref = 0;
+    int mem_policy = 0;
+
+    int available() override { return numa_avail; }
+    int max_node() override { return max_n; }
+    int preferred() override { return pref; }
+    int set_mem_policy(int , const unsigned long *,
+                              unsigned long ) override
+    { return mem_policy; }
+};
+
+class HwlocWrapperMock : public HwlocWrapper
+{
+public:
+    int nbobjs_by_depth = 1;
+    int type_depth = 2;
+    int intersects = 1;
+    struct hwloc_obj node;
+
+    unsigned get_nbobjs_by_depth(hwloc_topology_t , int ) override
+    { return nbobjs_by_depth; }
+    hwloc_obj_t get_obj_by_depth(hwloc_topology_t, int, unsigned ) override
+    { return &node; }
+    int get_type_depth(hwloc_topology_t, hwloc_obj_type_t ) override
+    { return type_depth; }
+    int bitmap_intersects(hwloc_const_cpuset_t, hwloc_const_cpuset_t ) override
+    { return intersects; }
+};
+
+TEST_CASE("set node for thread", "[ThreadConfig]")
+{
+    CpuSet* cpuset = new CpuSet(hwloc_bitmap_dup(process_cpuset));
+    CpuSet* cpuset2 = new CpuSet(hwloc_bitmap_dup(process_cpuset));
+    ThreadConfig tc;
+
+    std::shared_ptr<NumaWrapperMock> numa_mock = std::make_shared<NumaWrapperMock>();
+    std::shared_ptr<HwlocWrapperMock> hwloc_mock = std::make_shared<HwlocWrapperMock>();
+
+    hwloc_mock->node.os_index = 0; 
+
+    numa = numa_mock;
+    hwloc = hwloc_mock;
+
+    tc.set_thread_affinity(STHREAD_TYPE_PACKET, 0, cpuset2);
+    tc.set_thread_affinity(STHREAD_TYPE_PACKET, 1, cpuset);
+
+    CHECK(tc.implement_thread_mempolicy(STHREAD_TYPE_PACKET, 0));
+
+    hwloc_mock->node.os_index = 1; 
+    numa_mock->pref = 1;
+    CHECK(tc.implement_thread_mempolicy(STHREAD_TYPE_PACKET, 1));
+}   
+
+TEST_CASE("numa_available negative test", "[ThreadConfig]")
+{
+    CpuSet* cpuset = new CpuSet(hwloc_bitmap_dup(process_cpuset));
+    ThreadConfig tc;
+    tc.set_thread_affinity(STHREAD_TYPE_PACKET, 1, cpuset);
+
+    std::shared_ptr<NumaWrapperMock> numa_mock = std::make_shared<NumaWrapperMock>();
+    std::shared_ptr<HwlocWrapperMock> hwloc_mock = std::make_shared<HwlocWrapperMock>();
+
+    numa_mock->numa_avail = -1; 
+    numa = numa_mock;
+    hwloc = hwloc_mock;
+    CHECK(!tc.implement_thread_mempolicy(STHREAD_TYPE_PACKET, 0));
+}
+
+TEST_CASE("set node failure negative test", "[ThreadConfig]")
+{
+    CpuSet* cpuset = new CpuSet(hwloc_bitmap_dup(process_cpuset));
+    ThreadConfig tc;
+    tc.set_thread_affinity(STHREAD_TYPE_PACKET, 0, cpuset);
+
+    std::shared_ptr<NumaWrapperMock> numa_mock = std::make_shared<NumaWrapperMock>();
+    std::shared_ptr<HwlocWrapperMock> hwloc_mock = std::make_shared<HwlocWrapperMock>();
+    hwloc_mock->node.os_index = 0; 
+    numa_mock->pref = -1; 
+    numa = numa_mock;
+    hwloc = hwloc_mock;
+    CHECK(!tc.implement_thread_mempolicy(STHREAD_TYPE_PACKET, 0));
+}
+
+TEST_CASE("depth unknown negative test", "[ThreadConfig]")
+{
+    CpuSet* cpuset = new CpuSet(hwloc_bitmap_dup(process_cpuset));
+
+    ThreadConfig tc;
+    tc.set_thread_affinity(STHREAD_TYPE_PACKET, 0, cpuset);
+
+    std::shared_ptr<NumaWrapperMock> numa_mock = std::make_shared<NumaWrapperMock>();
+    std::shared_ptr<HwlocWrapperMock> hwloc_mock = std::make_shared<HwlocWrapperMock>();
+
+    hwloc_mock->type_depth = HWLOC_TYPE_DEPTH_UNKNOWN;
+    hwloc = hwloc_mock;
+    numa = numa_mock;
+    CHECK(!tc.implement_thread_mempolicy(STHREAD_TYPE_PACKET, 0));
+}
+
+TEST_CASE("set memory policy failure negative test", "[ThreadConfig]")
+{
+    CpuSet* cpuset = new CpuSet(hwloc_bitmap_dup(process_cpuset));
+    ThreadConfig tc;
+    tc.set_thread_affinity(STHREAD_TYPE_PACKET, 0, cpuset);
+
+    std::shared_ptr<NumaWrapperMock> numa_mock = std::make_shared<NumaWrapperMock>();
+    std::shared_ptr<HwlocWrapperMock> hwloc_mock = std::make_shared<HwlocWrapperMock>();
+
+    hwloc_mock->node.os_index = 0;
+    numa_mock->mem_policy = -1;
+    numa = numa_mock;
+    hwloc = hwloc_mock;
+    CHECK(!tc.implement_thread_mempolicy(STHREAD_TYPE_PACKET, 0));    
+}
+
+TEST_CASE("get_nbobjs_by_depth failure negative test", "[ThreadConfig]")
+{
+    CpuSet* cpuset = new CpuSet(hwloc_bitmap_dup(process_cpuset));
+    ThreadConfig tc;
+    tc.set_thread_affinity(STHREAD_TYPE_PACKET, 0, cpuset);
+
+    std::shared_ptr<NumaWrapperMock> numa_mock = std::make_shared<NumaWrapperMock>();
+    std::shared_ptr<HwlocWrapperMock> hwloc_mock = std::make_shared<HwlocWrapperMock>();
+
+    hwloc_mock->nbobjs_by_depth = 0;
+    hwloc = hwloc_mock;
+    numa = numa_mock;
+    CHECK(!tc.implement_thread_mempolicy(STHREAD_TYPE_PACKET, 0));
+}
+
+#endif
+
 #endif
index ba409694179ede8dcd7842dea24e2522ac7fd42c..fb8ec2f25f6eb631404544f2a887c0e0ccc66786 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef THREAD_CONFIG_H
 #define THREAD_CONFIG_H
 
+#include <hwloc.h>
 #include <map>
 #include <string>
 
@@ -44,11 +45,13 @@ public:
     static int get_instance_tid(int);
 
     ~ThreadConfig();
+    void apply_thread_policy(SThreadType type, unsigned id);
     void set_thread_affinity(SThreadType, unsigned id, CpuSet*);
     void set_named_thread_affinity(const std::string&, CpuSet*);
     void implement_thread_affinity(SThreadType, unsigned id);
     void implement_named_thread_affinity(const std::string& name);
-
+    bool implement_thread_mempolicy(SThreadType type, unsigned id);
+    
     static constexpr unsigned int DEFAULT_THREAD_ID = 0;
 
 private:
@@ -70,7 +73,9 @@ private:
     };
     std::map<TypeIdPair, CpuSet*, TypeIdPairComparer> thread_affinity;
     std::map<std::string, CpuSet*> named_thread_affinity;
+
+    bool set_preferred_mempolicy(int node);
+    int get_numa_node(hwloc_topology_t, hwloc_cpuset_t);
 };
 }
-
 #endif
index 19372c3afad863cca32184dc61d2bd82c8bed412..9973a56c23c7f5754dfca9c0a476082d073b7bce 100644 (file)
@@ -16,6 +16,7 @@ set( UTIL_INCLUDES
     util_cstring.h
     util_unfold.h
     util_utf.h
+    util_numa.h
 )
 
 add_library ( utils OBJECT
@@ -40,6 +41,7 @@ add_library ( utils OBJECT
     util_net.h
     util_unfold.cc
     util_utf.cc
+    util_numa.h
     ${TEST_FILES}
 )
 
diff --git a/src/utils/util_numa.h b/src/utils/util_numa.h
new file mode 100644 (file)
index 0000000..53010ba
--- /dev/null
@@ -0,0 +1,74 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2023 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// util_numa.h author Raza Shafiq <rshafiq@cisco.com>
+
+#ifndef NUMA_UTILS_H
+#define NUMA_UTILS_H
+
+#ifdef HAVE_NUMA
+
+#include <numa.h>
+#include <numaif.h>
+#include <sched.h>
+#include <hwloc.h>
+
+class NumaWrapper
+{
+public:
+    virtual ~NumaWrapper() {}
+    virtual int available() 
+    { 
+        return numa_available(); 
+    }
+    virtual int max_node() 
+    { 
+        return numa_max_node(); 
+    }
+    virtual int preferred() 
+    { 
+        return numa_preferred(); 
+    }
+    virtual int set_mem_policy(int mode, const unsigned long *nodemask,
+                              unsigned long maxnode)
+    {
+        return set_mempolicy(mode, nodemask, maxnode);
+    }
+};
+class HwlocWrapper
+{
+public:
+    virtual ~HwlocWrapper() {}
+    virtual unsigned get_nbobjs_by_depth(hwloc_topology_t topology, int depth)
+    {
+        return hwloc_get_nbobjs_by_depth(topology, depth);
+    }
+    virtual hwloc_obj_t get_obj_by_depth(hwloc_topology_t topology, int depth, unsigned idx)
+    {
+        return hwloc_get_obj_by_depth(topology, depth, idx);
+    }
+    virtual int get_type_depth(hwloc_topology_t topology, hwloc_obj_type_t type)
+    {
+        return hwloc_get_type_depth(topology, type);
+    }
+    virtual int bitmap_intersects(hwloc_const_cpuset_t set1, hwloc_const_cpuset_t set2)
+    {
+        return hwloc_bitmap_intersects(set1, set2);
+    }
+};
+#endif // HAVE_NUMA
+#endif // NUMA_UTILS_H
\ No newline at end of file