Skip to content

Commit a988a34

Browse files
committed
initial changes for mpi shared memory socket scope
1 parent f81afca commit a988a34

13 files changed

Lines changed: 254 additions & 11 deletions

docs/sphinx/cookbook/shared_memory_allocators.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ To create an allocator with the MPI3 Shared Memory resource, you can do the foll
7979
.. code-block:: cpp
8080
8181
auto traits{umpire::get_default_resource_traits("SHARED::MPI3")};
82+
traits.scope = umpire::MemoryResourceTraits::shared_scope::socket; // or node
8283
auto node_allocator{rm.makeResource("SHARED::mpi3_alloc", traits)};
8384
8485
See the bottom of this page for a full example of how to use MPI3 Shared Memory Allocators with Umpire.
@@ -131,4 +132,3 @@ when creating the MPI3 Shared Memory allocator, a name is not needed when alloca
131132

132133
.. literalinclude:: ../../../examples/mpi3_shared_memory.cpp
133134
:language: cpp
134-

examples/mpi3_shared_memory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ int main(int argc, char** argv)
2121
auto traits = umpire::get_default_resource_traits("SHARED::MPI3");
2222
traits.size = 1 * 1024 * 1024; // 1 MB
2323

24-
// Node scope is required for mpi3 shared memory
24+
// Node scope is the default for MPI3 shared memory; socket scope is also supported.
2525
traits.scope = umpire::MemoryResourceTraits::shared_scope::node;
2626

2727
// Create allocator using MPI3 shared memory

src/umpire/Umpire.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
#include "umpire/ResourceManager.hpp"
1919
#include "umpire/config.hpp"
20+
#if defined(UMPIRE_ENABLE_MPI3_SHARED_MEMORY)
21+
#include "umpire/resource/HostMpi3SharedMemoryResource.hpp"
22+
#endif
2023
#include "umpire/resource/HostSharedMemoryResource.hpp"
2124
#include "umpire/resource/MemoryResource.hpp"
2225
#if defined(UMPIRE_ENABLE_MPI) && defined(UMPIRE_ENABLE_IPC_SHARED_MEMORY)
@@ -27,6 +30,7 @@
2730
#include "umpire/strategy/DynamicPoolList.hpp"
2831
#include "umpire/strategy/QuickPool.hpp"
2932
#include "umpire/strategy/ResourceAwarePool.hpp"
33+
#include "umpire/util/mpi_shared.hpp"
3034
#include "umpire/util/wrap_allocator.hpp"
3135

3236
#if !defined(_MSC_VER)
@@ -318,6 +322,10 @@ MPI_Comm get_communicator_for_allocator(Allocator a, MPI_Comm comm)
318322
if (auto alloc = dynamic_cast<strategy::DeviceIpcAllocator*>(a.getAllocationStrategy()))
319323
return alloc->get_scope_communicator();
320324
#endif
325+
#if defined(UMPIRE_ENABLE_MPI3_SHARED_MEMORY)
326+
if (auto resource = dynamic_cast<resource::HostMpi3SharedMemoryResource*>(a.getAllocationStrategy()))
327+
return resource->getSharedCommunicator();
328+
#endif
321329

322330
std::map<int, MPI_Comm>& cached_communicators = get_cached_communicators();
323331

