Skip to content

Commit 8a4d1bb

Browse files
committed
Add tests for memspace "highest bandwidth"
Those tests are skipped with GTEST_SKIP() when bandwidth property can't be queried (HMAT is not supported on the platform).
1 parent a800d2f commit 8a4d1bb

File tree

4 files changed

+203
-108
lines changed

4 files changed

+203
-108
lines changed

test/memspaces/memspace_helpers.hpp

Lines changed: 38 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
#include "base.hpp"
99
#include "memspace_internal.h"
1010
#include "memspaces/memspace_numa.h"
11+
#include "test_helpers.h"
1112

1213
#include <numa.h>
14+
#include <numaif.h>
1315
#include <umf/providers/provider_os_memory.h>
1416

1517
#define SIZE_4K (4096UL)
@@ -40,75 +42,44 @@ struct numaNodesTest : ::umf_test::test {
4042
unsigned long maxNodeId = 0;
4143
};
4244

43-
struct memspaceNumaTest : ::numaNodesTest {
44-
void SetUp() override {
45-
::numaNodesTest::SetUp();
46-
47-
enum umf_result_t ret = umfMemspaceCreateFromNumaArray(
48-
nodeIds.data(), nodeIds.size(), &hMemspace);
49-
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
50-
ASSERT_NE(hMemspace, nullptr);
51-
}
52-
53-
void TearDown() override {
54-
::numaNodesTest::TearDown();
55-
if (hMemspace) {
56-
umfMemspaceDestroy(hMemspace);
45+
///
46+
/// @brief Retrieves the memory policy information for \p ptr.
47+
/// @param ptr allocation pointer.
48+
/// @param maxNodeId maximum node id.
49+
/// @param mode [out] memory policy.
50+
/// @param boundNodeIds [out] node ids associated with the policy.
51+
/// @param allocNodeId [out] id of the node that allocated the memory.
52+
///
53+
void getAllocationPolicy(void *ptr, unsigned long maxNodeId, int &mode,
54+
std::vector<size_t> &boundNodeIds,
55+
size_t &allocNodeId) {
56+
const static unsigned bitsPerUlong = sizeof(unsigned long) * 8;
57+
58+
const unsigned nrUlongs = (maxNodeId + bitsPerUlong) / bitsPerUlong;
59+
std::vector<unsigned long> memNodeMasks(nrUlongs, 0);
60+
61+
int memMode = -1;
62+
// Get policy and the nodes associated with this policy.
63+
int ret = get_mempolicy(&memMode, memNodeMasks.data(),
64+
nrUlongs * bitsPerUlong, ptr, MPOL_F_ADDR);
65+
UT_ASSERTeq(ret, 0);
66+
mode = memMode;
67+
68+
UT_ASSERTeq(boundNodeIds.size(), 0);
69+
for (size_t i = 0; i <= maxNodeId; i++) {
70+
const size_t memNodeMaskIdx = ((i + bitsPerUlong) / bitsPerUlong) - 1;
71+
const auto &memNodeMask = memNodeMasks.at(memNodeMaskIdx);
72+
73+
if (memNodeMask && (1UL << (i % bitsPerUlong))) {
74+
boundNodeIds.emplace_back(i);
5775
}
5876
}
5977

60-
umf_memspace_handle_t hMemspace = nullptr;
61-
};
62-
63-
struct memspaceNumaProviderTest : ::memspaceNumaTest {
64-
void SetUp() override {
65-
::memspaceNumaTest::SetUp();
66-
67-
umf_result_t ret =
68-
umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider);
69-
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
70-
ASSERT_NE(hProvider, nullptr);
71-
}
72-
73-
void TearDown() override {
74-
::memspaceNumaTest::TearDown();
75-
76-
if (hProvider != nullptr) {
77-
umfMemoryProviderDestroy(hProvider);
78-
}
79-
}
80-
81-
umf_memory_provider_handle_t hProvider = nullptr;
82-
};
83-
84-
struct memspaceHostAllTest : ::numaNodesTest {
85-
void SetUp() override {
86-
::numaNodesTest::SetUp();
87-
88-
hMemspace = umfMemspaceHostAllGet();
89-
ASSERT_NE(hMemspace, nullptr);
90-
}
91-
92-
umf_memspace_handle_t hMemspace = nullptr;
93-
};
94-
95-
struct memspaceHostAllProviderTest : ::memspaceHostAllTest {
96-
void SetUp() override {
97-
::memspaceHostAllTest::SetUp();
98-
99-
umf_result_t ret =
100-
umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider);
101-
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
102-
ASSERT_NE(hProvider, nullptr);
103-
}
104-
105-
void TearDown() override {
106-
::memspaceHostAllTest::TearDown();
107-
108-
umfMemoryProviderDestroy(hProvider);
109-
}
110-
111-
umf_memory_provider_handle_t hProvider = nullptr;
112-
};
78+
// Get the node that allocated the memory at 'ptr'.
79+
int nodeId = -1;
80+
ret = get_mempolicy(&nodeId, nullptr, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE);
81+
UT_ASSERTeq(ret, 0);
82+
allocNodeId = static_cast<size_t>(nodeId);
83+
}
11384

