Skip to content

Commit e30a9ae

Browse files
committed
TPC: replace two-copy forwarding by shallow-copy forwarding in IDC/CMV distribute devices
1 parent b4570d8 commit e30a9ae

2 files changed

Lines changed: 58 additions & 31 deletions

File tree

Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeCMVSpec.h

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,13 @@ class TPCDistributeCMVSpec : public o2::framework::Task
182182

183183
forwardOrbitInfo(pc, currentBuffer, relTF, currentOutLane);
184184

185-
for (auto& ref : o2::framework::InputRecordWalker(pc.inputs(), mFilter)) {
186-
auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
185+
auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mFilter);
186+
for (auto it = inputs.begin(); it != inputs.end(); ++it) {
187+
auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
187188
const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
188189

189190
// check if cru is specified in input cru list
190-
if (!(std::binary_search(mCRUs.begin(), mCRUs.end(), cru))) {
191+
if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
191192
LOGP(debug, "Received data from CRU: {} which was not specified as input. Skipping", cru);
192193
continue;
193194
}
@@ -200,7 +201,7 @@ class TPCDistributeCMVSpec : public o2::framework::Task
200201
// to keep track of processed CRUs
201202
mProcessedCRUs[currentBuffer][relTF][cru] = true;
202203

203-
sendOutput(pc, currentOutLane, cru, pc.inputs().get<o2::pmr::vector<uint16_t>>(ref));
204+
forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, cru, it, [&] { sendEmptyCMVOutput(pc, currentOutLane, cru); });
204205
}
205206

206207
LOGP(detail, "Number of received CRUs for current TF: {} Needed a total number of processed CRUs of: {} Current TF: {}", mProcessedCRU[currentBuffer][relTF], mCRUs.size(), tf);
@@ -247,7 +248,7 @@ class TPCDistributeCMVSpec : public o2::framework::Task
247248
const unsigned int mTimeFrames{}; ///< number of TFs per aggregation interval
248249
const int mNTFsBuffer{1}; ///< number of TFs for which the CMVs will be buffered (must match TPCFLPCMVSpec)
249250
const unsigned int mOutLanes{}; ///< number of parallel aggregate pipelines this distributor feeds
250-
std::array<unsigned int, 2> mProcessedTFs{{0, 0}}; ///< number of processed timeframes per buffer; triggers sendOutput when it reaches mTimeFrames
251+
std::array<unsigned int, 2> mProcessedTFs{{0, 0}}; ///< number of processed timeframes per buffer; triggers finishInterval when it reaches mTimeFrames
251252
std::array<std::vector<unsigned int>, 2> mProcessedCRU{}; ///< counter of received CRUs per (buffer, relTF); used to detect when a relTF is complete
252253
std::array<std::vector<std::unordered_map<unsigned int, bool>>, 2> mProcessedCRUs{}; ///< per-CRU received flag ([buffer][relTF][CRU]); prevents double-counting when a CRU re-sends
253254
std::array<long, 2> mTFStart{}; ///< absolute TF counter of the first TF in each buffer interval
@@ -274,14 +275,26 @@ class TPCDistributeCMVSpec : public o2::framework::Task
274275
/// Returns the total number of real TFs per buffer interval (= mNTFsBuffer * mTimeFrames)
275276
unsigned int getNRealTFs() const { return mNTFsBuffer * mTimeFrames; }
276277

277-
void sendOutput(o2::framework::ProcessingContext& pc, const unsigned int currentOutLane, const unsigned int cru, o2::pmr::vector<uint16_t> cmvs)
278+
void sendEmptyCMVOutput(o2::framework::ProcessingContext& pc, const unsigned int currentOutLane, const unsigned int cru)
279+
{
280+
pc.outputs().adoptContainer(o2::framework::Output{o2::header::gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, o2::pmr::vector<uint16_t>());
281+
}
282+
283+
void sendEmptyOrbitInfo(o2::framework::ProcessingContext& pc, const unsigned int outLane)
278284
{
279-
pc.outputs().adoptContainer(o2::framework::Output{o2::header::gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, std::move(cmvs));
285+
pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTPC, mOrbitDescrOut[outLane], header::DataHeader::SubSpecificationType{outLane}}, static_cast<uint64_t>(0));
280286
}
281287

