Skip to content

Commit b6848e3

Browse files
mkrzewicktf
authored andcommitted
DPL: Initial support for pmr containers (#1593)
1 parent 6bb09a2 commit b6848e3

File tree

6 files changed

+42
-14
lines changed

6 files changed

+42
-14
lines changed

DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,9 @@ auto adoptVector(size_t nelem, FairMQMessagePtr message)
224224

225225
//__________________________________________________________________________________________________
226226
/// Get the allocator associated to a transport factory
227-
inline static ChannelResource* getTransportAllocator(FairMQTransportFactory* factory)
227+
inline static FairMQMemoryResource* getTransportAllocator(FairMQTransportFactory* factory)
228228
{
229-
return factory->GetMemoryResource();
229+
return *factory;
230230
}
231231

232232
}; //namespace pmr

Framework/Core/include/Framework/DataAllocator.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,37 @@ class DataAllocator
370370
return adopt(getOutputByBind(std::move(ref)), obj);
371371
}
372372

373+
//make a stl (pmr) vector
374+
template <typename T, typename... Args>
375+
o2::vector<T> makeVector(const Output& spec, Args&&... args)
376+
{
377+
std::string channel = matchDataHeader(spec, mTimingInfo->timeslice);
378+
auto context = mContextRegistry->get<MessageContext>();
379+
o2::pmr::FairMQMemoryResource* targetResource = *context->proxy().getTransport(channel);
380+
return o2::vector<T>{targetResource, std::forward<Args>(args)...};
381+
}
382+
383+
//adopt container (if PMR is used with the appropriate memory resource in container it is ZERO-copy)
384+
template <typename ContainerT>
385+
void adoptContainer(const Output& spec, ContainerT& container) = delete; //only bind to moved-from containers
386+
template <typename ContainerT>
387+
void adoptContainer(const Output& spec, ContainerT&& container)
388+
{
389+
// Find a matching channel, extract the message for it form the container
390+
// and put it in the queue to be sent at the end of the processing
391+
std::string channel = matchDataHeader(spec, mTimingInfo->timeslice);
392+
393+
auto context = mContextRegistry->get<MessageContext>();
394+
FairMQMessagePtr payloadMessage = o2::pmr::getMessage(std::forward<ContainerT>(container), *context->proxy().getTransport(channel));
395+
396+
FairMQMessagePtr headerMessage = headerMessageFromOutput(spec, channel, //
397+
o2::header::gSerializationMethodNone, //
398+
payloadMessage->GetSize() //
399+
);
400+
401+
context->add<MessageContext::TrivialObject>(std::move(headerMessage), std::move(payloadMessage), channel);
402+
}
403+
373404
/// snapshot object and route to output specified by OutputRef
374405
/// Framework makes a (serialized) copy of object content.
375406
///

Framework/Core/include/Framework/FairMQDeviceProxy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class FairMQDeviceProxy
4040

4141
/// Looks like what we really need in the headers is just the transport.
4242
FairMQTransportFactory* getTransport();
43-
FairMQTransportFactory* getTransport(const std::string& channel, int index);
43+
FairMQTransportFactory* getTransport(const std::string& channel, int index = 0);
4444
std::unique_ptr<FairMQMessage> createMessage() const;
4545
std::unique_ptr<FairMQMessage> createMessage(const size_t size) const;
4646

Framework/Core/src/FairMQDeviceProxy.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ FairMQTransportFactory* FairMQDeviceProxy::getTransport()
2222
return mDevice->Transport();
2323
}
2424

25-
FairMQTransportFactory* FairMQDeviceProxy::getTransport(const std::string& channel, const int index = 0)
25+
FairMQTransportFactory* FairMQDeviceProxy::getTransport(const std::string& channel, const int index)
2626
{
2727
return mDevice->GetChannel(channel, index).Transport();
2828
}

Framework/Utils/include/DPLUtils/Utils.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,14 @@
1818

1919
#include "Framework/DataProcessorSpec.h"
2020
#include <functional>
21+
#include "MemoryResources/MemoryResources.h"
2122

2223
namespace o2f = o2::framework;
2324