11485
#endif /* UMF_MEMSPACE_HELPERS_HPP */

test/memspaces/memspace_highest_bandwidth.cpp

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,104 @@
77
#include "memspace_internal.h"
88
#include "test_helpers.h"
99

10+
#include <hwloc.h>
1011
#include <numa.h>
1112
#include <numaif.h>
1213
#include <umf/memspace.h>
1314

1415
using umf_test::test;
1516

16-
TEST_F(numaNodesTest, memspaceGet) {
17-
umf_memspace_handle_t hMemspace = umfMemspaceHighestBandwidthGet();
18-
UT_ASSERTne(hMemspace, nullptr);
17+
static bool canQueryBandwidth(size_t nodeId) {
18+
hwloc_topology_t topology = nullptr;
19+
int ret = hwloc_topology_init(&topology);
20+
UT_ASSERTeq(ret, 0);
21+
ret = hwloc_topology_load(topology);
22+
UT_ASSERTeq(ret, 0);
23+
24+
hwloc_obj_t numaNode =
25+
hwloc_get_obj_by_type(topology, HWLOC_OBJ_NUMANODE, nodeId);
26+
UT_ASSERTne(numaNode, nullptr);
27+
28+
// Get local cpuset.
29+
hwloc_const_cpuset_t cCpuset = hwloc_topology_get_allowed_cpuset(topology);
30+
hwloc_cpuset_t cpuset = hwloc_bitmap_dup(cCpuset);
31+
32+
// Setup initiator structure.
33+
struct hwloc_location initiator;
34+
initiator.location.cpuset = cpuset;
35+
initiator.type = HWLOC_LOCATION_TYPE_CPUSET;
36+
37+
hwloc_uint64_t value = 0;
38+
ret = hwloc_memattr_get_value(topology, HWLOC_MEMATTR_ID_BANDWIDTH,
39+
numaNode, &initiator, 0, &value);
40+
41+
hwloc_bitmap_free(cpuset);
42+
hwloc_topology_destroy(topology);
43+
return (ret == 0);
44+
}
45+
46+
struct memspaceHighestBandwidthTest : ::numaNodesTest {
47+
void SetUp() override {
48+
::numaNodesTest::SetUp();
49+
50+
if (!canQueryBandwidth(nodeIds.front())) {
51+
GTEST_SKIP();
52+
}
53+
54+
hMemspace = umfMemspaceHighestBandwidthGet();
55+
ASSERT_NE(hMemspace, nullptr);
56+
}
57+
58+
umf_memspace_handle_t hMemspace = nullptr;
59+
};
60+
61+
struct memspaceHighestBandwidthProviderTest : ::memspaceHighestBandwidthTest {
62+
void SetUp() override {
63+
::memspaceHighestBandwidthTest::SetUp();
64+
65+
if (!canQueryBandwidth(nodeIds.front())) {
66+
GTEST_SKIP();
67+
}
68+
69+
umf_result_t ret =
70+
umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider);
71+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
72+
ASSERT_NE(hProvider, nullptr);
73+
}
74+
75+
void TearDown() override {
76+
::memspaceHighestBandwidthTest::TearDown();
77+
78+
if (hProvider) {
79+
umfMemoryProviderDestroy(hProvider);
80+
}
81+
}
82+
83+
umf_memory_provider_handle_t hProvider = nullptr;
84+
};
85+
86+
TEST_F(memspaceHighestBandwidthTest, providerFromMemspace) {
87+
umf_memory_provider_handle_t hProvider = nullptr;
88+
enum umf_result_t ret =
89+
umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider);
90+
UT_ASSERTeq(ret, UMF_RESULT_SUCCESS);
91+
UT_ASSERTne(hProvider, nullptr);
92+
93+
umfMemoryProviderDestroy(hProvider);
94+
}
95+
96+
TEST_F(memspaceHighestBandwidthProviderTest, allocFree) {
97+
void *ptr = nullptr;
98+
size_t size = SIZE_4K;
99+
size_t alignment = 0;
100+
101+
enum umf_result_t ret =
102+
umfMemoryProviderAlloc(hProvider, size, alignment, &ptr);
103+
UT_ASSERTeq(ret, UMF_RESULT_SUCCESS);
104+
UT_ASSERTne(ptr, nullptr);
105+
106+
memset(ptr, 0xFF, size);
107+
108+
ret = umfMemoryProviderFree(hProvider, ptr, size);
109+
UT_ASSERTeq(ret, UMF_RESULT_SUCCESS);
19110
}

test/memspaces/memspace_host_all.cpp

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,36 @@
1616

1717
using umf_test::test;
1818

