Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 33 additions & 20 deletions Framework/Core/src/ExternalFairMQDeviceProxy.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ void sendOnChannel(FairMQDevice& device, FairMQParts& messages, std::string cons
// method to clear the content.
// Maybe the FairMQ API can be improved at some point. Actually the ownership of all messages should be passed
// on to the transport and the messages should be empty after sending and the parts content can be cleared.
//assert(std::accumulate(messages.begin(), messages.end(), true, [](bool a, auto const& msg) {return a && (msg.get() == nullptr);}));
// assert(std::accumulate(messages.begin(), messages.end(), true, [](bool a, auto const& msg) {return a && (msg.get() == nullptr);}));
messages.fParts.clear();
}

Expand Down Expand Up @@ -168,17 +168,16 @@ void sendOnChannel(FairMQDevice& device, FairMQMessagePtr&& headerMessage, FairM
sendOnChannel(device, out, spec, tslice, channelRetriever);
}

InjectorFunction o2DataModelAdaptor(OutputSpec const& spec, uint64_t startTime, uint64_t step)
InjectorFunction o2DataModelAdaptor(OutputSpec const& spec, uint64_t startTime, uint64_t /*step*/)
{
auto timesliceId = std::make_shared<size_t>(startTime);
return [timesliceId, step, spec](FairMQDevice& device, FairMQParts& parts, ChannelRetriever channelRetriever) {
for (size_t i = 0; i < parts.Size() / 2; ++i) {
return [timesliceId, spec](FairMQDevice& device, FairMQParts& parts, ChannelRetriever channelRetriever) {
for (int i = 0; i < parts.Size() / 2; ++i) {
auto dh = o2::header::get<DataHeader*>(parts.At(i * 2)->GetData());

DataProcessingHeader dph{*timesliceId, 0};
o2::header::Stack headerStack{*dh, dph};
sendOnChannel(device, std::move(headerStack), std::move(parts.At(i * 2 + 1)), spec, channelRetriever);
auto oldTimesliceId = *timesliceId;
*timesliceId += 1;
}
};
Expand All @@ -197,7 +196,7 @@ InjectorFunction dplModelAdaptor(std::vector<OutputSpec> const& filterSpecs, DPL
warning();
}

bool find(std::string const& desc) const
[[nodiscard]] bool find(std::string const& desc) const
{
return descriptions.find(desc) != std::string::npos;
}
Expand Down Expand Up @@ -225,7 +224,7 @@ InjectorFunction dplModelAdaptor(std::vector<OutputSpec> const& filterSpecs, DPL
std::vector<std::string> unmatchedDescriptions;
static int64_t dplCounter = -1;
dplCounter++;
for (size_t msgidx = 0; msgidx < parts.Size(); msgidx += 2) {
for (int msgidx = 0; msgidx < parts.Size(); msgidx += 2) {
const auto dh = o2::header::get<DataHeader*>(parts.At(msgidx)->GetData());
if (!dh) {
LOG(error) << "data on input " << msgidx << " does not follow the O2 data model, DataHeader missing";
Expand All @@ -244,7 +243,7 @@ InjectorFunction dplModelAdaptor(std::vector<OutputSpec> const& filterSpecs, DPL

OutputSpec query{dh->dataOrigin, dh->dataDescription, dh->subSpecification};
LOG(debug) << "processing " << DataSpecUtils::describe(OutputSpec{dh->dataOrigin, dh->dataDescription, dh->subSpecification}) << " time slice " << dph->startTime << " part " << dh->splitPayloadIndex << " of " << dh->splitPayloadParts;
size_t finalBlockIndex = 0;
int finalBlockIndex = 0;
std::string channelName = "";

for (auto const& spec : filterSpecs) {
Expand Down Expand Up @@ -272,14 +271,14 @@ InjectorFunction dplModelAdaptor(std::vector<OutputSpec> const& filterSpecs, DPL
assert(finalBlockIndex >= msgidx + 2);
if (finalBlockIndex > parts.Size()) {
// TODO error handling
//LOGP(error, "DataHeader::splitPayloadParts invalid");
// LOGP(error, "DataHeader::splitPayloadParts invalid");
continue;
}

if (!channelName.empty()) {
// the checks for consistency of split payload parts are of informative nature
// forwarding happens independently
//if (dh->splitPayloadParts > 1 && dh->splitPayloadParts != std::numeric_limits<decltype(dh->splitPayloadParts)>::max()) {
// if (dh->splitPayloadParts > 1 && dh->splitPayloadParts != std::numeric_limits<decltype(dh->splitPayloadParts)>::max()) {
// if (lastSplitPartIndex == -1 && dh->splitPayloadIndex != 0) {
// LOG(warning) << "wrong split part index, expecting the first of " << dh->splitPayloadParts << " part(s)";
// } else if (dh->splitPayloadIndex != lastSplitPartIndex + 1) {
Expand Down Expand Up @@ -341,7 +340,7 @@ InjectorFunction incrementalConverter(OutputSpec const& spec, uint64_t startTime
return [timesliceId, spec, step](FairMQDevice& device, FairMQParts& parts, ChannelRetriever channelRetriever) {
// We iterate on all the parts and we send them two by two,
// adding the appropriate O2 header.
for (size_t i = 0; i < parts.Size(); ++i) {
for (int i = 0; i < parts.Size(); ++i) {
DataHeader dh;

// FIXME: this only supports fully specified output specs...
Expand All @@ -353,7 +352,7 @@ InjectorFunction incrementalConverter(OutputSpec const& spec, uint64_t startTime

DataProcessingHeader dph{*timesliceId, 0};
*timesliceId += step;
//we have to move the incoming data
// we have to move the incoming data
o2::header::Stack headerStack{dh, dph};

sendOnChannel(device, std::move(headerStack), std::move(parts.At(i)), spec, channelRetriever);
Expand Down Expand Up @@ -407,12 +406,12 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name,
return route.channel;
}
}
return std::string("");
return {""};
};

auto checkEos = [&inputs]() -> bool {
std::string channelNameForSplitParts;
for (size_t msgidx = 0; msgidx < inputs.Size() / 2; ++msgidx) {
for (int msgidx = 0; msgidx < inputs.Size() / 2; ++msgidx) {
auto const sih = o2::header::get<SourceInfoHeader*>(inputs.At(msgidx * 2)->GetData());
if (sih != nullptr && sih->state == InputChannelState::Completed) {
return true;
Expand All @@ -439,6 +438,21 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name,

FairMQParts parts;
device->Receive(parts, channel, 0);
// Populate TimingInfo from the first message
if (parts.Size() != 0) {
auto const dh = o2::header::get<DataHeader*>(parts.At(0)->GetData());
auto& timingInfo = ctx.services().get<TimingInfo>();
if (dh != nullptr) {
timingInfo.runNumber = dh->runNumber;
timingInfo.firstTFOrbit = dh->firstTForbit;
timingInfo.tfCounter = dh->tfCounter;
}
auto const dph = o2::header::get<DataProcessingHeader*>(parts.At(0)->GetData());
if (dph != nullptr) {
timingInfo.timeslice = dph->startTime;
timingInfo.creation = dph->creation;
}
}
dataHandler(parts, 0);
};

Expand All @@ -450,7 +464,6 @@ DataProcessorSpec specifyExternalFairMQDeviceProxy(char const* name,
return spec;
}

static char const* gDefaultChannel = "downstream";
// Decide where to sent the output. Everything to "downstream" if there is such a channel.
std::string defaultOutputProxyChannelSelector(InputSpec const& input, const std::unordered_map<std::string, std::vector<FairMQChannel>>& channels)
{
Expand All @@ -470,7 +483,7 @@ DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name,
// FIXME: even if a --channel-config option is specified on the command line, always the default string
// is retrieved from the config registry. The channel name thus needs to be configured in the default
// string AND must match the name in an optional channel config.
std::string channelConfig = options.get<std::string>("channel-config");
auto channelConfig = options.get<std::string>("channel-config");
std::regex r{R"(name=([^,]*))"};
std::vector<std::string> values{std::sregex_token_iterator{std::begin(channelConfig), std::end(channelConfig), r, 1},
std::sregex_token_iterator{}};
Expand Down Expand Up @@ -530,13 +543,13 @@ DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name,
FairMQParts out;
out.AddPart(std::move(headerMessage));
// add empty payload message
out.AddPart(std::move(device->NewMessageFor(channelName, 0, 0)));
out.AddPart(device->NewMessageFor(channelName, 0, 0));
sendOnChannel(*device, out, channelName);
}
};
callbacks.set(CallbackService::Id::EndOfStream, forwardEos);

return adaptStateless([lastDataProcessingHeader](RawDeviceService& rds, InputRecord& inputs) {
return adaptStateless([lastDataProcessingHeader](InputRecord& inputs) {
for (size_t ii = 0; ii != inputs.size(); ++ii) {
for (size_t pi = 0; pi < inputs.getNofParts(ii); ++pi) {
auto part = inputs.getByPos(ii, pi);
Expand Down Expand Up @@ -635,13 +648,13 @@ DataProcessorSpec specifyFairMQDeviceMultiOutputProxy(char const* name,
FairMQParts out;
out.AddPart(std::move(headerMessage));
// add empty payload message
out.AddPart(std::move(device->NewMessageFor(channelName, 0, 0)));
out.AddPart(device->NewMessageFor(channelName, 0, 0));
sendOnChannel(*device, out, channelName);
}
};
callbacks.set(CallbackService::Id::EndOfStream, forwardEos);

return adaptStateless([channelSelector, lastDataProcessingHeader](RawDeviceService& rds, InputRecord& inputs) {
return adaptStateless([channelSelector, lastDataProcessingHeader](InputRecord& inputs) {
// there is nothing to do if the forwarding is handled on the framework level
// as forward routes but we need to keep a copy of the last DataProcessingHeader
// for sending the EOS
Expand Down