Project
Loading...
Searching...
No Matches
TPCDistributeCMVSpec.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15
16#ifndef O2_TPCDISTRIBUTECMVSPEC_H
17#define O2_TPCDISTRIBUTECMVSPEC_H
18
19#include <algorithm>
20#include <array>
21#include <limits>
22#include <unordered_map>
23#include <vector>
24#include <fmt/format.h>
25#include "Framework/Task.h"
27#include "Framework/Logger.h"
31#include "Headers/DataHeader.h"
38
39namespace o2::tpc
40{
41
43{
44 public:
45 TPCDistributeCMVSpec(const std::vector<uint32_t>& crus, const unsigned int timeframes, const int nTFsBuffer, const unsigned int outlanes, const int firstTF, std::shared_ptr<o2::base::GRPGeomRequest> req)
46 : mCRUs{crus},
47 mTimeFrames{timeframes},
48 mNTFsBuffer{nTFsBuffer},
49 mOutLanes{outlanes},
50 mProcessedCRU{{std::vector<unsigned int>(timeframes), std::vector<unsigned int>(timeframes)}},
51 mTFStart{{firstTF, firstTF + static_cast<long>(timeframes) * nTFsBuffer}},
52 mTFEnd{{firstTF + static_cast<long>(timeframes) * nTFsBuffer - 1, firstTF + 2LL * timeframes * nTFsBuffer - 1}},
53 mCCDBRequest(req),
54 mSendCCDBOutputOrbitReset(outlanes),
55 mSendCCDBOutputGRPECS(outlanes),
56 mOrbitInfoForwarded{{std::vector<bool>(timeframes, false), std::vector<bool>(timeframes, false)}}
57 {
58 mDataDescrOut.reserve(mOutLanes);
59 mOrbitDescrOut.reserve(mOutLanes);
60 for (unsigned int i = 0; i < mOutLanes; ++i) {
61 mDataDescrOut.emplace_back(getDataDescriptionCMV(i));
62 mOrbitDescrOut.emplace_back(getDataDescriptionCMVOrbitInfo(i));
63 }
64 // sort vector for binary_search
65 std::sort(mCRUs.begin(), mCRUs.end());
66
67 for (auto& processedCRUbuffer : mProcessedCRUs) {
68 processedCRUbuffer.resize(mTimeFrames);
69 for (auto& crusMap : processedCRUbuffer) {
70 crusMap.reserve(mCRUs.size());
71 for (const auto cruID : mCRUs) {
72 crusMap.emplace(cruID, false);
73 }
74 }
75 }
76
79 }
80
82 {
84 mNFactorTFs = ic.options().get<int>("nFactorTFs");
85 mNTFsDataDrop = ic.options().get<int>("drop-data-after-nTFs");
86 mCheckEveryNData = ic.options().get<int>("check-data-every-n");
87 if (mCheckEveryNData == 0) {
88 mCheckEveryNData = mTimeFrames / 2;
89 if (mCheckEveryNData == 0) {
90 mCheckEveryNData = 1;
91 }
92 mNTFsDataDrop = mCheckEveryNData;
93 }
94 }
95
96 void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final
97 {
99 if (matcher == o2::framework::ConcreteDataMatcher("CTP", "ORBITRESET", 0)) {
100 LOGP(debug, "Updating ORBITRESET");
101 std::fill(mSendCCDBOutputOrbitReset.begin(), mSendCCDBOutputOrbitReset.end(), true);
102 } else if (matcher == o2::framework::ConcreteDataMatcher("GLO", "GRPECS", 0)) {
103 // check if received object is valid
104 if (o2::base::GRPGeomHelper::instance().getGRPECS()->getRun() != 0) {
105 LOGP(debug, "Updating GRPECS");
106 std::fill(mSendCCDBOutputGRPECS.begin(), mSendCCDBOutputGRPECS.end(), true);
107 } else {
108 LOGP(debug, "Detected default GRPECS object");
109 }
110 }
111 }
112
114 {
115 // capture orbit-reset info once for precise CCDB timestamp calculation
116 if (mCCDBRequest->askTime) {
117 const bool grpecsValid = pc.inputs().isValid("grpecs");
118 const bool orbitResetValid = pc.inputs().isValid("orbitReset");
119 if (grpecsValid) {
120 pc.inputs().get<o2::parameters::GRPECSObject*>("grpecs");
121 }
122 if (orbitResetValid) {
123 pc.inputs().get<std::vector<Long64_t>*>("orbitReset");
124 }
125 if (pc.inputs().countValidInputs() == (grpecsValid + orbitResetValid)) {
126 return;
127 }
128 }
129
130 const auto tf = processing_helpers::getCurrentTF(pc);
131 if (tf == std::numeric_limits<uint32_t>::max()) {
132 forwardEOSData(pc);
133 return;
134 }
135
136 // automatically detect firstTF in case firstTF was not specified
137 if (mTFStart.front() <= -1) {
138 const auto firstTFDetected = tf;
139 const long offsetTF = std::abs(mTFStart.front() + 1);
140 const auto nTotTFs = getNRealTFs();
141 // tf is the batch TF counter (= last real TF in the first batch), subtract (mNTFsBuffer - 1) to recover the actual first real TF of the interval
142 const long firstRealTF = static_cast<long>(firstTFDetected) - (mNTFsBuffer - 1) + offsetTF;
143 mTFStart = {firstRealTF, firstRealTF + nTotTFs};
144 mTFEnd = {mTFStart[1] - 1, mTFStart[1] - 1 + nTotTFs};
145 LOGP(detail, "Setting {} as first TF", mTFStart[0]);
146 LOGP(detail, "Using offset of {} TFs for setting the first TF", offsetTF);
147 }
148
149 // check which buffer to use for current incoming data
150 const bool currentBuffer = (tf > mTFEnd[mBuffer]) ? !mBuffer : mBuffer;
151 if (mTFStart[currentBuffer] > tf) {
152 LOGP(warning, "Current TF {} is older than start of currentBuffer {}. Skipping this TF", tf, mTFStart[currentBuffer]);
153 return;
154 }
155
156 const unsigned int currentOutLane = getOutLane(tf);
157 const unsigned int relTF = (tf - mTFStart[currentBuffer]) / mNTFsBuffer;
158 LOGP(debug, "Current TF: {}, relative TF: {}, current buffer: {}, current output lane: {}, mTFStart: {}", tf, relTF, currentBuffer, currentOutLane, mTFStart[currentBuffer]);
159
160 if (relTF >= mProcessedCRU[currentBuffer].size()) {
161 LOGP(warning, "Skipping tf {} for lane {}: relative tf {} is larger than size of buffer [{}, {}]: {}", tf, currentOutLane, relTF, mTFStart[currentBuffer], mTFEnd[currentBuffer], mProcessedCRU[currentBuffer].size());
162 // check number of processed CRUs for previous TFs. If CRUs are missing for them, they are probably lost/not received
163 mProcessedTotalData = mCheckEveryNData;
164 checkIntervalsForMissingData(pc, currentBuffer, relTF, currentOutLane, tf);
165 return;
166 }
167
168 if (mProcessedCRU[currentBuffer][relTF] == mCRUs.size()) {
169 LOGP(warning, "All CRUs for current TF {} (relTF {}, lane {}) already received. Skipping this TF", tf, relTF, currentOutLane);
170 return;
171 }
172
173 if (mSendOutputStartInfo[currentBuffer]) {
174 mSendOutputStartInfo[currentBuffer] = false;
175 pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTPC, getDataDescriptionCMVFirstTF(), header::DataHeader::SubSpecificationType{currentOutLane}}, mTFStart[currentBuffer]);
176 }
177
178 if (mSendCCDBOutputOrbitReset[currentOutLane] && mSendCCDBOutputGRPECS[currentOutLane]) {
179 mSendCCDBOutputOrbitReset[currentOutLane] = false;
180 mSendCCDBOutputGRPECS[currentOutLane] = false;
182 }
183
184 forwardOrbitInfo(pc, currentBuffer, relTF, currentOutLane);
185
186 auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mFilter);
187 for (auto it = inputs.begin(); it != inputs.end(); ++it) {
188 auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
189 const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
190
191 // check if cru is specified in input cru list
192 if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
193 LOGP(debug, "Received data from CRU: {} which was not specified as input. Skipping", cru);
194 continue;
195 }
196
197 if (mProcessedCRUs[currentBuffer][relTF][cru]) {
198 LOGP(warning, "CRU {} for current TF {} (relTF {}, lane {}) already processed. Skipping ...", cru, tf, relTF, currentOutLane);
199 continue;
200 }
201 // count total number of processed CRUs for given TF
202 ++mProcessedCRU[currentBuffer][relTF];
203 // to keep track of processed CRUs
204 mProcessedCRUs[currentBuffer][relTF][cru] = true;
205
206 forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, cru, it, [&] { sendEmptyCMVOutput(pc, currentOutLane, cru); });
207 }
208
209 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);
210
211 // check for missing data if specified
212 if (mNTFsDataDrop > 0) {
213 checkIntervalsForMissingData(pc, currentBuffer, relTF, currentOutLane, tf);
214 }
215
216 if (mProcessedCRU[currentBuffer][relTF] == mCRUs.size()) {
217 ++mProcessedTFs[currentBuffer];
218 }
219
220 if (mProcessedTFs[currentBuffer] == mTimeFrames) {
221 finishInterval(pc, currentOutLane, currentBuffer, tf);
222 }
223 }
224
226
228 static header::DataDescription getDataDescriptionCMV(const unsigned int lane)
229 {
230 const std::string name = fmt::format("CMVAGG{}", lane);
232 description.runtimeInit(name.substr(0, 16).c_str());
233 return description;
234 }
235
238 {
239 const std::string name = fmt::format("CMVORB{}", lane);
241 description.runtimeInit(name.substr(0, 16).c_str());
242 return description;
243 }
244
247
248 private:
249 std::vector<uint32_t> mCRUs{};
250 const unsigned int mTimeFrames{};
251 const int mNTFsBuffer{1};
252 const unsigned int mOutLanes{};
253 std::array<unsigned int, 2> mProcessedTFs{{0, 0}};
254 std::array<std::vector<unsigned int>, 2> mProcessedCRU{};
255 std::array<std::vector<std::unordered_map<unsigned int, bool>>, 2> mProcessedCRUs{};
256 std::array<long, 2> mTFStart{};
257 std::array<long, 2> mTFEnd{};
258 std::array<bool, 2> mSendOutputStartInfo{true, true};
259 std::shared_ptr<o2::base::GRPGeomRequest> mCCDBRequest;
260 std::vector<bool> mSendCCDBOutputOrbitReset{};
261 std::vector<bool> mSendCCDBOutputGRPECS{};
262 unsigned int mCurrentOutLane{0};
263 bool mBuffer{false};
264 int mNFactorTFs{0};
265 int mNTFsDataDrop{0};
266 std::array<int, 2> mStartNTFsDataDrop{0};
267 long mProcessedTotalData{0};
268 int mCheckEveryNData{1};
269 std::vector<o2::framework::InputSpec> mFilter{};
270 std::vector<o2::framework::InputSpec> mOrbitFilter{};
271 std::vector<header::DataDescription> mDataDescrOut{};
272 std::vector<header::DataDescription> mOrbitDescrOut{};
273 std::array<std::vector<bool>, 2> mOrbitInfoForwarded{};
274
276 unsigned int getOutLane(const uint32_t tf) const { return (tf > mTFEnd[mBuffer]) ? (mCurrentOutLane + 1) % mOutLanes : mCurrentOutLane; }
278 unsigned int getNRealTFs() const { return mNTFsBuffer * mTimeFrames; }
279
280 void sendEmptyCMVOutput(o2::framework::ProcessingContext& pc, const unsigned int currentOutLane, const unsigned int cru)
281 {
283 }
284
285 void sendEmptyOrbitInfo(o2::framework::ProcessingContext& pc, const unsigned int outLane)
286 {
287 pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTPC, mOrbitDescrOut[outLane], header::DataHeader::SubSpecificationType{outLane}}, static_cast<uint64_t>(0));
288 }
289
290 template <typename EmptyFn>
291 void forwardData(o2::framework::ProcessingContext& pc, o2::framework::Output outSpec, const unsigned int cru, auto& it, EmptyFn&& sendEmptyData)
292 {
293 if (auto* payloadMsg = it.getPayload()) {
294 pc.outputs().forwardPayload(outSpec, *payloadMsg);
295 } else [[unlikely]] {
296 // this should never happen
297 LOGP(warning, "No payload for CRU {}; sending empty {} payload", cru, outSpec.description.as<std::string>());
298 sendEmptyData();
299 }
300 }
301
302 void forwardOrbitInfo(o2::framework::ProcessingContext& pc, const bool currentBuffer, const unsigned int relTF, const unsigned int currentOutLane)
303 {
304 if (mOrbitInfoForwarded[currentBuffer][relTF]) {
305 return;
306 }
307
308 auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mOrbitFilter);
309 for (auto it = inputs.begin(); it != inputs.end(); ++it) {
310 auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
311 const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
312 if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
313 continue;
314 }
315
316 forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mOrbitDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{currentOutLane}}, cru, it, [&] { sendEmptyOrbitInfo(pc, currentOutLane); });
317 mOrbitInfoForwarded[currentBuffer][relTF] = true;
318 break;
319 }
320 }
321
322 void forwardEOSData(o2::framework::ProcessingContext& pc)
323 {
324 const unsigned int currentOutLane = mCurrentOutLane;
325
326 if (mSendOutputStartInfo[mBuffer] && (mTFStart[mBuffer] >= 0)) {
327 mSendOutputStartInfo[mBuffer] = false;
328 pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginTPC, getDataDescriptionCMVFirstTF(), header::DataHeader::SubSpecificationType{currentOutLane}}, mTFStart[mBuffer]);
329 }
330
331 if (mSendCCDBOutputOrbitReset[currentOutLane] && mSendCCDBOutputGRPECS[currentOutLane]) {
332 mSendCCDBOutputOrbitReset[currentOutLane] = false;
333 mSendCCDBOutputGRPECS[currentOutLane] = false;
335 }
336
337 if (!mOrbitInfoForwarded[mBuffer].empty()) {
338 auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mOrbitFilter);
339 for (auto it = inputs.begin(); it != inputs.end(); ++it) {
340 auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
341 const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
342 if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
343 continue;
344 }
345
346 forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mOrbitDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{currentOutLane}}, cru, it, [&] { sendEmptyOrbitInfo(pc, currentOutLane); });
347 break;
348 }
349 }
350
351 auto inputs = o2::framework::InputRecordWalker(pc.inputs(), mFilter);
352 for (auto it = inputs.begin(); it != inputs.end(); ++it) {
353 auto const* tpcCRUHeader = o2::framework::DataRefUtils::getHeader<o2::header::DataHeader*>(*it);
354 const unsigned int cru = tpcCRUHeader->subSpecification >> 7;
355
356 // check if cru is specified in input cru list
357 if (!std::binary_search(mCRUs.begin(), mCRUs.end(), cru)) {
358 continue;
359 }
360
361 forwardData(pc, o2::framework::Output{o2::header::gDataOriginTPC, mDataDescrOut[currentOutLane], header::DataHeader::SubSpecificationType{cru}}, cru, it, [&] { sendEmptyCMVOutput(pc, currentOutLane, cru); });
362 }
363 }
364
365 void clearBuffer(const bool currentBuffer)
366 {
367 // reset per-CRU received flags so the next interval can accept data from all CRUs again
368 for (auto& crusMap : mProcessedCRUs[currentBuffer]) {
369 for (auto& it : crusMap) {
370 it.second = false;
371 }
372 }
373
374 mProcessedTFs[currentBuffer] = 0;
375 std::fill(mProcessedCRU[currentBuffer].begin(), mProcessedCRU[currentBuffer].end(), 0);
376 std::fill(mOrbitInfoForwarded[currentBuffer].begin(), mOrbitInfoForwarded[currentBuffer].end(), false);
377
378 mTFStart[mBuffer] = mTFEnd[!mBuffer] + 1;
379 mTFEnd[mBuffer] = mTFStart[mBuffer] + getNRealTFs() - 1;
380
381 // switch buffer and advance output lane
382 mBuffer = !mBuffer;
383 mCurrentOutLane = ++mCurrentOutLane % mOutLanes;
384 }
385
386 void checkIntervalsForMissingData(o2::framework::ProcessingContext& pc, const bool currentBuffer, const long relTF, const unsigned int currentOutLane, const uint32_t tf)
387 {
388 if (!(mProcessedTotalData++ % mCheckEveryNData)) {
389 LOGP(detail, "Checking for dropped packages...");
390
391 // if the last buffer has a smaller time range than expected, flush its remaining uncompleted TFs
392 if ((mTFStart[currentBuffer] > mTFStart[!currentBuffer]) && (relTF > mNTFsDataDrop)) {
393 LOGP(warning, "Checking last buffer from relTF {} to {}", mStartNTFsDataDrop[!currentBuffer], mProcessedCRU[!currentBuffer].size());
394 const unsigned int lastLane = (currentOutLane == 0) ? (mOutLanes - 1) : (currentOutLane - 1);
395 checkMissingData(pc, !currentBuffer, mStartNTFsDataDrop[!currentBuffer], mProcessedCRU[!currentBuffer].size(), lastLane);
396 LOGP(warning, "All empty TFs of last buffer [{}, {}] filled with dummy and sent, triggered by data from TF {} (relTF {}). Clearing buffer", mTFStart[!currentBuffer], mTFEnd[!currentBuffer], tf, relTF);
397 finishInterval(pc, lastLane, !currentBuffer, tf);
398 }
399
400 const int tfEndCheck = std::clamp(static_cast<int>(relTF) - mNTFsDataDrop, 0, static_cast<int>(mProcessedCRU[currentBuffer].size()));
401 LOGP(detail, "Checking current buffer from relTF {} to {}", mStartNTFsDataDrop[currentBuffer], tfEndCheck);
402 checkMissingData(pc, currentBuffer, mStartNTFsDataDrop[currentBuffer], tfEndCheck, currentOutLane);
403 mStartNTFsDataDrop[currentBuffer] = tfEndCheck;
404 }
405 }
406
407 void checkMissingData(o2::framework::ProcessingContext& pc, const bool currentBuffer, const int startTF, const int endTF, const unsigned int outLane)
408 {
409 for (int iTF = startTF; iTF < endTF; ++iTF) {
410 if (mProcessedCRU[currentBuffer][iTF] != mCRUs.size()) {
411 LOGP(warning, "CRUs for lane {} rel. TF: {} curr TF {} are missing! Processed {} CRUs out of {}", outLane, iTF, mTFStart[currentBuffer] + static_cast<long>(iTF) * mNTFsBuffer + mNTFsBuffer - 1, mProcessedCRU[currentBuffer][iTF], mCRUs.size());
412 ++mProcessedTFs[currentBuffer];
413 mProcessedCRU[currentBuffer][iTF] = mCRUs.size();
414
415 // send empty payloads for missing CRUs so the aggregate lane sees a complete set
416 for (auto& it : mProcessedCRUs[currentBuffer][iTF]) {
417 if (!it.second) {
418 it.second = true;
419 sendEmptyCMVOutput(pc, outLane, it.first);
420 }
421 }
422
423 // send zero orbit placeholder for missing TF so the aggregate lane can still reconstruct timing
424 if (!mOrbitInfoForwarded[currentBuffer][iTF]) {
425 sendEmptyOrbitInfo(pc, outLane);
426 mOrbitInfoForwarded[currentBuffer][iTF] = true;
427 }
428 }
429 }
430 }
431
432 void finishInterval(o2::framework::ProcessingContext& pc, const unsigned int currentOutLane, const bool buffer, const uint32_t tf)
433 {
434 if (mNFactorTFs > 0) {
435 mNFactorTFs = 0;
436 // ToDo: Find better fix. Set oldestForChannel to a very large value so the DPL dispatcher does not block waiting for older TF data that will never arrive
437 for (unsigned int ilane = 0; ilane < mOutLanes; ++ilane) {
438 auto& deviceProxy = pc.services().get<o2::framework::FairMQDeviceProxy>();
439 auto& state = deviceProxy.getOutputChannelState({static_cast<int>(ilane)});
440 size_t oldest = std::numeric_limits<size_t>::max() - 1;
441 state.oldestForChannel = {oldest};
442 }
443 }
444
445 LOGP(info, "All TFs for buffer [{}, {}] (lane {}) received at data from TF {}. Clearing buffer", mTFStart[buffer], mTFEnd[buffer], currentOutLane, tf);
446 clearBuffer(buffer);
447 mStartNTFsDataDrop[buffer] = 0;
448 mSendOutputStartInfo[buffer] = true;
449 }
450};
451
452o2::framework::DataProcessorSpec getTPCDistributeCMVSpec(const int ilane, const std::vector<uint32_t>& crus, const unsigned int timeframes, const unsigned int outlanes, const int firstTF, const bool sendPrecisetimeStamp = false, const int nTFsBuffer = 1)
453{
454 std::vector<o2::framework::InputSpec> inputSpecs;
455 inputSpecs.emplace_back(o2::framework::InputSpec{"cmvsgroup", o2::framework::ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, TPCFLPCMVDevice::getDataDescriptionCMVGroup()}, o2::framework::Lifetime::Sporadic});
456 inputSpecs.emplace_back(o2::framework::InputSpec{"cmvorbit", o2::framework::ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, TPCFLPCMVDevice::getDataDescriptionCMVOrbitInfo()}, o2::framework::Lifetime::Sporadic});
457
458 std::vector<o2::framework::OutputSpec> outputSpecs;
459 outputSpecs.reserve(3 * outlanes);
460 for (unsigned int lane = 0; lane < outlanes; ++lane) {
461 outputSpecs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, TPCDistributeCMVSpec::getDataDescriptionCMV(lane)}, o2::framework::Lifetime::Sporadic);
462 outputSpecs.emplace_back(o2::framework::ConcreteDataMatcher{o2::header::gDataOriginTPC, TPCDistributeCMVSpec::getDataDescriptionCMVOrbitInfo(lane), header::DataHeader::SubSpecificationType{lane}}, o2::framework::Lifetime::Sporadic);
463 outputSpecs.emplace_back(o2::framework::ConcreteDataMatcher{o2::header::gDataOriginTPC, TPCDistributeCMVSpec::getDataDescriptionCMVFirstTF(), header::DataHeader::SubSpecificationType{lane}}, o2::framework::Lifetime::Sporadic);
464 }
465
466 // Only lane 0 fetches CCDB orbit-reset/GRPECS objects and broadcasts them to all aggregate lanes, the other distribute lanes do not need them, avoiding redundant CCDB requests
467 bool fetchCCDB = false;
468 if (sendPrecisetimeStamp && (ilane == 0)) {
469 fetchCCDB = true;
470 for (unsigned int lane = 0; lane < outlanes; ++lane) {
471 outputSpecs.emplace_back(o2::framework::ConcreteDataMatcher{o2::header::gDataOriginTPC, TPCDistributeCMVSpec::getDataDescriptionCMVOrbitReset(), header::DataHeader::SubSpecificationType{lane}}, o2::framework::Lifetime::Sporadic);
472 }
473 }
474
475 auto ccdbRequest = std::make_shared<o2::base::GRPGeomRequest>(fetchCCDB, // orbitResetTime
476 fetchCCDB, // GRPECS=true
477 false, // GRPLHCIF
478 false, // GRPMagField
479 false, // askMatLUT
481 inputSpecs);
482
483 const auto id = fmt::format("tpc-distribute-cmv-{:02}", ilane);
485 id.data(),
486 inputSpecs,
487 outputSpecs,
488 o2::framework::AlgorithmSpec{o2::framework::adaptFromTask<TPCDistributeCMVSpec>(crus, timeframes, nTFsBuffer, outlanes, firstTF, ccdbRequest)},
489 o2::framework::Options{{"drop-data-after-nTFs", o2::framework::VariantType::Int, 0, {"Number of TFs after which to drop the data."}},
490 {"check-data-every-n", o2::framework::VariantType::Int, 0, {"Number of run function called after which to check for missing data (-1 for no checking, 0 for default checking)."}},
491 {"nFactorTFs", o2::framework::VariantType::Int, 1000, {"Number of TFs to skip for sending oldest TF."}}}};
492 spec.rank = ilane;
493 return spec;
494}
495
496} // namespace o2::tpc
497
498#endif
header::DataDescription description
benchmark::State & state
std::ostringstream debug
int32_t i
Helper for geometry and GRP related CCDB requests.
A helper class to iteratate over all parts of all input routes.
TPC device for processing CMVs on FLPs.
auto getOrbitResetTimeMS() const
bool finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
void snapshot(const Output &spec, T const &object)
CacheId adoptContainer(const Output &, ContainerT &, CacheStrategy, o2::header::SerializationMethod)
void forwardPayload(const Output &spec, fair::mq::Message &inputPayload, o2::header::SerializationMethod serializationMethod=o2::header::gSerializationMethodNone)
A helper class to iteratate over all parts of all input routes.
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
void finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj) final
static constexpr header::DataDescription getDataDescriptionCMVFirstTF()
void init(o2::framework::InitContext &ic) final
static header::DataDescription getDataDescriptionCMV(const unsigned int lane)
Return data description for aggregated CMVs for a given lane.
static constexpr header::DataDescription getDataDescriptionCMVOrbitReset()
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
TPCDistributeCMVSpec(const std::vector< uint32_t > &crus, const unsigned int timeframes, const int nTFsBuffer, const unsigned int outlanes, const int firstTF, std::shared_ptr< o2::base::GRPGeomRequest > req)
static header::DataDescription getDataDescriptionCMVOrbitInfo(const unsigned int lane)
Return data description for orbit/BC info for a given output lane.
void run(o2::framework::ProcessingContext &pc) final
static constexpr header::DataDescription getDataDescriptionCMVOrbitInfo()
Data description for the packed (orbit<<32|bc) scalar forwarded alongside each CRU's CMVGROUP.
static constexpr header::DataDescription getDataDescriptionCMVGroup()
GLuint buffer
Definition glcorearb.h:655
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLuint const GLchar * name
Definition glcorearb.h:781
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
@ Me
Only quit this data processor.
std::vector< ConfigParamSpec > Options
std::vector< T, fair::mq::pmr::polymorphic_allocator< T > > vector
uint32_t getCurrentTF(o2::framework::ProcessingContext &pc)
Global TPC definitions and constants.
Definition SimTraits.h:172
Enum< T >::Iterator begin(Enum< T >)
Definition Defs.h:156
o2::framework::DataProcessorSpec getTPCDistributeCMVSpec(const int ilane, const std::vector< uint32_t > &crus, const unsigned int timeframes, const unsigned int outlanes, const int firstTF, const bool sendPrecisetimeStamp=false, const int nTFsBuffer=1)
void empty(int)
std::unique_ptr< GPUReconstructionTimeframe > tf
header::DataDescription description
Definition Output.h:29
uint32_t SubSpecificationType
Definition DataHeader.h:622
std::enable_if_t< std::is_same< T, std::string >::value==true, T > as() const
get the descriptor as std::string
Definition DataHeader.h:301
void runtimeInit(const char *string, short length=-1)
Definition DataHeader.h:261