Skip to content

Commit 7d5cf67

Browse files
committed
Optimize MPI transfers using the TrivialCopyTraits
1 parent 0fece6a commit 7d5cf67

File tree

3 files changed

+79
-5
lines changed

3 files changed

+79
-5
lines changed

HeterogeneousCore/MPICore/plugins/api.cc

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,4 +192,63 @@ void MPIChannel::receiveTrivialProduct_(int instance, edm::ObjectWithDict& produ
192192
MPI_Get_count(&status, MPI_BYTE, &size);
193193
assert(static_cast<int>(product.typeOf().size()) == size);
194194
MPI_Mrecv(product.address(), size, MPI_BYTE, &message, MPI_STATUS_IGNORE);
195-
}
195+
}
196+
197+
// transfer a wrapped object using its TrivialCopyTraits
198+
void MPIChannel::sendTrivialCopyProduct_(int instance, edm::WrapperBase const* wrapper) {
199+
int tag = EDM_MPI_SendTrivialCopyProduct | instance * EDM_MPI_MessageTagWidth_;
200+
201+
// if the wrapped type requires it, send the properties required toinitialise the remote copy
202+
if (wrapper->hasTrivialCopyProperties()) {
203+
edm::AnyBuffer buffer = wrapper->trivialCopyParameters();
204+
MPI_Send(buffer.data(), buffer.size_bytes(), MPI_BYTE, dest_, tag, comm_);
205+
}
206+
207+
// transfer the memory regions
208+
auto regions = wrapper->trivialCopyRegions();
209+
// TODO send the number of regions ?
210+
for (size_t i = 0; i < regions.size(); ++i) {
211+
assert(regions[i].data() != nullptr);
212+
MPI_Send(regions[i].data(), regions[i].size_bytes(), MPI_BYTE, dest_, tag, comm_);
213+
}
214+
}
215+
216+
// receive a wrapped object using its TrivialCopyTraits
217+
void MPIChannel::receiveTrivialCopyProduct_(int instance, edm::WrapperBase* wrapper) {
218+
int tag = EDM_MPI_SendTrivialCopyProduct | instance * EDM_MPI_MessageTagWidth_;
219+
220+
MPI_Message message;
221+
MPI_Status status;
222+
int size;
223+
224+
// mark the wrapped object as present
225+
wrapper->markAsPresent();
226+
227+
// if the wrapped type requires it, send the properties required toinitialise the remote copy
228+
if (wrapper->hasTrivialCopyProperties()) {
229+
edm::AnyBuffer buffer = wrapper->trivialCopyParameters();
230+
MPI_Mprobe(dest_, tag, comm_, &message, &status);
231+
// check that the message size matches the expected buffer size
232+
MPI_Get_count(&status, MPI_BYTE, &size);
233+
assert(static_cast<int>(buffer.size_bytes()) == size);
234+
// receive the properties
235+
MPI_Mrecv(buffer.data(), buffer.size_bytes(), MPI_BYTE, &message, &status);
236+
wrapper->trivialCopyInitialize(buffer);
237+
}
238+
239+
// receive the memory regions
240+
auto regions = wrapper->trivialCopyRegions();
241+
// TODO receive and validate the number of regions ?
242+
for (size_t i = 0; i < regions.size(); ++i) {
243+
assert(regions[i].data() != nullptr);
244+
MPI_Mprobe(dest_, tag, comm_, &message, &status);
245+
// check that the message size matches the expected region size
246+
MPI_Get_count(&status, MPI_BYTE, &size);
247+
assert(static_cast<int>(regions[i].size_bytes()) == size);
248+
// receive the data region
249+
MPI_Mrecv(regions[i].data(), regions[i].size_bytes(), MPI_BYTE, &message, &status);
250+
}
251+
252+
// finalize the clone after the trivialCopy, if the type requires it
253+
wrapper->trivialCopyFinalize();
254+
}

HeterogeneousCore/MPICore/plugins/api.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,13 @@ class MPIChannel {
9393
}
9494
}
9595

96-
// serialize a wrapped object using its ROOT dictionary, and transmit it
96+
// transfer a wrapped object using the TrivialCopyTraits or its ROOT dictionary
9797
void sendProduct(int instance, edm::TypeWithDict const& type, edm::WrapperBase const& wrapper) {
98-
sendSerializedProduct_(instance, type.getClass(), &wrapper);
98+
if (wrapper.hasTrivialCopyTraits()) {
99+
sendTrivialCopyProduct_(instance, &wrapper);
100+
} else {
101+
sendSerializedProduct_(instance, type.getClass(), &wrapper);
102+
}
99103
}
100104

101105
// signal that an expected product will not be transmitted
@@ -130,9 +134,13 @@ class MPIChannel {
130134
}
131135
}
132136

133-
// receive a wrapped object, and deserialize it using its ROOT dictionary
137+
// receive a wrapped object using the TrivialCopyTraits or its ROOT dictionary
134138
void receiveProduct(int instance, edm::TypeWithDict const& type, edm::WrapperBase& wrapper) {
135-
receiveSerializedProduct_(instance, type.getClass(), &wrapper);
139+
if (wrapper.hasTrivialCopyTraits()) {
140+
receiveTrivialCopyProduct_(instance, &wrapper);
141+
} else {
142+
receiveSerializedProduct_(instance, type.getClass(), &wrapper);
143+
}
136144
}
137145

138146
private:
@@ -194,6 +202,12 @@ class MPIChannel {
194202
// receive a binary blob, and deserialize an object of generic type using its ROOT dictionary
195203
void receiveSerializedProduct_(int instance, TClass const* type, void* product);
196204

205+
// transfer a wrapped object using its TrivialCopyTraits
206+
void sendTrivialCopyProduct_(int instance, edm::WrapperBase const* wrapper);
207+
208+
// receive a wrapped object using its TrivialCopyTraits
209+
void receiveTrivialCopyProduct_(int instance, edm::WrapperBase* wrapper);
210+
197211
// MPI intercommunicator
198212
MPI_Comm comm_ = MPI_COMM_NULL;
199213

HeterogeneousCore/MPICore/plugins/messages.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ enum EDM_MPI_MessageTag {
2323
EDM_MPI_ProcessEvent,
2424
EDM_MPI_SendSerializedProduct,
2525
EDM_MPI_SendTrivialProduct,
26+
EDM_MPI_SendTrivialCopyProduct,
2627
EDM_MPI_SkipProduct,
2728
EDM_MPI_SendComplete,
2829
EDM_MPI_MessageTagCount_

0 commit comments

Comments
 (0)