Enable GDA+IPC (#249)
* Enable GDA+IPC
Fix ROCSHMEM_DISABLE_IPC for both RO and GDA
* add more functionality to bootstrap class
we need a few more functions in the boostrap class to be able to fully
handle the rocshmem requirements:
- add a function to return the list of local ranks
- provide a groupAllgather operation which takes a vector of ranks
participating
- provide a groupAlltoall operation which takes a vector of ranks
participating
Also, update the functionality of the gda-Alltoall and gda-Allreduce
operations to take advantage of these functions.
* ipc_policy adapted to use bootstrap groupallgather
* bugfix: there was a mistake in computing sendto in groupallgather
* bugfix: shm_size and shm_rank were set in a local variable rather than
the class member
* mpi-bootstrap: remove an unecessary allgather
---------
Co-authored-by: Edgar Gabriel <Edgar.Gabriel@amd.com>
[ROCm/rocshmem commit: 801d2c5012]
This commit is contained in:
gecommit door
GitHub
bovenliggende
c33fa46a00
commit
bce851466b
@@ -63,12 +63,12 @@ target_compile_options(${PROJECT_NAME} PUBLIC ${ROCSHMEM_COMPILE_FLAGS})
|
||||
###############################################################################
|
||||
# ROCSHMEM TARGET FOR BACKENDS
|
||||
###############################################################################
|
||||
if (USE_RO)
|
||||
if (USE_GDA)
|
||||
add_subdirectory(gda)
|
||||
elseif (USE_RO)
|
||||
add_subdirectory(reverse_offload)
|
||||
elseif (USE_IPC)
|
||||
add_subdirectory(ipc)
|
||||
elseif (USE_GDA)
|
||||
add_subdirectory(gda)
|
||||
endif()
|
||||
add_subdirectory(host)
|
||||
add_subdirectory(containers)
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#include "backend_type.hpp"
|
||||
#include "context_incl.hpp"
|
||||
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#include "gda/backend_gda.hpp"
|
||||
#elif defined(USE_RO)
|
||||
#include "reverse_offload/backend_ro.hpp"
|
||||
#elif defined(USE_IPC)
|
||||
#include "ipc/backend_ipc.hpp"
|
||||
#elif defined(USE_GDA)
|
||||
#include "gda/backend_gda.hpp"
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
@@ -249,22 +249,22 @@ void Backend::reset_stats() {
|
||||
}
|
||||
|
||||
__device__ bool Backend::create_ctx(int64_t option, rocshmem_ctx_t* ctx) {
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
return static_cast<GDABackend*>(this)->create_ctx(option, ctx);
|
||||
#elif defined(USE_RO)
|
||||
return static_cast<ROBackend*>(this)->create_ctx(option, ctx);
|
||||
#elif defined(USE_IPC)
|
||||
return static_cast<IPCBackend*>(this)->create_ctx(option, ctx);
|
||||
#elif defined(USE_GDA)
|
||||
return static_cast<GDABackend*>(this)->create_ctx(option, ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
__device__ void Backend::destroy_ctx(rocshmem_ctx_t* ctx) {
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
static_cast<GDABackend*>(this)->destroy_ctx(ctx);
|
||||
#elif defined(USE_RO)
|
||||
static_cast<ROBackend*>(this)->destroy_ctx(ctx);
|
||||
#elif defined(USE_IPC)
|
||||
static_cast<IPCBackend*>(this)->destroy_ctx(ctx);
|
||||
#elif defined(USE_GDA)
|
||||
static_cast<GDABackend*>(this)->destroy_ctx(ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace rocshmem {
|
||||
* @note Derived classes which use Backend as a base class must add
|
||||
* themselves to this enum class to support static polymorphism.
|
||||
*/
|
||||
enum class BackendType { RO_BACKEND, IPC_BACKEND, GDA_BACKEND };
|
||||
enum class BackendType { GDA_BACKEND, RO_BACKEND, IPC_BACKEND };
|
||||
|
||||
/**
|
||||
* @brief Helper macro for some dispatch calls
|
||||
@@ -56,52 +56,52 @@ enum class BackendType { RO_BACKEND, IPC_BACKEND, GDA_BACKEND };
|
||||
/**
|
||||
* @brief Device static dispatch method call.
|
||||
*/
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#define DISPATCH(Func) \
|
||||
static_cast<GDAContext *>(this)->Func;
|
||||
#elif defined(USE_RO)
|
||||
#define DISPATCH(Func) \
|
||||
static_cast<ROContext *>(this)->Func;
|
||||
#elif defined(USE_IPC)
|
||||
#define DISPATCH(Func) \
|
||||
static_cast<IPCContext *>(this)->Func;
|
||||
#elif defined(USE_GDA)
|
||||
#define DISPATCH(Func) \
|
||||
static_cast<GDAContext *>(this)->Func;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Device static dispatch method call with a return value.
|
||||
*/
|
||||
#if defined(USE_RO)
|
||||
#define DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<ROContext *>(this)->Func; \
|
||||
#if defined(USE_GDA)
|
||||
#define DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<GDAContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_RO)
|
||||
#define DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<ROContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_IPC)
|
||||
#define DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<IPCContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_GDA)
|
||||
#define DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<GDAContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Device static dispatch method call with a return type of pointer.
|
||||
*/
|
||||
#if defined(USE_RO)
|
||||
#define DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<ROContext *>(this)->Func; \
|
||||
#if defined(USE_GDA)
|
||||
#define DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<GDAContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_RO)
|
||||
#define DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<ROContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_IPC)
|
||||
#define DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<IPCContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_GDA)
|
||||
#define DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<GDAContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -111,12 +111,12 @@ enum class BackendType { RO_BACKEND, IPC_BACKEND, GDA_BACKEND };
|
||||
* MPI_THREAD_MULTIPLE (for RMA and AMO operations) and the ordering and
|
||||
* threading semantics of collectives in OpenSHMEM match those of MPI.
|
||||
*/
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#define HOST_DISPATCH(Func) static_cast<GDAHostContext *>(this)->Func;
|
||||
#elif defined(USE_RO)
|
||||
#define HOST_DISPATCH(Func) static_cast<ROHostContext *>(this)->Func;
|
||||
#elif defined(USE_IPC)
|
||||
#define HOST_DISPATCH(Func) static_cast<IPCHostContext *>(this)->Func;
|
||||
#elif defined(USE_GDA)
|
||||
#define HOST_DISPATCH(Func) static_cast<GDAHostContext *>(this)->Func;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -126,24 +126,29 @@ enum class BackendType { RO_BACKEND, IPC_BACKEND, GDA_BACKEND };
|
||||
* MPI_THREAD_MULTIPLE (for RMA and AMO operations) and the ordering and
|
||||
* threading semantics of collectives in OpenSHMEM match those of MPI.
|
||||
*/
|
||||
#if defined(USE_RO)
|
||||
#define HOST_DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<ROHostContext *>(this)->Func; \
|
||||
#if defined(USE_GDA)
|
||||
#define HOST_DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<GDAHostContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_RO)
|
||||
#define HOST_DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<ROHostContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_IPC)
|
||||
#define HOST_DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<IPCHostContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_GDA)
|
||||
#define HOST_DISPATCH_RET(Func) \
|
||||
auto ret_val = static_cast<GDAHostContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Host static dispatch method call with a return type of pointer.
|
||||
*/
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#define HOST_DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<GDAHostContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_RO)
|
||||
#define HOST_DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<ROHostContext *>(this)->Func; \
|
||||
@@ -153,11 +158,6 @@ enum class BackendType { RO_BACKEND, IPC_BACKEND, GDA_BACKEND };
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<IPCHostContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#elif defined(USE_GDA)
|
||||
#define HOST_DISPATCH_RET_PTR(Func) \
|
||||
void *ret_val{nullptr}; \
|
||||
ret_val = static_cast<GDAHostContext *>(this)->Func; \
|
||||
return ret_val;
|
||||
#endif
|
||||
|
||||
} // namespace rocshmem
|
||||
|
||||
@@ -74,6 +74,89 @@ struct ExtInfo {
|
||||
}
|
||||
}
|
||||
|
||||
void Bootstrap::groupAllGather(void* allData, int size, const std::vector<int>& ranks) {
|
||||
char* data = static_cast<char*>(allData);
|
||||
int rank = this->getRank();
|
||||
int nRanks = ranks.size();
|
||||
int rank_pos = -1;
|
||||
|
||||
// Confirm that rank is in the vectors of ranks
|
||||
for (int i = 0; i < ranks.size(); i++) {
|
||||
if (rank == ranks[i]) {
|
||||
rank_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rank_pos == -1) {
|
||||
printf("Bootstrap::groupAllGather: called with process that is not in list of ranks. Aborting\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
DPRINTF("groupAllGather: rank %d nranks %d size %d\n", rank, nRanks, size);
|
||||
|
||||
int sendto = (rank_pos + 1 + nRanks) % nRanks;
|
||||
int recvfrom = (rank_pos - 1 + nRanks) % nRanks;
|
||||
for (int i = 0; i < nRanks - 1; i++) {
|
||||
size_t rSlice = (rank_pos - i - 1 + nRanks) % nRanks;
|
||||
size_t sSlice = (rank_pos - i + nRanks) % nRanks;
|
||||
|
||||
char *tmpsend = data + sSlice * size;
|
||||
char *tmprecv = data + rSlice * size;
|
||||
this->send(tmpsend, size, ranks[sendto], i);
|
||||
this->recv(tmprecv, size, ranks[recvfrom], i);
|
||||
}
|
||||
|
||||
DPRINTF("groupAllGather: rank %d nranks %d size %d - DONE\n", rank, nRanks, size);
|
||||
}
|
||||
|
||||
void Bootstrap::groupAlltoall(void* allData, int size, const std::vector<int>& ranks) {
|
||||
char* data = static_cast<char*>(allData);
|
||||
int num_pes = ranks.size();
|
||||
int rank = this->getRank();
|
||||
int rank_pos = -1;
|
||||
|
||||
// Confirm that rank is in the vectors of ranks
|
||||
for (int i = 0; i < ranks.size(); i++) {
|
||||
if (rank == ranks[i]) {
|
||||
rank_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rank_pos == -1) {
|
||||
printf("Bootstrap::groupAlltoall: called with process that is not in list of ranks. Aborting\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
DPRINTF("groupAlltoall: rank %d nranks %d size %d\n", rank, num_pes, size);
|
||||
|
||||
// Since this is an in-place algorithm, allocate temporary receive buffer
|
||||
char *recv_buf = new char[size * num_pes];
|
||||
std::memset(recv_buf, 0, num_pes * size);
|
||||
|
||||
// Perform pairwise exchange - local copy is ommitted
|
||||
for (int step = 1; step < num_pes; step++) {
|
||||
int sendto = (rank_pos + step) % num_pes;
|
||||
int recvfrom = (rank_pos + num_pes - step) % num_pes;
|
||||
|
||||
char *tmpsend = (char*)data + (ptrdiff_t)sendto * size;
|
||||
char *tmprecv = (char*)recv_buf + (ptrdiff_t)recvfrom * size;
|
||||
|
||||
this->send(tmpsend, size, ranks[sendto], step /* used as tag */);
|
||||
this->recv(tmprecv, size, ranks[recvfrom], step);
|
||||
}
|
||||
|
||||
//Since this is an in_place all-to-all, copy data back into the user buffer
|
||||
for (int step = 0; step < num_pes; step++) {
|
||||
if (step == rank_pos) continue;
|
||||
std::memcpy(&data[step*size], &recv_buf[step*size], size);
|
||||
}
|
||||
|
||||
DPRINTF("groupAlltoall: rank %d nranks %d size %d DONE \n", rank, num_pes, size);
|
||||
delete[] recv_buf;
|
||||
}
|
||||
|
||||
void Bootstrap::send(const std::vector<char>& data, int peer, int tag) {
|
||||
size_t size = data.size();
|
||||
send((void*)&size, sizeof(size_t), peer, tag);
|
||||
@@ -107,6 +190,7 @@ class TcpBootstrap::Impl {
|
||||
int getRank();
|
||||
int getNranks();
|
||||
int getNranksPerNode();
|
||||
std::vector<int> getLocalRanks();
|
||||
void allGather(void* allData, int size);
|
||||
void send(void* data, int size, int peer, int tag);
|
||||
void recv(void* data, int size, int peer, int tag);
|
||||
@@ -131,6 +215,7 @@ class TcpBootstrap::Impl {
|
||||
SocketAddress netIfAddr_;
|
||||
std::unordered_map<std::pair<int, int>, std::shared_ptr<Socket>, PairHash> peerSendSockets_;
|
||||
std::unordered_map<std::pair<int, int>, std::shared_ptr<Socket>, PairHash> peerRecvSockets_;
|
||||
std::vector<int> localRanks_;
|
||||
|
||||
void netSend(Socket* sock, const void* data, int size);
|
||||
void netRecv(Socket* sock, void* data, int size);
|
||||
@@ -181,6 +266,8 @@ int TcpBootstrap::Impl::getRank() { return rank_; }
|
||||
|
||||
int TcpBootstrap::Impl::getNranks() { return nRanks_; }
|
||||
|
||||
std::vector<int> TcpBootstrap::Impl::getLocalRanks() { return localRanks_; }
|
||||
|
||||
void TcpBootstrap::Impl::initialize(const rocshmem_uniqueid_t& uniqueId, int64_t timeoutSec) {
|
||||
if (!netInitialized) {
|
||||
netInit("", "", netIfAddr_);
|
||||
@@ -467,12 +554,14 @@ int TcpBootstrap::Impl::getNranksPerNode() {
|
||||
if (useIpv4) {
|
||||
if (peerCommAddresses_[i].sin.sin_addr.s_addr ==
|
||||
peerCommAddresses_[rank_].sin.sin_addr.s_addr) {
|
||||
localRanks_.push_back(i);
|
||||
nRanksPerNode++;
|
||||
}
|
||||
} else {
|
||||
if (std::memcmp(&(peerCommAddresses_[i].sin6.sin6_addr),
|
||||
&(peerCommAddresses_[rank_].sin6.sin6_addr),
|
||||
sizeof(in6_addr)) == 0) {
|
||||
localRanks_.push_back(i);
|
||||
nRanksPerNode++;
|
||||
}
|
||||
}
|
||||
@@ -586,6 +675,8 @@ void TcpBootstrap::Impl::close() {
|
||||
|
||||
int TcpBootstrap::getNranksPerNode() { return pimpl_->getNranksPerNode(); }
|
||||
|
||||
std::vector<int> TcpBootstrap::getLocalRanks() { return pimpl_->getLocalRanks(); }
|
||||
|
||||
void TcpBootstrap::send(void* data, int size, int peer, int tag) {
|
||||
pimpl_->send(data, size, peer, tag);
|
||||
}
|
||||
|
||||
@@ -49,12 +49,15 @@ class Bootstrap {
|
||||
virtual int getRank() = 0;
|
||||
virtual int getNranks() = 0;
|
||||
virtual int getNranksPerNode() = 0;
|
||||
virtual std::vector<int> getLocalRanks() = 0;
|
||||
virtual void send(void* data, int size, int peer, int tag) = 0;
|
||||
virtual void recv(void* data, int size, int peer, int tag) = 0;
|
||||
virtual void allGather(void* allData, int size) = 0;
|
||||
virtual void barrier() = 0;
|
||||
|
||||
void groupBarrier(const std::vector<int>& ranks);
|
||||
void groupAllGather(void* allData, int size, const std::vector<int>& ranks);
|
||||
void groupAlltoall(void* allData, int size, const std::vector<int>& ranks);
|
||||
void send(const std::vector<char>& data, int peer, int tag);
|
||||
void recv(std::vector<char>& data, int peer, int tag);
|
||||
};
|
||||
@@ -119,6 +122,9 @@ class TcpBootstrap : public Bootstrap {
|
||||
/// @param tag The tag to receive the data with.
|
||||
void recv(void* data, int size, int peer, int tag) override;
|
||||
|
||||
/// Provide list of ranks that are local to the calling process
|
||||
std::vector<int> getLocalRanks() override;
|
||||
|
||||
/// Gather data from all processes.
|
||||
///
|
||||
/// When called by rank `r`, this sends data from `allData[r * size]` to `allData[(r + 1) * size - 1]` to all other
|
||||
|
||||
@@ -28,15 +28,15 @@
|
||||
#include "context.hpp"
|
||||
#include "context_tmpl_device.hpp"
|
||||
#include "context_tmpl_host.hpp"
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#include "gda/context_gda_device.hpp"
|
||||
#include "gda/context_gda_host.hpp"
|
||||
#elif defined(USE_RO)
|
||||
#include "reverse_offload/context_ro_device.hpp"
|
||||
#include "reverse_offload/context_ro_host.hpp"
|
||||
#elif defined(USE_IPC)
|
||||
#include "ipc/context_ipc_device.hpp"
|
||||
#include "ipc/context_ipc_host.hpp"
|
||||
#elif defined(USE_GDA)
|
||||
#include "gda/context_gda_device.hpp"
|
||||
#include "gda/context_gda_host.hpp"
|
||||
#else
|
||||
#error "Select one backend among USE_RO, USE_IPC, USE_GDA"
|
||||
#endif
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
|
||||
#include "rocshmem/rocshmem_config.h" // NOLINT(build/include_subdir)
|
||||
#include "backend_type.hpp"
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#include "gda/context_gda_device.hpp"
|
||||
#elif defined(USE_RO)
|
||||
#include "reverse_offload/context_ro_device.hpp"
|
||||
#elif defined(USE_IPC)
|
||||
#include "ipc/context_ipc_device.hpp"
|
||||
#elif defined(USE_GDA)
|
||||
#include "gda/context_gda_device.hpp"
|
||||
#endif
|
||||
|
||||
namespace rocshmem {
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
|
||||
#include "rocshmem/rocshmem_config.h" // NOLINT(build/include_subdir)
|
||||
#include "backend_type.hpp"
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#include "gda/context_gda_host.hpp"
|
||||
#elif defined(USE_RO)
|
||||
#include "reverse_offload/context_ro_host.hpp"
|
||||
#elif defined(USE_IPC)
|
||||
#include "ipc/context_ipc_host.hpp"
|
||||
#elif defined(USE_GDA)
|
||||
#include "gda/context_gda_host.hpp"
|
||||
#endif
|
||||
|
||||
namespace rocshmem {
|
||||
|
||||
@@ -115,6 +115,8 @@ void GDABackend::init() {
|
||||
setup_team_world();
|
||||
rte_barrier();
|
||||
|
||||
setup_ipc();
|
||||
|
||||
setup_ibv();
|
||||
setup_heap_memory_rkey();
|
||||
setup_gpu_qps();
|
||||
@@ -133,6 +135,8 @@ GDABackend::~GDABackend() {
|
||||
|
||||
cleanup_wrk_sync_buffer();
|
||||
|
||||
cleanup_ipc();
|
||||
|
||||
cleanup_gpu_qps();
|
||||
cleanup_heap_memory_rkey();
|
||||
cleanup_ibv();
|
||||
@@ -166,6 +170,18 @@ void GDABackend::read_env() {
|
||||
}
|
||||
}
|
||||
|
||||
void GDABackend::setup_ipc() {
|
||||
const auto &heap_bases{heap.get_heap_bases()};
|
||||
|
||||
if (MPI_COMM_NULL != backend_comm)
|
||||
ipcImpl.ipcHostInit(my_pe, heap_bases, backend_comm);
|
||||
else
|
||||
ipcImpl.ipcHostInit(my_pe, heap_bases, backend_bootstr);
|
||||
}
|
||||
|
||||
void GDABackend::cleanup_ipc() {
|
||||
ipcImpl.ipcHostStop();
|
||||
}
|
||||
|
||||
void GDABackend::setup_host_ctx() {
|
||||
default_host_ctx = std::make_unique<GDAHostContext>(this, 0);
|
||||
@@ -258,41 +274,12 @@ void GDABackend::team_destroy(rocshmem_team_t team) {
|
||||
void GDABackend::Alltoall_char_inplace (char *inoutbuf, size_t num_bytes, rocshmem_team_t team) {
|
||||
// Implement an Alltoall outside of MPI assuming in_place communication
|
||||
GDATeam *team_obj = reinterpret_cast<GDATeam *>(team);
|
||||
int num_pes = team_obj->num_pes;
|
||||
int my_pe = team_obj->my_pe;
|
||||
int *pes_in_world = new int[num_pes];
|
||||
std::vector<int> pes_in_world;
|
||||
|
||||
int my_pe_in_world = team_obj->my_pe_in_world;
|
||||
for (int i = 0; i < num_pes; i++) {
|
||||
pes_in_world[i] = team_obj->get_pe_in_world(i);
|
||||
pes_in_world.push_back(team_obj->get_pe_in_world(i));
|
||||
}
|
||||
|
||||
// Since this is an in-place algorithm, allocate the temporary receive buffer first
|
||||
char *recv_buf = new char[num_bytes * num_pes];
|
||||
std::memset(recv_buf, 0, num_pes * num_bytes);
|
||||
|
||||
// Perform pairwise exchange - local copy is ommitted
|
||||
for (int step = 1; step < num_pes; step++) {
|
||||
int sendto_team = (my_pe + step) % num_pes;
|
||||
int recvfrom_team = (my_pe + num_pes - step) % num_pes;
|
||||
|
||||
char *tmpsend = (char*)inoutbuf + (ptrdiff_t)sendto_team * num_bytes;
|
||||
char *tmprecv = (char*)recv_buf + (ptrdiff_t)recvfrom_team * num_bytes;
|
||||
|
||||
// similarly to the allGather in the bootstrap code, we do send first
|
||||
// followed by the receive.
|
||||
// There is a chance for deadlock in my opinion for large messages.
|
||||
backend_bootstr->send(tmpsend, num_bytes, pes_in_world[sendto_team], step /* used as tag */);
|
||||
backend_bootstr->recv(tmprecv, num_bytes, pes_in_world[recvfrom_team], step);
|
||||
}
|
||||
//Since this is an in_place all-to-all, copy data back into the user buffer
|
||||
for (int step = 0; step < num_pes; step++) {
|
||||
if (step == my_pe) continue;
|
||||
std::memcpy(&inoutbuf[step*num_bytes], &recv_buf[step*num_bytes], num_bytes);
|
||||
}
|
||||
|
||||
delete[] recv_buf;
|
||||
delete[] pes_in_world;
|
||||
backend_bootstr->groupAlltoall(inoutbuf, num_bytes, pes_in_world);
|
||||
}
|
||||
|
||||
//TODO: factorize somewhere else, maybe backend_bc?
|
||||
@@ -305,18 +292,16 @@ void GDABackend::Allreduce_char_BAND (char* inbuf, char *outbuf, size_t num_byte
|
||||
|
||||
GDATeam *team_obj = reinterpret_cast<GDATeam *>(team);
|
||||
int num_pes = team_obj->num_pes;
|
||||
int my_pe = team_obj->my_pe;
|
||||
std::vector<int> pes_in_world;
|
||||
|
||||
char *tmp_buffer = new char[num_pes * num_bytes];
|
||||
std::memset(tmp_buffer, 0, num_pes * num_bytes);
|
||||
std::memcpy (&tmp_buffer[my_pe * num_bytes], inbuf, num_bytes);
|
||||
std::memcpy(&tmp_buffer[my_pe * num_bytes], inbuf, num_bytes);
|
||||
|
||||
if (num_pes == backend_bootstr->getNranks() ) {
|
||||
backend_bootstr->allGather(tmp_buffer, num_bytes);
|
||||
} else {
|
||||
printf("GDABackend::create_new_team: non-mpi version only supports parent_teams that contain all processes. Aborting.\n");
|
||||
abort();
|
||||
for (int i = 0; i < num_pes; i++) {
|
||||
pes_in_world.push_back(team_obj->get_pe_in_world(i));
|
||||
}
|
||||
backend_bootstr->groupAllGather(tmp_buffer, num_bytes, pes_in_world);
|
||||
|
||||
for (int i = 0; i < num_bytes; i++) {
|
||||
outbuf[i] = tmp_buffer[i];
|
||||
|
||||
@@ -301,6 +301,14 @@ class GDABackend : public Backend {
|
||||
void setup_host_ctx();
|
||||
void setup_default_ctx();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allocation and initialization of resources required to
|
||||
* support IPC handover.
|
||||
*/
|
||||
void setup_ipc();
|
||||
void cleanup_ipc();
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize barrier operation addresses on
|
||||
* symmetric heap.
|
||||
|
||||
@@ -49,6 +49,12 @@ __host__ GDAContext::GDAContext(Backend *b, unsigned int ctx_id)
|
||||
CHECK_HIP(hipMemcpy(&qps[i], &backend->gpu_qps[offset], sizeof(QueuePair), hipMemcpyDefault));
|
||||
qps[i].base_heap = base_heap;
|
||||
}
|
||||
|
||||
ipcImpl_.ipc_bases = backend->ipcImpl.ipc_bases;
|
||||
ipcImpl_.shm_size = backend->ipcImpl.shm_size;
|
||||
ipcImpl_.shm_rank = backend->ipcImpl.shm_rank;
|
||||
ipcImpl_.pes_with_ipc_avail = backend->ipcImpl.pes_with_ipc_avail;
|
||||
|
||||
ctx_id_ = ctx_id;
|
||||
}
|
||||
|
||||
@@ -63,7 +69,13 @@ __device__ void GDAContext::ctx_destroy(){
|
||||
}
|
||||
|
||||
__device__ void GDAContext::putmem(void *dest, const void *source, size_t nelems,
|
||||
int pe) {
|
||||
int pe) {
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dest) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy(ipcImpl_.ipc_bases[local_pe] + L_offset, const_cast<void *>(source), nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = reinterpret_cast<char*>(dest) - base_heap[my_pe];
|
||||
bool need_turn {true};
|
||||
uint64_t turns = __ballot(need_turn);
|
||||
@@ -80,8 +92,14 @@ __device__ void GDAContext::putmem(void *dest, const void *source, size_t nelems
|
||||
}
|
||||
|
||||
__device__ void GDAContext::getmem(void *dest, const void *source, size_t nelems,
|
||||
int pe) {
|
||||
int pe) {
|
||||
const char *src_typed = reinterpret_cast<const char *>(source);
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy(dest, ipcImpl_.ipc_bases[local_pe] + L_offset, nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - base_heap[my_pe];
|
||||
bool need_turn {true};
|
||||
uint64_t turns = __ballot(need_turn);
|
||||
@@ -98,7 +116,13 @@ __device__ void GDAContext::getmem(void *dest, const void *source, size_t nelems
|
||||
}
|
||||
|
||||
__device__ void GDAContext::putmem_nbi(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dest) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy(ipcImpl_.ipc_bases[local_pe] + L_offset, const_cast<void *>(source), nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = reinterpret_cast<char*>(dest) - base_heap[my_pe];
|
||||
bool need_turn {true};
|
||||
uint64_t turns = __ballot(need_turn);
|
||||
@@ -114,8 +138,14 @@ __device__ void GDAContext::putmem_nbi(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::getmem_nbi(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
const char *src_typed = reinterpret_cast<const char *>(source);
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy(dest, ipcImpl_.ipc_bases[local_pe] + L_offset, nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - base_heap[my_pe];
|
||||
bool need_turn {true};
|
||||
uint64_t turns = __ballot(need_turn);
|
||||
@@ -148,11 +178,24 @@ __device__ void GDAContext::quiet() {
|
||||
}
|
||||
|
||||
__device__ void *GDAContext::shmem_ptr(const void *dest, int pe) {
|
||||
return nullptr;
|
||||
void *ret = nullptr;
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
void *dst = const_cast<void *>(dest);
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dst) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ret = ipcImpl_.ipc_bases[local_pe] + L_offset;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__device__ void GDAContext::putmem_wg(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dest) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wg(ipcImpl_.ipc_bases[local_pe] + L_offset, const_cast<void *>(source), nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = reinterpret_cast<char*>(dest) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_block()) {
|
||||
qps[pe].put_nbi(base_heap[pe] + L_offset, source, nelems, pe);
|
||||
@@ -161,8 +204,14 @@ __device__ void GDAContext::putmem_wg(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::getmem_wg(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
const char *src_typed = reinterpret_cast<const char *>(source);
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wg(dest, ipcImpl_.ipc_bases[local_pe] + L_offset, nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_block()) {
|
||||
qps[pe].get_nbi(dest, base_heap[pe] + L_offset, nelems, pe);
|
||||
@@ -171,7 +220,13 @@ __device__ void GDAContext::getmem_wg(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::putmem_nbi_wg(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dest) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wg(ipcImpl_.ipc_bases[local_pe] + L_offset, const_cast<void *>(source), nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = reinterpret_cast<char*>(dest) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_block()) {
|
||||
qps[pe].put_nbi(base_heap[pe] + L_offset, source, nelems, pe);
|
||||
@@ -179,8 +234,14 @@ __device__ void GDAContext::putmem_nbi_wg(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::getmem_nbi_wg(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
const char *src_typed = reinterpret_cast<const char *>(source);
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wg(dest, ipcImpl_.ipc_bases[local_pe] + L_offset, nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_block()) {
|
||||
qps[pe].get_nbi(dest, base_heap[pe] + L_offset, nelems, pe);
|
||||
@@ -188,7 +249,13 @@ __device__ void GDAContext::getmem_nbi_wg(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::putmem_wave(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dest) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wave(ipcImpl_.ipc_bases[local_pe] + L_offset, const_cast<void *>(source), nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = reinterpret_cast<char*>(dest) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_wave()) {
|
||||
qps[pe].put_nbi(base_heap[pe] + L_offset, source, nelems, pe);
|
||||
@@ -197,8 +264,14 @@ __device__ void GDAContext::putmem_wave(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::getmem_wave(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
const char *src_typed = reinterpret_cast<const char *>(source);
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wave(dest, ipcImpl_.ipc_bases[local_pe] + L_offset, nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_wave()) {
|
||||
qps[pe].get_nbi(dest, base_heap[pe] + L_offset, nelems, pe);
|
||||
@@ -207,7 +280,13 @@ __device__ void GDAContext::getmem_wave(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::putmem_nbi_wave(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dest) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wave(ipcImpl_.ipc_bases[local_pe] + L_offset, const_cast<void *>(source), nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = reinterpret_cast<char*>(dest) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_wave()) {
|
||||
qps[pe].put_nbi(base_heap[pe] + L_offset, source, nelems, pe);
|
||||
@@ -215,8 +294,14 @@ __device__ void GDAContext::putmem_nbi_wave(void *dest, const void *source,
|
||||
}
|
||||
|
||||
__device__ void GDAContext::getmem_nbi_wave(void *dest, const void *source,
|
||||
size_t nelems, int pe) {
|
||||
size_t nelems, int pe) {
|
||||
const char *src_typed = reinterpret_cast<const char *>(source);
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ipcImpl_.ipcCopy_wave(dest, ipcImpl_.ipc_bases[local_pe] + L_offset, nelems);
|
||||
return;
|
||||
}
|
||||
uint64_t L_offset = const_cast<char *>(src_typed) - base_heap[my_pe];
|
||||
if (is_thread_zero_in_wave()) {
|
||||
qps[pe].get_nbi(dest, base_heap[pe] + L_offset, nelems, pe);
|
||||
|
||||
@@ -42,9 +42,29 @@ __host__ GDAHostContext::GDAHostContext(Backend *backend,
|
||||
host_interface = b->host_interface;
|
||||
|
||||
context_window_info = host_interface->acquire_window_context();
|
||||
|
||||
int *pes_with_ipc_avail = new int[backend->ipcImpl.shm_size];
|
||||
char** ipc_bases = new char*[b->ipcImpl.shm_size];
|
||||
if (backend->ipcImpl.pes_with_ipc_avail != nullptr) {
|
||||
CHECK_HIP(hipMemcpy(pes_with_ipc_avail,
|
||||
backend->ipcImpl.pes_with_ipc_avail,
|
||||
backend->ipcImpl.shm_size * sizeof(int),
|
||||
hipMemcpyDeviceToHost));
|
||||
CHECK_HIP(hipMemcpy(ipc_bases,
|
||||
backend->ipcImpl.ipc_bases,
|
||||
backend->ipcImpl.shm_size * sizeof(char *),
|
||||
hipMemcpyDeviceToHost));
|
||||
}
|
||||
ipcImpl_.pes_with_ipc_avail = pes_with_ipc_avail;
|
||||
ipcImpl_.ipc_bases = ipc_bases;
|
||||
ipcImpl_.shm_size = backend->ipcImpl.shm_size;
|
||||
ipcImpl_.shm_rank = backend->ipcImpl.shm_rank;
|
||||
}
|
||||
|
||||
__host__ GDAHostContext::~GDAHostContext() {
|
||||
delete[] ipcImpl_.pes_with_ipc_avail;
|
||||
delete[] ipcImpl_.ipc_bases;
|
||||
|
||||
host_interface->release_window_context(context_window_info);
|
||||
}
|
||||
|
||||
@@ -78,8 +98,12 @@ __host__ void GDAHostContext::quiet() {
|
||||
|
||||
__host__ void *GDAHostContext::shmem_ptr(const void *dest, int pe) {
|
||||
void *ret = nullptr;
|
||||
//not implemented, returning nullptr is spec-valid
|
||||
//TODO: copy ipc handover from RO when IPC+GDA is implemented
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
void *dst = const_cast<void *>(dest);
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dst) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank];
|
||||
ret = ipcImpl_.ipc_bases[local_pe] + L_offset;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,12 @@ namespace rocshmem {
|
||||
*****************************************************************************/
|
||||
template <typename T>
|
||||
__device__ void GDAContext::p(T *dest, T value, int pe) {
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
long L_offset{reinterpret_cast<char *>(dest) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank]};
|
||||
ipcImpl_.ipcCopy(ipcImpl_.ipc_bases[local_pe] + L_offset, reinterpret_cast<void *>(&value), sizeof(T));
|
||||
return;
|
||||
}
|
||||
putmem_nbi(dest, &value, sizeof(T), pe);
|
||||
}
|
||||
|
||||
@@ -58,6 +64,13 @@ __device__ void GDAContext::put_nbi(T *dest, const T *source, size_t nelems, int
|
||||
template <typename T>
|
||||
__device__ T GDAContext::g(const T *source, int pe) {
|
||||
T ret;
|
||||
int local_pe{-1};
|
||||
if (ipcImpl_.isIpcAvailable(my_pe, pe, &local_pe)) {
|
||||
const char *src_typed{reinterpret_cast<const char *>(source)};
|
||||
long L_offset{const_cast<char *>(src_typed) - ipcImpl_.ipc_bases[ipcImpl_.shm_rank]};
|
||||
ipcImpl_.ipcCopy(&ret, ipcImpl_.ipc_bases[local_pe] + L_offset, sizeof(T));
|
||||
return ret;
|
||||
}
|
||||
printf("rocshmem::gda:g not implemented\n");
|
||||
abort();
|
||||
//TODO the following is incorrect because ret is not ibv registered memory
|
||||
|
||||
@@ -90,9 +90,8 @@ __host__ void IPCHostContext::quiet() {
|
||||
__host__ void *IPCHostContext::shmem_ptr(const void *dest, int pe) {
|
||||
void *ret = nullptr;
|
||||
void *dst = const_cast<void *>(dest);
|
||||
uint64_t L_offset =
|
||||
reinterpret_cast<char *>(dst) - ipcImpl_.ipc_bases[my_pe];
|
||||
ret = ipcImpl_.ipc_bases[pe] + L_offset;
|
||||
uint64_t L_offset = reinterpret_cast<char *>(dst) - ipcImpl_.ipc_bases[my_pe];
|
||||
ret = ipcImpl_.ipc_bases[pe] + L_offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,25 +109,29 @@ __host__ void IpcOnImpl::ipcHostInit(int my_pe, const HEAP_BASES_T &heap_bases,
|
||||
*/
|
||||
free(vec_ipc_handle);
|
||||
|
||||
if (0 == rocshmem_env_.get_ro_disable_ipc()) {
|
||||
if (0 == rocshmem_env_.get_disable_ipc()) {
|
||||
int thread_comm_rank {-1};
|
||||
|
||||
CHECK_HIP(hipMalloc(reinterpret_cast<void**>(&pes_with_ipc_avail), shm_size * sizeof(int)));
|
||||
|
||||
MPI_Comm_rank(thread_comm, &thread_comm_rank);
|
||||
MPI_Allgather(&thread_comm_rank, 1, MPI_INT, pes_with_ipc_avail, 1, MPI_INT, shmcomm);
|
||||
MPI_Group thread_grp, shm_grp;
|
||||
MPI_Comm_group(thread_comm, &thread_grp);
|
||||
MPI_Comm_group(shmcomm, &shm_grp);
|
||||
int *seqranks = new int[shm_size];
|
||||
for(int i = 0; i < shm_size; i++)
|
||||
seqranks[i] = i;
|
||||
MPI_Group_translate_ranks(shm_grp, shm_size, seqranks, thread_grp, pes_with_ipc_avail);
|
||||
delete [] seqranks;
|
||||
MPI_Group_free(&shm_grp);
|
||||
MPI_Group_free(&thread_grp);
|
||||
}
|
||||
}
|
||||
|
||||
__host__ void IpcOnImpl::ipcHostInit(int my_pe, const HEAP_BASES_T &heap_bases,
|
||||
TcpBootstrap *bootstr) {
|
||||
/*
|
||||
* The non-MPI based version only works for ipc conduit for now,
|
||||
* i.e. total number of ranks and number of local ranks have to match.
|
||||
*/
|
||||
shm_size = bootstr->getNranksPerNode();
|
||||
assert (shm_size == bootstr->getNranks());
|
||||
shm_rank = my_pe;
|
||||
auto shm_ranks = bootstr->getLocalRanks();
|
||||
shm_rank = std::find(shm_ranks.begin(), shm_ranks.end(), my_pe) - shm_ranks.begin();
|
||||
|
||||
/*
|
||||
* Allocate a host-side c-array to hold the IPC handles.
|
||||
@@ -148,7 +152,7 @@ __host__ void IpcOnImpl::ipcHostInit(int my_pe, const HEAP_BASES_T &heap_bases,
|
||||
* Do an all-to-all exchange with each local processing element to
|
||||
* share the symmetric heap IPC handles.
|
||||
*/
|
||||
bootstr->allGather(vec_ipc_handle, sizeof(hipIpcMemHandle_t));
|
||||
bootstr->groupAllGather(vec_ipc_handle, sizeof(hipIpcMemHandle_t), shm_ranks);
|
||||
|
||||
/*
|
||||
* Allocate device-side array to hold the IPC symmetric heap base
|
||||
@@ -182,6 +186,13 @@ __host__ void IpcOnImpl::ipcHostInit(int my_pe, const HEAP_BASES_T &heap_bases,
|
||||
* addresses.
|
||||
*/
|
||||
free(vec_ipc_handle);
|
||||
|
||||
if (0 == rocshmem_env_.get_disable_ipc()) {
|
||||
int thread_comm_rank {-1};
|
||||
|
||||
CHECK_HIP(hipMalloc(reinterpret_cast<void**>(&pes_with_ipc_avail), shm_size * sizeof(int)));
|
||||
std::copy(shm_ranks.begin(), shm_ranks.end(), pes_with_ipc_avail);
|
||||
}
|
||||
}
|
||||
|
||||
__host__ void IpcOnImpl::ipcHostStop() {
|
||||
|
||||
@@ -44,17 +44,16 @@ __host__ ROHostContext::ROHostContext(Backend *backend, long options)
|
||||
|
||||
int *pes_with_ipc_avail = new int[backend->ipcImpl.shm_size];
|
||||
char** ipc_bases = new char*[b->ipcImpl.shm_size];
|
||||
|
||||
CHECK_HIP(hipMemcpy(pes_with_ipc_avail,
|
||||
if (backend->ipcImpl.pes_with_ipc_avail != nullptr) {
|
||||
CHECK_HIP(hipMemcpy(pes_with_ipc_avail,
|
||||
backend->ipcImpl.pes_with_ipc_avail,
|
||||
backend->ipcImpl.shm_size * sizeof(int),
|
||||
hipMemcpyDeviceToHost));
|
||||
|
||||
CHECK_HIP(hipMemcpy(ipc_bases,
|
||||
CHECK_HIP(hipMemcpy(ipc_bases,
|
||||
backend->ipcImpl.ipc_bases,
|
||||
backend->ipcImpl.shm_size * sizeof(char *),
|
||||
hipMemcpyDeviceToHost));
|
||||
|
||||
}
|
||||
ipcImpl_.pes_with_ipc_avail = pes_with_ipc_avail;
|
||||
ipcImpl_.ipc_bases = ipc_bases;
|
||||
ipcImpl_.shm_size = backend->ipcImpl.shm_size;
|
||||
@@ -62,9 +61,9 @@ __host__ ROHostContext::ROHostContext(Backend *backend, long options)
|
||||
}
|
||||
|
||||
__host__ ROHostContext::~ROHostContext() {
|
||||
// host_interface->release_window_context(context_window_info);
|
||||
delete[] ipcImpl_.pes_with_ipc_avail;
|
||||
delete[] ipcImpl_.ipc_bases;
|
||||
// host_interface->release_window_context(context_window_info);
|
||||
}
|
||||
|
||||
__host__ void ROHostContext::putmem_nbi(void *dest, const void *source,
|
||||
|
||||
@@ -35,15 +35,15 @@
|
||||
|
||||
#include "backend_bc.hpp"
|
||||
#include "context_incl.hpp"
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#include "gda/backend_gda.hpp"
|
||||
#include "gda/context_gda_tmpl_host.hpp"
|
||||
#elif defined(USE_RO)
|
||||
#include "reverse_offload/backend_ro.hpp"
|
||||
#include "reverse_offload/context_ro_tmpl_host.hpp"
|
||||
#elif defined(USE_IPC)
|
||||
#include "ipc/backend_ipc.hpp"
|
||||
#include "ipc/context_ipc_tmpl_host.hpp"
|
||||
#elif defined(USE_GDA)
|
||||
#include "gda/backend_gda.hpp"
|
||||
#include "gda/context_gda_tmpl_host.hpp"
|
||||
#else
|
||||
#error "Select one backend among USE_RO, USE_IPC, USE_GDA"
|
||||
#endif
|
||||
@@ -94,15 +94,15 @@ rocshmem_ctx_t ROCSHMEM_HOST_CTX_DEFAULT;
|
||||
|
||||
mpi_instance = new MPIInstance(comm);
|
||||
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
CHECK_HIP(hipHostMalloc(&backend, sizeof(GDABackend)));
|
||||
backend = new (backend) GDABackend(comm);
|
||||
#elif defined(USE_RO)
|
||||
CHECK_HIP(hipHostMalloc(&backend, sizeof(ROBackend)));
|
||||
backend = new (backend) ROBackend(comm);
|
||||
#elif defined(USE_IPC)
|
||||
CHECK_HIP(hipHostMalloc(&backend, sizeof(IPCBackend)));
|
||||
backend = new (backend) IPCBackend(comm);
|
||||
#elif defined(USE_GDA)
|
||||
CHECK_HIP(hipHostMalloc(&backend, sizeof(GDABackend)));
|
||||
backend = new (backend) GDABackend(comm);
|
||||
#endif
|
||||
|
||||
if (!backend) {
|
||||
@@ -174,15 +174,15 @@ rocshmem_ctx_t ROCSHMEM_HOST_CTX_DEFAULT;
|
||||
|
||||
rocm_init();
|
||||
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
CHECK_HIP(hipHostMalloc(&backend, sizeof(GDABackend)));
|
||||
backend = new (backend) GDABackend(bootstrap);
|
||||
#elif defined(USE_RO)
|
||||
printf("RO Backend requires MPI library to be initialized, even when using uniqueId initializations!\n");
|
||||
abort();
|
||||
#elif defined(USE_IPC)
|
||||
CHECK_HIP(hipHostMalloc(&backend, sizeof(IPCBackend)));
|
||||
backend = new (backend) IPCBackend(bootstrap);
|
||||
#elif defined(USE_GDA)
|
||||
CHECK_HIP(hipHostMalloc(&backend, sizeof(GDABackend)));
|
||||
backend = new (backend) GDABackend(bootstrap);
|
||||
#endif
|
||||
|
||||
if (!backend) {
|
||||
|
||||
@@ -51,15 +51,15 @@
|
||||
#include "templates.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#if defined(USE_RO)
|
||||
#if defined(USE_GDA)
|
||||
#include "gda/context_gda_tmpl_device.hpp"
|
||||
#elif defined(USE_RO)
|
||||
#include "reverse_offload/context_ro_tmpl_device.hpp"
|
||||
#elif defined(USE_IPC)
|
||||
# if defined(ENABLE_IPC_BITCODE)
|
||||
# include "ipc/backend_ipc.hpp"
|
||||
# endif
|
||||
#include "ipc/context_ipc_tmpl_device.hpp"
|
||||
#elif defined(USE_GDA)
|
||||
#include "gda/context_gda_tmpl_device.hpp"
|
||||
#else
|
||||
#error "Select one backend among USE_RO, USE_IPC, USE_GDA"
|
||||
#endif
|
||||
|
||||
@@ -127,9 +127,14 @@ void rocm_memory_lock_to_fine_grain(void* ptr, size_t size, void** gpu_ptr,
|
||||
rocshmem_env_config::rocshmem_env_config() {
|
||||
char* env_value = NULL;
|
||||
|
||||
env_value = getenv("ROCSHMEM_DISABLE_IPC");
|
||||
if (NULL != env_value) {
|
||||
disable_ipc = atoi(env_value);
|
||||
}
|
||||
// For backward compatibility, synonymous with ROCSHMEM_DISABLE_IPC
|
||||
env_value = getenv("ROCSHMEM_RO_DISABLE_IPC");
|
||||
if (NULL != env_value) {
|
||||
ro_disable_ipc = atoi(env_value);
|
||||
disable_ipc = atoi(env_value);
|
||||
}
|
||||
|
||||
env_value = getenv("ROCSHMEM_RO_PROGRESS_DELAY");
|
||||
@@ -163,8 +168,8 @@ rocshmem_env_config::rocshmem_env_config() {
|
||||
}
|
||||
}
|
||||
|
||||
int rocshmem_env_config::get_ro_disable_ipc() {
|
||||
return ro_disable_ipc;
|
||||
int rocshmem_env_config::get_disable_ipc() {
|
||||
return disable_ipc;
|
||||
}
|
||||
|
||||
int rocshmem_env_config::get_ro_progress_delay() {
|
||||
|
||||
@@ -361,7 +361,7 @@ class rocshmem_env_config {
|
||||
public:
|
||||
rocshmem_env_config();
|
||||
|
||||
int get_ro_disable_ipc();
|
||||
int get_disable_ipc();
|
||||
int get_ro_progress_delay();
|
||||
int get_uniqueid_with_mpi();
|
||||
int get_bootstrap_timeout();
|
||||
@@ -370,7 +370,7 @@ public:
|
||||
std::string get_bootstrap_socket_ifname();
|
||||
|
||||
private:
|
||||
int ro_disable_ipc = 0;
|
||||
int disable_ipc = 0;
|
||||
int ro_progress_delay = 3;
|
||||
int bootstrap_timeout = 5;
|
||||
int uniqueid_with_mpi = 0;
|
||||
|
||||
Verwijs in nieuw issue
Block a user