@@ -329,8 +337,8 @@ MPI_Comm get_communicator_for_allocator(Allocator a, MPI_Comm comm)
329337
if (cached_comm != cached_communicators.end()) {
330338
c = cached_comm->second;
331339
} else {
332-
if (scope == MemoryResourceTraits::shared_scope::node) {
333-
MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &c);
340+
if (scope == MemoryResourceTraits::shared_scope::node || scope == MemoryResourceTraits::shared_scope::socket) {
341+
c = util::create_shared_communicator(comm, scope);
334342
} else {
335343
c = MPI_COMM_NULL;
336344
}

src/umpire/resource/HostMpi3SharedMemoryResource.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "umpire/resource/MemoryResource.hpp"
1111
#include "umpire/util/MPI.hpp"
1212
#include "umpire/util/Macros.hpp"
13+
#include "umpire/util/mpi_shared.hpp"
1314
#include "umpire/util/error.hpp"
1415

1516
namespace umpire {
@@ -18,8 +19,7 @@ namespace resource {
1819
HostMpi3SharedMemoryResource::HostMpi3SharedMemoryResource(const std::string& name, int id, MemoryResourceTraits traits)
1920
: MemoryResource{name, id, traits}
2021
{
21-
constexpr int IGNORE_KEY{0};
22-
MPI_Comm_split_type(util::MPI::getCommunicator(), MPI_COMM_TYPE_SHARED, IGNORE_KEY, MPI_INFO_NULL, &m_shared_comm);
22+
m_shared_comm = util::create_shared_communicator(util::MPI::getCommunicator(), traits.scope);
2323
MPI_Comm_rank(m_shared_comm, &m_local_rank);
2424

2525
// Free the comm at exit during cleanup in MPI_Finalize. We pass the m_shared_comm
@@ -73,6 +73,11 @@ Platform HostMpi3SharedMemoryResource::getPlatform() noexcept
7373
return Platform::host;
7474
}
7575

76+
MPI_Comm HostMpi3SharedMemoryResource::getSharedCommunicator() const noexcept
77+
{
78+
return m_shared_comm;
79+
}
80+
7681
int HostMpi3SharedMemoryResource::free_comm(MPI_Comm UMPIRE_UNUSED_ARG(comm), int UMPIRE_UNUSED_ARG(keyval),
7782
void* attribute_val, void* UMPIRE_UNUSED_ARG(extra_state))
7883
{

src/umpire/resource/HostMpi3SharedMemoryResource.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
//
55
// SPDX-License-Identifier: (MIT)
66
//////////////////////////////////////////////////////////////////////////////
7-
#ifndef __Host_Shared_Memory_Resource_HPP
8-
#define __Host_Shared_Memory_Resource_HPP
7+
#ifndef UMPIRE_Host_Mpi3_Shared_Memory_Resource_HPP
8+
#define UMPIRE_Host_Mpi3_Shared_Memory_Resource_HPP
99

1010
#include <map>
1111
#include <memory>
@@ -32,6 +32,8 @@ class HostMpi3SharedMemoryResource : public MemoryResource {
3232

3333
Platform getPlatform() noexcept override;
3434

35+
MPI_Comm getSharedCommunicator() const noexcept;
36+
3537
private:
3638
static int free_comm(MPI_Comm comm, int keyval, void* attribute_val, void* extra_state);
3739

@@ -42,4 +44,4 @@ class HostMpi3SharedMemoryResource : public MemoryResource {
4244

4345
} // end of namespace resource
4446
} // end of namespace umpire
45-
#endif // __Host_Shared_Memory_Resource_HPP
47+
#endif // UMPIRE_Host_Mpi3_Shared_Memory_Resource_HPP

src/umpire/resource/HostMpi3SharedMemoryResourceFactory.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ std::unique_ptr<resource::MemoryResource> HostMpi3SharedMemoryResourceFactory::c
2828
std::unique_ptr<resource::MemoryResource> HostMpi3SharedMemoryResourceFactory::create(const std::string& name, int id,
2929
MemoryResourceTraits traits)
3030
{
31-
if (traits.scope != MemoryResourceTraits::shared_scope::node) {
32-
UMPIRE_ERROR(runtime_error, "HostMpi3SharedMemoryResource only supports shared_scope::node");
31+
if (traits.scope != MemoryResourceTraits::shared_scope::node &&
32+
traits.scope != MemoryResourceTraits::shared_scope::socket) {
33+
UMPIRE_ERROR(runtime_error, "HostMpi3SharedMemoryResource only supports shared_scope::node or ::socket");
3334
}
3435
return util::make_unique<HostMpi3SharedMemoryResource>(name, id, traits);
3536
}

src/umpire/util/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ set (umpire_util_headers
2222
MemoryResourceTraits.hpp
2323
MemoryMap.hpp
2424
MemoryMap.inl
25+
mpi_shared.hpp
2526
OutputBuffer.hpp
2627
Platform.hpp
2728
allocation_statistics.hpp
@@ -43,6 +44,7 @@ set (umpire_util_sources
4344
io.cpp
4445
Logger.cpp
4546
MPI.cpp
47+
mpi_shared.cpp
4648
OutputBuffer.cpp
4749
allocation_statistics.cpp
4850
detect_vendor.cpp)

src/umpire/util/mpi_shared.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//////////////////////////////////////////////////////////////////////////////
2+
// Copyright (c) 2016-26, Lawrence Livermore National Security, LLC and Umpire
3+
// project contributors. See the COPYRIGHT file for details.
4+
//
5+
// SPDX-License-Identifier: (MIT)
6+
//////////////////////////////////////////////////////////////////////////////
7+
8+
#include "umpire/util/mpi_shared.hpp"
9+
10+
#if defined(UMPIRE_ENABLE_MPI)
11+
12+
#include <fstream>
13+
#include <string>
14+
15+
#if defined(__linux__)
16+
#include <sched.h>
17+
#endif
18+
19+
#include "umpire/util/Macros.hpp"
20+
#if defined(UMPIRE_ENABLE_NUMA)
21+
#include "umpire/util/numa.hpp"
22+
#endif
23+
#include "umpire/util/error.hpp"
24+
25+
namespace umpire {
26+
namespace util {
27+
28+
namespace {
29+
30+
constexpr int IGNORE_KEY{0};
31+
32+
bool get_socket_color_from_package_id(int& color)
33+
{
34+
#if defined(__linux__)
35+
const int cpu = sched_getcpu();
36+
if (cpu < 0) {
37+
UMPIRE_LOG(Debug, "sched_getcpu failed while determining socket color");
38+
return false;
39+
}
40+
41+
std::ifstream package_id_file{"/sys/devices/system/cpu/cpu" + std::to_string(cpu) +
42+
"/topology/physical_package_id"};
43+
if (!package_id_file) {
44+
UMPIRE_LOG(Debug, "Could not open physical_package_id for cpu " << cpu);
45+
return false;
46+
}
47+
48+
package_id_file >> color;
49+
if (!package_id_file) {
50+
UMPIRE_LOG(Debug, "Could not read physical_package_id for cpu " << cpu);
51+
return false;
52+
}
53+
54+
UMPIRE_LOG(Debug, "Using Linux physical_package_id " << color << " for cpu " << cpu);
55+
return true;
56+
#else
57+
UMPIRE_USE_VAR(color);
58+
return false;
59+
#endif
60+
}
61+
62+
bool get_socket_color_from_numa(int& color)
63+
{
64+
#if defined(UMPIRE_ENABLE_NUMA) && defined(__linux__)
65+
const int cpu = sched_getcpu();
66+
if (cpu < 0) {
67+
UMPIRE_LOG(Debug, "sched_getcpu failed while determining NUMA fallback color");
68+
return false;
69+
}
70+
71+
try {
72+
color = numa::node_of_cpu(cpu);
73+
UMPIRE_LOG(Debug, "Using NUMA node " << color << " as socket color fallback for cpu " << cpu);
74+
return true;
75+
} catch (const std::exception& e) {
76+
UMPIRE_LOG(Debug, "NUMA fallback failed for cpu " << cpu << ": " << e.what());
77+
return false;
78+
}
79+
#else
80+
UMPIRE_USE_VAR(color);
81+
return false;
82+
#endif
83+
}
84+
85+
} // end anonymous namespace
86+
87+
MPI_Comm create_shared_communicator(MPI_Comm comm, MemoryResourceTraits::shared_scope scope)
88+
{
89+
MPI_Comm shared_comm{MPI_COMM_NULL};
90+
91+
if (scope == MemoryResourceTraits::shared_scope::node) {
92+
MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, IGNORE_KEY, MPI_INFO_NULL, &shared_comm);
93+
return shared_comm;
94+
}
95+
96+
if (scope == MemoryResourceTraits::shared_scope::socket) {
97+
MPI_Comm node_comm{MPI_COMM_NULL};
98+
MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, IGNORE_KEY, MPI_INFO_NULL, &node_comm);
99+
100+
int color{-1};
101+
if (!get_socket_color_from_package_id(color) && !get_socket_color_from_numa(color)) {
102+
MPI_Comm_free(&node_comm);
103+
UMPIRE_ERROR(runtime_error,
104+
"Unable to determine a socket color for shared_scope::socket. "
105+
"Expected Linux CPU topology data or a NUMA fallback.");
106+
}
107+
108+
UMPIRE_LOG(Debug, "Creating socket-scoped shared communicator with color " << color);
109+
MPI_Comm_split(node_comm, color, IGNORE_KEY, &shared_comm);
110+
MPI_Comm_free(&node_comm);
111+
return shared_comm;
112+
}
113+
114+
UMPIRE_ERROR(runtime_error,
115+
fmt::format("Unsupported shared communicator scope: {}", to_string(scope)));
116+
}
117+
118+
} // end of namespace util
119+
} // end of namespace umpire
120+
121+
#endif

src/umpire/util/mpi_shared.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//////////////////////////////////////////////////////////////////////////////
2+
// Copyright (c) 2016-26, Lawrence Livermore National Security, LLC and Umpire
3+
// project contributors. See the COPYRIGHT file for details.
4+
//
5+
// SPDX-License-Identifier: (MIT)
6+
//////////////////////////////////////////////////////////////////////////////
7+
#ifndef UMPIRE_mpi_shared_HPP
8+
#define UMPIRE_mpi_shared_HPP
9+
10+
#include "umpire/config.hpp"
11+
#include "umpire/util/MemoryResourceTraits.hpp"
12+
13+
#if defined(UMPIRE_ENABLE_MPI)
14+
#include "mpi.h"
15+
#endif
16+
17+
namespace umpire {
18+
namespace util {
19+
20+
#if defined(UMPIRE_ENABLE_MPI)
21+
MPI_Comm create_shared_communicator(MPI_Comm comm, MemoryResourceTraits::shared_scope scope);
22+
#endif
23+
24+
} // end of namespace util
25+
} // end of namespace umpire
26+
27+
#endif // UMPIRE_mpi_shared_HPP

src/umpire/util/numa.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ int get_location(void* ptr)
5858
return numa_node;
5959
}
6060

61+
int node_of_cpu(int cpu)
62+
{
63+
if (numa_available() < 0)
64+
UMPIRE_ERROR(runtime_error, "libnuma is unusable.");
65+
66+
const int numa_node = numa_node_of_cpu(cpu);
67+
if (numa_node < 0) {
68+
UMPIRE_ERROR(runtime_error, fmt::format("numa::node_of_cpu error for cpu {}", cpu));
69+
}
70+
71+
return numa_node;
72+
}
73+
6174
std::vector<int> get_host_nodes()
6275
{
6376
if (numa_available() < 0)

0 commit comments

Comments
 (0)