282-
void sendOrbitInfo(o2::framework::ProcessingContext& pc, const unsigned int outLane, const uint64_t orbitInfo)
288+
template <typename EmptyFn>
289+
void forwardData(o2::framework::ProcessingContext& pc, o2::framework::Output outSpec, const unsigned int cru, auto& it, EmptyFn&& sendEmptyData)
283290
{
284-
pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTPC, mOrbitDescrOut[outLane], header::DataHeader::SubSpecificationType{outLane}}, orbitInfo);
291+
if (auto* payloadMsg = it.getPayload()) {
292+
pc.outputs().forwardPayload(outSpec, *payloadMsg);
293+
} else [[unlikely]] {
294+
// this should never happen
295+
LOGP(warning, "No payload for CRU {}; sending empty {} payload", cru, outSpec.description.as<std::string>());
296+
sendEmptyData();
297+
}
285298
}
286299

287300
void forwardOrbitInfo(o2::framework::ProcessingContext& pc, const bool currentBuffer, const unsigned int relTF, const unsigned int currentOutLane)
@@ -290,14 +303,15 @@ class TPCDistributeCMVSpec : public o2::framework::Task
290303
return;
291304
}
292305

293-
for (auto& ref : o2::framework::InputRecordWalker(pc.inputs(), mOrbitFilter)) {
294-
auto const* hdr = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
295-
const unsigned int cru = hdr->subSpecification >> 7;
306+
auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mOrbitFilter);
307+
for (auto it = inputs.begin(); it != inputs.end(); ++it) {
308+
auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
309+
const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
296310
if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
297311
continue;
298312
}
299313

300-
sendOrbitInfo(pc, currentOutLane, pc.inputs().get<uint64_t>(ref));
314+
forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mOrbitDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{currentOutLane}}, cru, it, [&] { sendEmptyOrbitInfo(pc, currentOutLane); });
301315
mOrbitInfoForwarded[currentBuffer][relTF] = true;
302316
break;
303317
}
@@ -319,24 +333,30 @@ class TPCDistributeCMVSpec : public o2::framework::Task
319333
}
320334

321335
if (!mOrbitInfoForwarded[mBuffer].empty()) {
322-
for (auto& ref : o2::framework::InputRecordWalker(pc.inputs(), mOrbitFilter)) {
323-
auto const* hdr = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
324-
const unsigned int cru = hdr->subSpecification >> 7;
336+
auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mOrbitFilter);
337+
for (auto it = inputs.begin(); it != inputs.end(); ++it) {
338+
auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
339+
const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
325340
if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
326341
continue;
327342
}
328-
sendOrbitInfo(pc, currentOutLane, pc.inputs().get<uint64_t>(ref));
343+
344+
forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mOrbitDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{currentOutLane}}, cru, it, [&] { sendEmptyOrbitInfo(pc, currentOutLane); });
329345
break;
330346
}
331347
}
332348

333-
for (auto& ref : o2::framework::InputRecordWalker(pc.inputs(), mFilter)) {
334-
auto const* hdr = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
335-
const unsigned int cru = hdr->subSpecification >> 7;
349+
auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mFilter);
350+
for (auto it = inputs.begin(); it != inputs.end(); ++it) {
351+
auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
352+
const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
353+
354+
// check if cru is specified in input cru list
336355
if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
337356
continue;
338357
}
339-
sendOutput(pc, currentOutLane, cru, pc.inputs().get<o2::pmr::vector<uint16_t>>(ref));
358+
359+
forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, cru, it, [&] { sendEmptyCMVOutput(pc, currentOutLane, cru); });
340360
}
341361
}
342362

@@ -394,13 +414,13 @@ class TPCDistributeCMVSpec : public o2::framework::Task
394414
for (auto& it : mProcessedCRUs[currentBuffer][iTF]) {
395415
if (!it.second) {
396416
it.second = true;
397-
sendOutput(pc, outLane, it.first, o2::pmr::vector<uint16_t>());
417+
sendEmptyCMVOutput(pc, outLane, it.first);
398418
}
399419
}
400420