2425
namespace o2
2526
{
2627
namespace workflows
2728
{
28-
//TODO: this is to make DPLmerger compile, but this code is (and always was) horribly broken - please remove.
29-
inline void freefn(void* data, void* /*hint*/) { delete static_cast<char*>(data); };
30-
3129
//
3230
o2f::Output getOutput(const o2f::OutputSpec outputSpec);
3331
std::shared_ptr<std::vector<o2f::Output>> getOutputList(const o2f::Outputs outputSpecs);
@@ -39,7 +37,7 @@ o2f::DataProcessorSpec defineBroadcaster(std::string devName, o2f::InputSpec usr
3937
size_t fixMsgSize);
4038
o2f::DataProcessorSpec defineBroadcaster(std::string devName, o2f::InputSpec usrInput, o2f::Outputs usrOutputs);
4139

42-
using OutputBuffer = std::vector<char>;
40+
using OutputBuffer = o2::vector<char>;
4341
// Merger implementations
4442
o2f::DataProcessorSpec defineMerger(std::string devName, o2f::Inputs usrInputs, o2f::OutputSpec usrOutput,
4543
std::function<void(OutputBuffer, const o2f::DataRef)> const mergerFunc);

Framework/Utils/src/DPLMerger.cxx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace workflows
2727
// This is a possible implementation of a DPL compliant and generic gatherer
2828
// Every other implementation should fall back to this one, after required translations.
2929
o2f::DataProcessorSpec defineMerger(std::string devName, o2f::Inputs usrInputs, o2f::OutputSpec usrOutput,
30-
std::function<void(OutputBuffer, const o2f::DataRef)> const mergerFunc)
30+
std::function<void(OutputBuffer&, const o2f::DataRef)> const mergerFunc)
3131
{
3232
return {devName, // Device name from user
3333
usrInputs, // User defined input as a vector of one InputSpec
@@ -36,18 +36,17 @@ o2f::DataProcessorSpec defineMerger(std::string devName, o2f::Inputs usrInputs,
3636
o2f::AlgorithmSpec{[usrOutput, mergerFunc](o2f::InitContext&) {
3737
// Creating shared ptrs to useful parameters
3838
auto outputPtr = std::make_shared<o2f::Output>(getOutput(usrOutput));
39-
auto mergerFuncPtr = std::make_shared<std::function<void(OutputBuffer, o2f::DataRef)> const>(mergerFunc);
39+
auto mergerFuncPtr = std::make_shared<std::function<void(OutputBuffer&, o2f::DataRef)> const>(mergerFunc);
4040

4141
// Defining the ProcessCallback as returned object of InitCallback
4242
return [outputPtr, mergerFuncPtr](o2f::ProcessingContext& ctx) {
43-
OutputBuffer outputBuffer;
43+
OutputBuffer outputBuffer = ctx.outputs().makeVector<char>(*outputPtr);
4444
// Iterating over the InputSpecs to aggregate msgs from the connected devices
4545
for (const auto& itInputs : ctx.inputs()) {
4646
(*mergerFuncPtr)(outputBuffer, itInputs);
4747
}
4848
// Adopting the buffer as new chunk
49-
ctx.outputs().adoptChunk((*outputPtr), &outputBuffer[0], outputBuffer.size(), &freefn,
50-
nullptr);
49+
ctx.outputs().adoptContainer((*outputPtr), std::move(outputBuffer));
5150
};
5251
}}};
5352
}
@@ -56,7 +55,7 @@ o2f::DataProcessorSpec defineMerger(std::string devName, o2f::Inputs usrInputs,
5655
o2f::DataProcessorSpec defineMerger(std::string devName, o2f::Inputs usrInputs, o2f::OutputSpec usrOutput)
5756
{
5857
// This lambda retrieves the payload size through the API and back-inserts it on the output buffer
59-
auto funcMerge = [](OutputBuffer buf, const o2f::DataRef d) {
58+
auto funcMerge = [](OutputBuffer& buf, const o2f::DataRef d) {
6059
auto msgSize = (o2::header::get<o2::header::DataHeader*>(d.header))->payloadSize;
6160
buf.resize(buf.size() + msgSize);
6261
std::copy(&(d.payload[0]), &(d.payload[msgSize - 1]), std::back_inserter(buf));

0 commit comments

Comments
 (0)