19+
struct memspaceHostAllTest : ::numaNodesTest {
20+
void SetUp() override {
21+
::numaNodesTest::SetUp();
22+
23+
hMemspace = umfMemspaceHostAllGet();
24+
ASSERT_NE(hMemspace, nullptr);
25+
}
26+
27+
umf_memspace_handle_t hMemspace = nullptr;
28+
};
29+
30+
struct memspaceHostAllProviderTest : ::memspaceHostAllTest {
31+
void SetUp() override {
32+
::memspaceHostAllTest::SetUp();
33+
34+
umf_result_t ret =
35+
umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider);
36+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
37+
ASSERT_NE(hProvider, nullptr);
38+
}
39+
40+
void TearDown() override {
41+
::memspaceHostAllTest::TearDown();
42+
43+
umfMemoryProviderDestroy(hProvider);
44+
}
45+
46+
umf_memory_provider_handle_t hProvider = nullptr;
47+
};
48+
1949
TEST_F(numaNodesTest, memspaceGet) {
2050
umf_memspace_handle_t hMemspace = umfMemspaceHostAllGet();
2151
UT_ASSERTne(hMemspace, nullptr);
@@ -58,44 +88,6 @@ TEST_F(memspaceHostAllProviderTest, allocFree) {
5888
UT_ASSERTeq(ret, UMF_RESULT_SUCCESS);
5989
}
6090

61-
///
62-
/// @brief Retrieves the memory policy information for \p ptr.
63-
/// @param ptr allocation pointer.
64-
/// @param maxNodeId maximum node id.
65-
/// @param mode [out] memory policy.
66-
/// @param boundNodeIds [out] node ids associated with the policy.
67-
/// @param allocNodeId [out] id of the node that allocated the memory.
68-
///
69-
static void getAllocationPolicy(void *ptr, unsigned long maxNodeId, int &mode,
70-
std::vector<size_t> &boundNodeIds,
71-
size_t &allocNodeId) {
72-
const static unsigned bitsPerUlong = sizeof(unsigned long) * 8;
73-
74-
const unsigned nrUlongs = (maxNodeId + bitsPerUlong) / bitsPerUlong;
75-
std::vector<unsigned long> memNodeMasks(nrUlongs, 0);
76-
77-
int memMode = -1;
78-
// Get policy and the nodes associated with this policy.
79-
int ret = get_mempolicy(&memMode, memNodeMasks.data(),
80-
nrUlongs * bitsPerUlong, ptr, MPOL_F_ADDR);
81-
UT_ASSERTeq(ret, 0);
82-
mode = memMode;
83-
84-
UT_ASSERTeq(boundNodeIds.size(), 0);
85-
for (size_t i = 0; i <= maxNodeId; i++) {
86-
const size_t memNodeMaskIdx = ((i + bitsPerUlong) / bitsPerUlong) - 1;
87-
const auto &memNodeMask = memNodeMasks.at(memNodeMaskIdx);
88-
89-
if (memNodeMask && (1UL << (i % bitsPerUlong))) {
90-
boundNodeIds.emplace_back(i);
91-
}
92-
}
93-
94-
// Get the node that allocated the memory at 'ptr'.
95-
int nodeId = getNumaNodeByPtr(ptr);
96-
allocNodeId = static_cast<size_t>(nodeId);
97-
}
98-
9991
TEST_F(memspaceHostAllProviderTest, allocsSpreadAcrossAllNumaNodes) {
10092
// This testcase is unsuitable for TSan.
10193
#ifdef __SANITIZE_THREAD__

test/memspaces/memspace_numa.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,47 @@
99

1010
#include <umf/providers/provider_os_memory.h>
1111

12+
struct memspaceNumaTest : ::numaNodesTest {
13+
void SetUp() override {
14+
::numaNodesTest::SetUp();
15+
16+
enum umf_result_t ret = umfMemspaceCreateFromNumaArray(
17+
nodeIds.data(), nodeIds.size(), &hMemspace);
18+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
19+
ASSERT_NE(hMemspace, nullptr);
20+
}
21+
22+
void TearDown() override {
23+
::numaNodesTest::TearDown();
24+
if (hMemspace) {
25+
umfMemspaceDestroy(hMemspace);
26+
}
27+
}
28+
29+
umf_memspace_handle_t hMemspace = nullptr;
30+
};
31+
32+
struct memspaceNumaProviderTest : ::memspaceNumaTest {
33+
void SetUp() override {
34+
::memspaceNumaTest::SetUp();
35+
36+
umf_result_t ret =
37+
umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider);
38+
ASSERT_EQ(ret, UMF_RESULT_SUCCESS);
39+
ASSERT_NE(hProvider, nullptr);
40+
}
41+
42+
void TearDown() override {
43+
::memspaceNumaTest::TearDown();
44+
45+
if (hProvider != nullptr) {
46+
umfMemoryProviderDestroy(hProvider);
47+
}
48+
}
49+
50+
umf_memory_provider_handle_t hProvider = nullptr;
51+
};
52+
1253
TEST_F(numaNodesTest, createDestroy) {
1354
umf_memspace_handle_t hMemspace = nullptr;
1455
enum umf_result_t ret = umfMemspaceCreateFromNumaArray(

0 commit comments

Comments
 (0)