401421
// send zero orbit placeholder for missing TF so the aggregate lane can still reconstruct timing
402422
if (!mOrbitInfoForwarded[currentBuffer][iTF]) {
403-
sendOrbitInfo(pc, outLane, 0);
423+
sendEmptyOrbitInfo(pc, outLane);
404424
mOrbitInfoForwarded[currentBuffer][iTF] = true;
405425
}
406426
}

Detectors/TPC/workflow/include/TPCWorkflow/TPCDistributeIDCSpec.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,13 @@ class TPCDistributeIDCSpec : public o2::framework::Task
169169
pc.outputs().snapshot(Output{gDataOriginTPC, getDataDescriptionIDCOrbitReset(), header::DataHeader::SubSpecificationType{currentOutLane}}, dataformats::Pair<long, int>{o2::base::GRPGeomHelper::instance().getOrbitResetTimeMS(), o2::base::GRPGeomHelper::instance().getNHBFPerTF()});
170170
}
171171

172-
for (auto& ref : InputRecordWalker(pc.inputs(), mFilter)) {
173-
auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(ref);
172+
auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mFilter);
173+
for (auto it = inputs.begin(); it != inputs.end(); ++it) {
174+
auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
174175
const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
175176

176177
// check if cru is specified in input cru list
177-
if (!(std::binary_search(mCRUs.begin(), mCRUs.end(), cru))) {
178+
if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
178179
LOGP(debug, "Received data from CRU: {} which was not specified as input. Skipping", cru);
179180
continue;
180181
}
@@ -189,8 +190,14 @@ class TPCDistributeIDCSpec : public o2::framework::Task
189190
mProcessedCRUs[currentBuffer][relTF][cru] = true;
190191
}
191192

192-
// sending IDCs
193-
sendOutput(pc, currentOutLane, cru, pc.inputs().get<pmr::vector<float>>(ref));
193+
// forward payload by shallow copy
194+
if (auto* payloadMsg = it.getPayload()) {
195+
pc.outputs().forwardPayload(Output{gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, *payloadMsg);
196+
} else [[unlikely]] {
197+
// this should never happen
198+
LOGP(warning, "No IDCGROUP payload for CRU {} (TF {}, relTF {}); sending empty IDCAGG{} payload", cru, tf, relTF, currentOutLane);
199+
sendEmptyIDCOutput(pc, currentOutLane, cru);
200+
}
194201
}
195202

196203
LOGP(info, "number of received CRUs for current TF: {} Needed a total number of processed CRUs of: {} Current TF: {}", mProcessedCRU[currentBuffer][relTF], mCRUs.size(), tf);
@@ -247,9 +254,9 @@ class TPCDistributeIDCSpec : public o2::framework::Task
247254
std::vector<InputSpec> mFilter{}; ///< filter for looping over input data
248255
std::vector<header::DataDescription> mDataDescrOut{};
249256

250-
void sendOutput(o2::framework::ProcessingContext& pc, const unsigned int currentOutLane, const unsigned int cru, o2::pmr::vector<float> idcs)
257+
void sendEmptyIDCOutput(o2::framework::ProcessingContext& pc, const unsigned int currentOutLane, const unsigned int cru)
251258
{
252-
pc.outputs().adoptContainer(Output{gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, std::move(idcs));
259+
pc.outputs().adoptContainer(Output{gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, pmr::vector<float>());
253260
}
254261

255262
/// returns the output lane to which the data will be send
@@ -314,7 +321,7 @@ class TPCDistributeIDCSpec : public o2::framework::Task
314321
for (auto& it : mProcessedCRUs[currentBuffer][iTF]) {
315322
if (!it.second) {
316323
it.second = true;
317-
sendOutput(pc, outLane, it.first, pmr::vector<float>());
324+
sendEmptyIDCOutput(pc, outLane, it.first);
318325
}
319326
}
320327
}

0 commit comments

Comments
 (0)