Project
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
GPUWorkflowSpec.cxx
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
16
18#include "Headers/DataHeader.h"
19#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs
27#include "Framework/Logger.h"
42#include "TPCFastTransform.h"
51#include "TPCBase/RDHUtils.h"
53#include "GPUO2InterfaceQA.h"
54#include "GPUO2Interface.h"
55#include "GPUO2InterfaceUtils.h"
56#include "CalibdEdxContainer.h"
57#include "GPUNewCalibValues.h"
58#include "TPCPadGainCalib.h"
59#include "TPCZSLinkMapping.h"
61#include "TPCBase/Sector.h"
62#include "TPCBase/Utils.h"
70#include "Algorithm/Parser.h"
73#include "TRDBase/Geometry.h"
80#include "GPUWorkflowInternal.h"
81// #include "Framework/ThreadPool.h"
82
83#include <TStopwatch.h>
84#include <TObjArray.h>
85#include <TH1F.h>
86#include <TH2F.h>
87#include <TH1D.h>
88#include <TGraphAsymmErrors.h>
89
90#include <filesystem>
91#include <memory>
92#include <vector>
93#include <iomanip>
94#include <stdexcept>
95#include <regex>
96#include <sys/types.h>
97#include <sys/stat.h>
98#include <fcntl.h>
99#include <chrono>
100#include <unordered_set>
101
102using namespace o2::framework;
103using namespace o2::header;
104using namespace o2::gpu;
105using namespace o2::base;
106using namespace o2::dataformats;
108
109namespace o2::gpu
110{
111
112GPURecoWorkflowSpec::GPURecoWorkflowSpec(GPURecoWorkflowSpec::CompletionPolicyData* policyData, Config const& specconfig, std::vector<int32_t> const& tpcsectors, uint64_t tpcSectorMask, std::shared_ptr<o2::base::GRPGeomRequest>& ggr, std::function<bool(o2::framework::DataProcessingHeader::StartTime)>** gPolicyOrder) : o2::framework::Task(), mPolicyData(policyData), mTPCSectorMask(tpcSectorMask), mTPCSectors(tpcsectors), mSpecConfig(specconfig), mGGR(ggr)
113{
114 if (mSpecConfig.outputCAClusters && !mSpecConfig.caClusterer && !mSpecConfig.decompressTPC) {
115 throw std::runtime_error("inconsistent configuration: cluster output is only possible if CA clusterer is activated");
116 }
117
118 mConfig.reset(new GPUO2InterfaceConfiguration);
119 mConfParam.reset(new GPUSettingsO2);
120 mTFSettings.reset(new GPUSettingsTF);
121 mTimer.reset(new TStopwatch);
122 mPipeline.reset(new GPURecoWorkflowSpec_PipelineInternals);
123
124 if (mSpecConfig.enableDoublePipeline == 1 && gPolicyOrder) {
125 *gPolicyOrder = &mPolicyOrder;
126 }
127}
128
130
132{
134 GPUO2InterfaceConfiguration& config = *mConfig.get();
135
136 // Create configuration object and fill settings
137 mConfig->configGRP.solenoidBzNominalGPU = 0;
138 mTFSettings->hasSimStartOrbit = 1;
139 auto& hbfu = o2::raw::HBFUtils::Instance();
140 mTFSettings->simStartOrbit = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).orbit;
141
142 *mConfParam = mConfig->ReadConfigurableParam();
143 if (mConfParam->display) {
144 mDisplayFrontend.reset(GPUDisplayFrontendInterface::getFrontend(mConfig->configDisplay.displayFrontend.c_str()));
145 mConfig->configProcessing.eventDisplay = mDisplayFrontend.get();
146 if (mConfig->configProcessing.eventDisplay != nullptr) {
147 LOG(info) << "Event display enabled";
148 } else {
149 throw std::runtime_error("GPU Event Display frontend could not be created!");
150 }
151 }
152 if (mSpecConfig.enableDoublePipeline) {
153 mConfig->configProcessing.doublePipeline = 1;
154 }
155
156 mAutoSolenoidBz = mConfParam->solenoidBzNominalGPU == -1e6f;
157 mAutoContinuousMaxTimeBin = mConfig->configGRP.grpContinuousMaxTimeBin < 0;
158 if (mAutoContinuousMaxTimeBin) {
159 mConfig->configGRP.grpContinuousMaxTimeBin = GPUO2InterfaceUtils::getTpcMaxTimeBinFromNHbf(mConfParam->overrideNHbfPerTF ? mConfParam->overrideNHbfPerTF : 256);
160 }
161 if (mConfig->configProcessing.deviceNum == -2) {
162 int32_t myId = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId;
163 int32_t idMax = ic.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices;
164 mConfig->configProcessing.deviceNum = myId;
165 LOG(info) << "GPU device number selected from pipeline id: " << myId << " / " << idMax;
166 }
167 if (mConfig->configProcessing.debugLevel >= 3 && mVerbosity == 0) {
168 mVerbosity = 1;
169 }
170 mConfig->configProcessing.runMC = mSpecConfig.processMC;
171 if (mSpecConfig.outputQA) {
172 if (!mSpecConfig.processMC && !mConfig->configQA.clusterRejectionHistograms) {
173 throw std::runtime_error("Need MC information to create QA plots");
174 }
175 if (!mSpecConfig.processMC) {
176 mConfig->configQA.noMC = true;
177 }
178 mConfig->configQA.shipToQC = true;
179 if (!mConfig->configProcessing.runQA) {
180 mConfig->configQA.enableLocalOutput = false;
181 mQATaskMask = (mSpecConfig.processMC ? 15 : 0) | (mConfig->configQA.clusterRejectionHistograms ? 32 : 0);
182 mConfig->configProcessing.runQA = -mQATaskMask;
183 }
184 }
185 mConfig->configReconstruction.tpc.nWaysOuter = true;
186 mConfig->configInterface.outputToExternalBuffers = true;
187 if (mConfParam->synchronousProcessing) {
188 mConfig->configReconstruction.useMatLUT = false;
189 }
190 if (mConfig->configProcessing.rtc.optSpecialCode == -1) {
191 mConfig->configProcessing.rtc.optSpecialCode = mConfParam->synchronousProcessing;
192 }
193
194 // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU)
195 if (mSpecConfig.outputTracks || mSpecConfig.outputCompClusters || mSpecConfig.outputCompClustersFlat) {
196 mConfig->configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion,
199 mConfig->configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks);
200 mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, mConfParam->rundEdx == -1 ? !mConfParam->synchronousProcessing : mConfParam->rundEdx);
201 }
202 if (mSpecConfig.outputCompClusters || mSpecConfig.outputCompClustersFlat) {
203 mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, true);
204 mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, true);
205 }
206 mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCClusters);
207 if (mSpecConfig.caClusterer) { // Override some settings if we have raw data as input
208 mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCRaw);
209 mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, true);
210 mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true);
211 }
212 if (mSpecConfig.decompressTPC) {
213 mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false);
214 mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true);
215 mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCCompressedClusters);
216 mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true);
217 mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false);
218 if (mTPCSectorMask != 0xFFFFFFFFF) {
219 throw std::invalid_argument("Cannot run TPC decompression with a sector mask");
220 }
221 }
222 if (mSpecConfig.runTRDTracking) {
223 mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::TRDTracklets, true);
224 mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, true);
225 }
226 if (mSpecConfig.runITSTracking) {
227 mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::ITSClusters, true);
228 mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::ITSTracks, true);
229 mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::ITSTracking, true);
230 }
231 if (mSpecConfig.outputSharedClusterMap) {
232 mConfig->configProcessing.outputSharedClusterMap = true;
233 }
234 if (!mSpecConfig.outputTracks) {
235 mConfig->configProcessing.createO2Output = 0; // Disable O2 TPC track format output if no track output requested
236 }
237 mConfig->configProcessing.param.tpcTriggerHandling = mSpecConfig.tpcTriggerHandling;
238
239 if (mConfParam->transformationFile.size() || mConfParam->transformationSCFile.size()) {
240 LOG(fatal) << "Deprecated configurable param options GPU_global.transformationFile or transformationSCFile used\n"
241 << "Instead, link the corresponding file as <somedir>/TPC/Calib/CorrectionMap/snapshot.root and use it via\n"
242 << "--condition-remap file://<somdir>=TPC/Calib/CorrectionMap option";
243 }
244 /* if (config.configProcessing.doublePipeline && ic.services().get<ThreadPool>().poolSize != 2) {
245 throw std::runtime_error("double pipeline requires exactly 2 threads");
246 } */
247 if (config.configProcessing.doublePipeline && (mSpecConfig.readTRDtracklets || mSpecConfig.runITSTracking || !(mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder))) {
248 LOG(fatal) << "GPU two-threaded pipeline works only with TPC-only processing, and with ZS input";
249 }
250
251 if (mSpecConfig.enableDoublePipeline != 2) {
252 mGPUReco = std::make_unique<GPUO2Interface>();
253
254 // initialize TPC calib objects
255 initFunctionTPCCalib(ic);
256
257 mConfig->configCalib.fastTransform = mCalibObjects.mFastTransformHelper->getCorrMap();
258 mConfig->configCalib.fastTransformRef = mCalibObjects.mFastTransformHelper->getCorrMapRef();
259 mConfig->configCalib.fastTransformMShape = mCalibObjects.mFastTransformHelper->getCorrMapMShape();
260 mConfig->configCalib.fastTransformHelper = mCalibObjects.mFastTransformHelper.get();
261 if (mConfig->configCalib.fastTransform == nullptr) {
262 throw std::invalid_argument("GPU workflow: initialization of the TPC transformation failed");
263 }
264
265 if (mConfParam->matLUTFile.size()) {
266 LOGP(info, "Loading matlut file {}", mConfParam->matLUTFile.c_str());
267 mConfig->configCalib.matLUT = o2::base::MatLayerCylSet::loadFromFile(mConfParam->matLUTFile.c_str());
268 if (mConfig->configCalib.matLUT == nullptr) {
269 LOGF(fatal, "Error loading matlut file");
270 }
271 } else {
272 mConfig->configProcessing.lateO2MatLutProvisioningSize = 50 * 1024 * 1024;
273 }
274
275 if (mSpecConfig.readTRDtracklets) {
276 mTRDGeometry = std::make_unique<o2::trd::GeometryFlat>();
277 mConfig->configCalib.trdGeometry = mTRDGeometry.get();
278 }
279
280 mConfig->configProcessing.willProvideO2PropagatorLate = true;
281 mConfig->configProcessing.o2PropagatorUseGPUField = true;
282
283 if (mConfParam->printSettings && (mConfParam->printSettings > 1 || ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId == 0)) {
284 mConfig->configProcessing.printSettings = true;
285 if (mConfParam->printSettings > 1) {
286 mConfig->PrintParam();
287 }
288 }
289
290 // Configuration is prepared, initialize the tracker.
291 if (mGPUReco->Initialize(config) != 0) {
292 throw std::invalid_argument("GPU Reconstruction initialization failed");
293 }
294 if (mSpecConfig.outputQA) {
295 mQA = std::make_unique<GPUO2InterfaceQA>(mConfig.get());
296 }
297 if (mSpecConfig.outputErrorQA) {
298 mGPUReco->setErrorCodeOutput(&mErrorQA);
299 }
300
301 // initialize ITS
302 if (mSpecConfig.runITSTracking) {
303 initFunctionITS(ic);
304 }
305 }
306
307 if (mSpecConfig.enableDoublePipeline) {
308 initPipeline(ic);
309 if (mConfParam->dump >= 2) {
310 LOG(fatal) << "Cannot use dump-only mode with multi-threaded pipeline";
311 }
312 }
313
314 auto& callbacks = ic.services().get<CallbackService>();
315 callbacks.set<CallbackService::Id::RegionInfoCallback>([this](fair::mq::RegionInfo const& info) {
316 if (info.size == 0) {
317 return;
318 }
319 if (mSpecConfig.enableDoublePipeline) {
320 mRegionInfos.emplace_back(info);
321 }
322 if (mSpecConfig.enableDoublePipeline == 2) {
323 return;
324 }
325 if (mConfParam->registerSelectedSegmentIds != -1 && info.managed && info.id != (uint32_t)mConfParam->registerSelectedSegmentIds) {
326 return;
327 }
328 int32_t fd = 0;
329 if (mConfParam->mutexMemReg) {
330 mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
331 fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, mask);
332 if (fd == -1) {
333 throw std::runtime_error("Error opening memlock mutex lock file");
334 }
335 fchmod(fd, mask);
336 if (lockf(fd, F_LOCK, 0)) {
337 throw std::runtime_error("Error locking memlock mutex file");
338 }
339 }
340 std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
341 if (mConfParam->benchmarkMemoryRegistration) {
342 start = std::chrono::high_resolution_clock::now();
343 }
344 if (mGPUReco->registerMemoryForGPU(info.ptr, info.size)) {
345 throw std::runtime_error("Error registering memory for GPU");
346 }
347 if (mConfParam->benchmarkMemoryRegistration) {
348 end = std::chrono::high_resolution_clock::now();
349 std::chrono::duration<double> elapsed_seconds = end - start;
350 LOG(info) << "Memory registration time (0x" << info.ptr << ", " << info.size << " bytes): " << elapsed_seconds.count() << " s";
351 }
352 if (mConfParam->mutexMemReg) {
353 if (lockf(fd, F_ULOCK, 0)) {
354 throw std::runtime_error("Error unlocking memlock mutex file");
355 }
356 close(fd);
357 }
358 });
359
360 mTimer->Stop();
361 mTimer->Reset();
362}
363
365{
366 LOGF(info, "GPU Reconstruction total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer->CpuTime(), mTimer->RealTime(), mTimer->Counter() - 1);
367 handlePipelineStop();
368}
369
371{
372 handlePipelineEndOfStream(ec);
373}
374
376{
377 if (mSpecConfig.enableDoublePipeline != 2) {
378 finaliseCCDBTPC(matcher, obj);
379 if (mSpecConfig.runITSTracking) {
380 finaliseCCDBITS(matcher, obj);
381 }
382 }
383 if (GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
384 mGRPGeomUpdated = true;
385 return;
386 }
387}
388
389template <class D, class E, class F, class G, class H, class I, class J, class K>
390void GPURecoWorkflowSpec::processInputs(ProcessingContext& pc, D& tpcZSmeta, E& inputZS, F& tpcZS, G& tpcZSonTheFlySizes, bool& debugTFDump, H& compClustersDummy, I& compClustersFlatDummy, J& pCompClustersFlat, K& tmpEmptyCompClusters)
391{
392 if (mSpecConfig.enableDoublePipeline == 1) {
393 return;
394 }
395 constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR;
396 constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS;
397
398 if (mSpecConfig.zsOnTheFly || mSpecConfig.zsDecoder) {
399 for (uint32_t i = 0; i < GPUTrackingInOutZS::NSECTORS; i++) {
400 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
401 tpcZSmeta.Pointers[i][j].clear();
402 tpcZSmeta.Sizes[i][j].clear();
403 }
404 }
405 }
406 if (mSpecConfig.zsOnTheFly) {
407 tpcZSonTheFlySizes = {0};
408 // tpcZSonTheFlySizes: #zs pages per endpoint:
409 std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "ZSSIZES"}, Lifetime::Timeframe}};
410 bool recv = false, recvsizes = false;
411 for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) {
412 if (recvsizes) {
413 throw std::runtime_error("Received multiple ZSSIZES data");
414 }
415 tpcZSonTheFlySizes = pc.inputs().get<std::array<uint32_t, NEndpoints * NSectors>>(ref);
416 recvsizes = true;
417 }
418 // zs pages
419 std::vector<InputSpec> filter2 = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "TPCZS"}, Lifetime::Timeframe}};
420 for (auto const& ref : InputRecordWalker(pc.inputs(), filter2)) {
421 if (recv) {
422 throw std::runtime_error("Received multiple TPCZS data");
423 }
424 inputZS = pc.inputs().get<gsl::span<o2::tpc::ZeroSuppressedContainer8kb>>(ref);
425 recv = true;
426 }
427 if (!recv || !recvsizes) {
428 throw std::runtime_error("TPC ZS on the fly data not received");
429 }
430
431 uint32_t offset = 0;
432 for (uint32_t i = 0; i < NSectors; i++) {
433 uint32_t pageSector = 0;
434 for (uint32_t j = 0; j < NEndpoints; j++) {
435 pageSector += tpcZSonTheFlySizes[i * NEndpoints + j];
436 offset += tpcZSonTheFlySizes[i * NEndpoints + j];
437 }
438 if (mVerbosity >= 1) {
439 LOG(info) << "GOT ZS on the fly pages FOR SECTOR " << i << " -> pages: " << pageSector;
440 }
441 }
442 }
443 if (mSpecConfig.zsDecoder) {
444 std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}};
445 auto isSameRdh = [](const char* left, const char* right) -> bool {
446 return o2::raw::RDHUtils::getFEEID(left) == o2::raw::RDHUtils::getFEEID(right) && o2::raw::RDHUtils::getDetectorField(left) == o2::raw::RDHUtils::getDetectorField(right);
447 };
448 auto checkForZSData = [](const char* ptr, uint32_t subSpec) -> bool {
449 const auto rdhLink = o2::raw::RDHUtils::getLinkID(ptr);
450 const auto detField = o2::raw::RDHUtils::getDetectorField(ptr);
451 const auto feeID = o2::raw::RDHUtils::getFEEID(ptr);
452 const auto feeLinkID = o2::tpc::rdh_utils::getLink(feeID);
453 // This check is not what it is supposed to be, but some MC SYNTHETIC data was generated with rdhLinkId set to feeLinkId, so we add some extra logic so we can still decode it
454 return detField == o2::tpc::raw_data_types::ZS && ((feeLinkID == o2::tpc::rdh_utils::UserLogicLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == 0)) ||
455 (feeLinkID == o2::tpc::rdh_utils::ILBZSLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == o2::tpc::rdh_utils::ILBZSLinkID || rdhLink == 0)) ||
456 (feeLinkID == o2::tpc::rdh_utils::DLBZSLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == o2::tpc::rdh_utils::DLBZSLinkID || rdhLink == 0)));
457 };
458 auto insertPages = [&tpcZSmeta, checkForZSData](const char* ptr, size_t count, uint32_t subSpec) -> void {
459 if (checkForZSData(ptr, subSpec)) {
460 int32_t rawcru = o2::tpc::rdh_utils::getCRU(ptr);
461 int32_t rawendpoint = o2::tpc::rdh_utils::getEndPoint(ptr);
462 tpcZSmeta.Pointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(ptr);
463 tpcZSmeta.Sizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(count);
464 }
465 };
466 if (DPLRawPageSequencer(pc.inputs(), filter)(isSameRdh, insertPages, checkForZSData)) {
467 debugTFDump = true;
468 static uint32_t nErrors = 0;
469 nErrors++;
470 if (nErrors == 1 || (nErrors < 100 && nErrors % 10 == 0) || nErrors % 1000 == 0 || mNTFs % 1000 == 0) {
471 LOG(error) << "DPLRawPageSequencer failed to process TPC raw data - data most likely not padded correctly - Using slow page scan instead (this alarm is downscaled from now on, so far " << nErrors << " of " << mNTFs << " TFs affected)";
472 }
473 }
474
475 int32_t totalCount = 0;
476 for (uint32_t i = 0; i < GPUTrackingInOutZS::NSECTORS; i++) {
477 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
478 tpcZSmeta.Pointers2[i][j] = tpcZSmeta.Pointers[i][j].data();
479 tpcZSmeta.Sizes2[i][j] = tpcZSmeta.Sizes[i][j].data();
480 tpcZS.sector[i].zsPtr[j] = tpcZSmeta.Pointers2[i][j];
481 tpcZS.sector[i].nZSPtr[j] = tpcZSmeta.Sizes2[i][j];
482 tpcZS.sector[i].count[j] = tpcZSmeta.Pointers[i][j].size();
483 totalCount += tpcZSmeta.Pointers[i][j].size();
484 }
485 }
486 } else if (mSpecConfig.decompressTPC) {
487 if (mSpecConfig.decompressTPCFromROOT) {
488 compClustersDummy = *pc.inputs().get<o2::tpc::CompressedClustersROOT*>("input");
489 compClustersFlatDummy.setForward(&compClustersDummy);
490 pCompClustersFlat = &compClustersFlatDummy;
491 } else {
492 pCompClustersFlat = pc.inputs().get<o2::tpc::CompressedClustersFlat*>("input").get();
493 }
494 if (pCompClustersFlat == nullptr) {
495 tmpEmptyCompClusters.reset(new char[sizeof(o2::tpc::CompressedClustersFlat)]);
496 memset(tmpEmptyCompClusters.get(), 0, sizeof(o2::tpc::CompressedClustersFlat));
497 pCompClustersFlat = (o2::tpc::CompressedClustersFlat*)tmpEmptyCompClusters.get();
498 }
499 } else if (!mSpecConfig.zsOnTheFly) {
500 if (mVerbosity) {
501 LOGF(info, "running tracking for sector(s) 0x%09x", mTPCSectorMask);
502 }
503 }
504}
505
506int32_t GPURecoWorkflowSpec::runMain(o2::framework::ProcessingContext* pc, GPUTrackingInOutPointers* ptrs, GPUInterfaceOutputs* outputRegions, int32_t threadIndex, GPUInterfaceInputUpdate* inputUpdateCallback)
507{
508 int32_t retVal = 0;
509 if (mConfParam->dump < 2) {
510 retVal = mGPUReco->RunTracking(ptrs, outputRegions, threadIndex, inputUpdateCallback);
511
512 if (retVal == 0 && mSpecConfig.runITSTracking) {
513 retVal = runITSTracking(*pc);
514 }
515 }
516
517 if (!mSpecConfig.enableDoublePipeline) { // TODO: Why is this needed for double-pipeline?
518 mGPUReco->Clear(false, threadIndex); // clean non-output memory used by GPU Reconstruction
519 }
520 return retVal;
521}
522
523void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs(calibObjectStruct& oldCalibObjects)
524{
525 if (mOldCalibObjects.size() > 0) {
526 mOldCalibObjects.pop();
527 }
528 mOldCalibObjects.emplace(std::move(oldCalibObjects));
529}
530
532{
533 constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR;
534 constexpr static size_t NEndpoints = o2::gpu::GPUTrackingInOutZS::NENDPOINTS;
535
536 auto cput = mTimer->CpuTime();
537 auto realt = mTimer->RealTime();
538 mTimer->Start(false);
539 mNTFs++;
540
541 std::vector<gsl::span<const char>> inputs;
542
543 const o2::tpc::CompressedClustersFlat* pCompClustersFlat = nullptr;
544 size_t compClustersFlatDummyMemory[(sizeof(o2::tpc::CompressedClustersFlat) + sizeof(size_t) - 1) / sizeof(size_t)];
545 o2::tpc::CompressedClustersFlat& compClustersFlatDummy = reinterpret_cast<o2::tpc::CompressedClustersFlat&>(compClustersFlatDummyMemory);
546 o2::tpc::CompressedClusters compClustersDummy;
549 std::array<uint32_t, NEndpoints * NSectors> tpcZSonTheFlySizes;
550 gsl::span<const o2::tpc::ZeroSuppressedContainer8kb> inputZS;
551 std::unique_ptr<char[]> tmpEmptyCompClusters;
552
553 bool getWorkflowTPCInput_clusters = false, getWorkflowTPCInput_mc = false, getWorkflowTPCInput_digits = false;
554 bool debugTFDump = false;
555
556 if (mSpecConfig.processMC) {
557 getWorkflowTPCInput_mc = true;
558 }
559 if (!mSpecConfig.decompressTPC && !mSpecConfig.caClusterer) {
560 getWorkflowTPCInput_clusters = true;
561 }
562 if (!mSpecConfig.decompressTPC && mSpecConfig.caClusterer && ((!mSpecConfig.zsOnTheFly || mSpecConfig.processMC) && !mSpecConfig.zsDecoder)) {
563 getWorkflowTPCInput_digits = true;
564 }
565
566 // ------------------------------ Handle inputs ------------------------------
567
568 auto lockDecodeInput = std::make_unique<std::lock_guard<std::mutex>>(mPipeline->mutexDecodeInput);
569
571 if (pc.inputs().getPos("itsTGeo") >= 0) {
572 pc.inputs().get<o2::its::GeometryTGeo*>("itsTGeo");
573 }
574 if (GRPGeomHelper::instance().getGRPECS()->isDetReadOut(o2::detectors::DetID::TPC) && mConfParam->tpcTriggeredMode ^ !GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::TPC)) {
575 LOG(fatal) << "configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting";
576 }
577
579 processInputs(pc, tpcZSmeta, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters); // Process non-digit / non-cluster inputs
580 const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits); // Process digit and cluster inputs
581
582 const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
583 mTFSettings->tfStartOrbit = tinfo.firstTForbit;
584 mTFSettings->hasTfStartOrbit = 1;
585 mTFSettings->hasNHBFPerTF = 1;
586 mTFSettings->nHBFPerTF = mConfParam->overrideNHbfPerTF ? mConfParam->overrideNHbfPerTF : GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF();
587 mTFSettings->hasRunStartOrbit = 0;
588 if (mVerbosity) {
589 LOG(info) << "TF firstTForbit " << mTFSettings->tfStartOrbit << " nHBF " << mTFSettings->nHBFPerTF << " runStartOrbit " << mTFSettings->runStartOrbit << " simStartOrbit " << mTFSettings->simStartOrbit;
590 }
591 ptrs.settingsTF = mTFSettings.get();
592
593 if (mConfParam->checkFirstTfOrbit) {
594 static uint32_t lastFirstTFOrbit = -1;
595 static uint32_t lastTFCounter = -1;
596 if (lastFirstTFOrbit != -1 && lastTFCounter != -1) {
597 int32_t diffOrbit = tinfo.firstTForbit - lastFirstTFOrbit;
598 int32_t diffCounter = tinfo.tfCounter - lastTFCounter;
599 if (diffOrbit != diffCounter * mTFSettings->nHBFPerTF) {
600 LOG(error) << "Time frame has mismatching firstTfOrbit - Last orbit/counter: " << lastFirstTFOrbit << " " << lastTFCounter << " - Current: " << tinfo.firstTForbit << " " << tinfo.tfCounter;
601 }
602 }
603 lastFirstTFOrbit = tinfo.firstTForbit;
604 lastTFCounter = tinfo.tfCounter;
605 }
606
608 decltype(o2::trd::getRecoInputContainer(pc, &ptrs, &inputTracksTRD)) trdInputContainer;
609 if (mSpecConfig.readTRDtracklets) {
610 o2::globaltracking::DataRequest dataRequestTRD;
612 inputTracksTRD.collectData(pc, dataRequestTRD);
613 trdInputContainer = std::move(o2::trd::getRecoInputContainer(pc, &ptrs, &inputTracksTRD));
614 }
615
616 void* ptrEp[NSectors * NEndpoints] = {};
617 bool doInputDigits = false, doInputDigitsMC = false;
618 if (mSpecConfig.decompressTPC) {
619 ptrs.tpcCompressedClusters = pCompClustersFlat;
620 } else if (mSpecConfig.zsOnTheFly) {
621 const uint64_t* buffer = reinterpret_cast<const uint64_t*>(&inputZS[0]);
622 o2::gpu::GPUReconstructionConvert::RunZSEncoderCreateMeta(buffer, tpcZSonTheFlySizes.data(), *&ptrEp, &tpcZS);
623 ptrs.tpcZS = &tpcZS;
624 doInputDigits = doInputDigitsMC = mSpecConfig.processMC;
625 } else if (mSpecConfig.zsDecoder) {
626 ptrs.tpcZS = &tpcZS;
627 if (mSpecConfig.processMC) {
628 throw std::runtime_error("Cannot process MC information, none available");
629 }
630 } else if (mSpecConfig.caClusterer) {
631 doInputDigits = true;
632 doInputDigitsMC = mSpecConfig.processMC;
633 } else {
634 ptrs.clustersNative = &inputsClustersDigits->clusterIndex;
635 }
636
637 if (mTPCSectorMask != 0xFFFFFFFFF) {
638 // Clean out the unused sectors, such that if they were present by chance, they are not processed, and if the values are uninitialized, we should not crash
639 for (uint32_t i = 0; i < NSectors; i++) {
640 if (!(mTPCSectorMask & (1ul << i))) {
641 if (ptrs.tpcZS) {
642 for (uint32_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) {
643 tpcZS.sector[i].zsPtr[j] = nullptr;
644 tpcZS.sector[i].nZSPtr[j] = nullptr;
645 tpcZS.sector[i].count[j] = 0;
646 }
647 }
648 }
649 }
650 }
651
652 GPUTrackingInOutDigits tpcDigitsMap;
653 GPUTPCDigitsMCInput tpcDigitsMapMC;
654 if (doInputDigits) {
655 ptrs.tpcPackedDigits = &tpcDigitsMap;
656 if (doInputDigitsMC) {
657 tpcDigitsMap.tpcDigitsMC = &tpcDigitsMapMC;
658 }
659 for (uint32_t i = 0; i < NSectors; i++) {
660 tpcDigitsMap.tpcDigits[i] = inputsClustersDigits->inputDigits[i].data();
661 tpcDigitsMap.nTPCDigits[i] = inputsClustersDigits->inputDigits[i].size();
662 if (doInputDigitsMC) {
663 tpcDigitsMapMC.v[i] = inputsClustersDigits->inputDigitsMCPtrs[i];
664 }
665 }
666 }
667
668 o2::tpc::TPCSectorHeader clusterOutputSectorHeader{0};
669 if (mClusterOutputIds.size() > 0) {
670 clusterOutputSectorHeader.sectorBits = mTPCSectorMask;
671 // subspecs [0, NSectors - 1] are used to identify sector data, we use NSectors to indicate the full TPC
672 clusterOutputSectorHeader.activeSectors = mTPCSectorMask;
673 }
674
675 // ------------------------------ Prepare stage for double-pipeline before normal output preparation ------------------------------
676
677 std::unique_ptr<GPURecoWorkflow_QueueObject> pipelineContext;
678 if (mSpecConfig.enableDoublePipeline) {
679 if (handlePipeline(pc, ptrs, tpcZSmeta, tpcZS, pipelineContext)) {
680 return;
681 }
682 }
683
684 // ------------------------------ Prepare outputs ------------------------------
685
686 GPUInterfaceOutputs outputRegions;
687 using outputDataType = char;
688 using outputBufferUninitializedVector = std::decay_t<decltype(pc.outputs().make<DataAllocator::UninitializedVector<outputDataType>>(Output{"", "", 0}))>;
689 using outputBufferType = std::pair<std::optional<std::reference_wrapper<outputBufferUninitializedVector>>, outputDataType*>;
690 std::vector<outputBufferType> outputBuffers(GPUInterfaceOutputs::count(), {std::nullopt, nullptr});
691 std::unordered_set<std::string> outputsCreated;
692
693 auto setOutputAllocator = [this, &outputBuffers, &outputRegions, &pc, &outputsCreated](const char* name, bool condition, GPUOutputControl& region, auto&& outputSpec, size_t offset = 0) {
694 if (condition) {
695 auto& buffer = outputBuffers[outputRegions.getIndex(region)];
696 if (mConfParam->allocateOutputOnTheFly) {
697 region.allocator = [this, name, &buffer, &pc, outputSpec = std::move(outputSpec), offset, &outputsCreated](size_t size) -> void* {
698 size += offset;
699 if (mVerbosity) {
700 LOG(info) << "ALLOCATING " << size << " bytes for " << name << ": " << std::get<DataOrigin>(outputSpec).template as<std::string>() << "/" << std::get<DataDescription>(outputSpec).template as<std::string>() << "/" << std::get<2>(outputSpec);
701 }
702 std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
703 if (mVerbosity) {
704 start = std::chrono::high_resolution_clock::now();
705 }
706 buffer.first.emplace(pc.outputs().make<DataAllocator::UninitializedVector<outputDataType>>(std::make_from_tuple<Output>(outputSpec), size));
707 outputsCreated.insert(name);
708 if (mVerbosity) {
709 end = std::chrono::high_resolution_clock::now();
710 std::chrono::duration<double> elapsed_seconds = end - start;
711 LOG(info) << "Allocation time for " << name << " (" << size << " bytes)"
712 << ": " << elapsed_seconds.count() << "s";
713 }
714 return (buffer.second = buffer.first->get().data()) + offset;
715 };
716 } else {
717 buffer.first.emplace(pc.outputs().make<DataAllocator::UninitializedVector<outputDataType>>(std::make_from_tuple<Output>(outputSpec), mConfParam->outputBufferSize));
718 region.ptrBase = (buffer.second = buffer.first->get().data()) + offset;
719 region.size = buffer.first->get().size() - offset;
720 outputsCreated.insert(name);
721 }
722 }
723 };
724
725 auto downSizeBuffer = [](outputBufferType& buffer, size_t size) {
726 if (!buffer.first) {
727 return;
728 }
729 if (buffer.first->get().size() < size) {
730 throw std::runtime_error("Invalid buffer size requested");
731 }
732 buffer.first->get().resize(size);
733 if (size && buffer.first->get().data() != buffer.second) {
734 throw std::runtime_error("Inconsistent buffer address after downsize");
735 }
736 };
737
738 /*auto downSizeBufferByName = [&outputBuffers, &outputRegions, &downSizeBuffer](GPUOutputControl& region, size_t size) {
739 auto& buffer = outputBuffers[outputRegions.getIndex(region)];
740 downSizeBuffer(buffer, size);
741 };*/
742
743 auto downSizeBufferToSpan = [&outputBuffers, &outputRegions, &downSizeBuffer](GPUOutputControl& region, auto span) {
744 auto& buffer = outputBuffers[outputRegions.getIndex(region)];
745 if (!buffer.first) {
746 return;
747 }
748 if (span.size() && buffer.second != (char*)span.data()) {
749 throw std::runtime_error("Buffer does not match span");
750 }
751 downSizeBuffer(buffer, span.size() * sizeof(*span.data()));
752 };
753
754 setOutputAllocator("COMPCLUSTERSFLAT", mSpecConfig.outputCompClustersFlat, outputRegions.compressedClusters, std::make_tuple(gDataOriginTPC, (DataDescription) "COMPCLUSTERSFLAT", 0));
755 setOutputAllocator("CLUSTERNATIVE", mClusterOutputIds.size() > 0, outputRegions.clustersNative, std::make_tuple(gDataOriginTPC, mSpecConfig.sendClustersPerSector ? (DataDescription) "CLUSTERNATIVETMP" : (DataDescription) "CLUSTERNATIVE", NSectors, clusterOutputSectorHeader), sizeof(o2::tpc::ClusterCountIndex));
756 setOutputAllocator("CLSHAREDMAP", mSpecConfig.outputSharedClusterMap, outputRegions.sharedClusterMap, std::make_tuple(gDataOriginTPC, (DataDescription) "CLSHAREDMAP", 0));
757 setOutputAllocator("TPCOCCUPANCYMAP", mSpecConfig.outputSharedClusterMap, outputRegions.tpcOccupancyMap, std::make_tuple(gDataOriginTPC, (DataDescription) "TPCOCCUPANCYMAP", 0));
758 setOutputAllocator("TRACKS", mSpecConfig.outputTracks, outputRegions.tpcTracksO2, std::make_tuple(gDataOriginTPC, (DataDescription) "TRACKS", 0));
759 setOutputAllocator("CLUSREFS", mSpecConfig.outputTracks, outputRegions.tpcTracksO2ClusRefs, std::make_tuple(gDataOriginTPC, (DataDescription) "CLUSREFS", 0));
760 setOutputAllocator("TRACKSMCLBL", mSpecConfig.outputTracks && mSpecConfig.processMC, outputRegions.tpcTracksO2Labels, std::make_tuple(gDataOriginTPC, (DataDescription) "TRACKSMCLBL", 0));
761 setOutputAllocator("TRIGGERWORDS", mSpecConfig.caClusterer && mConfig->configProcessing.param.tpcTriggerHandling, outputRegions.tpcTriggerWords, std::make_tuple(gDataOriginTPC, (DataDescription) "TRIGGERWORDS", 0));
763 if (mSpecConfig.processMC && mSpecConfig.caClusterer) {
764 outputRegions.clusterLabels.allocator = [&clustersMCBuffer](size_t size) -> void* { return &clustersMCBuffer; };
765 }
766
767 // ------------------------------ Actual processing ------------------------------
768
769 if ((int32_t)(ptrs.tpcZS != nullptr) + (int32_t)(ptrs.tpcPackedDigits != nullptr && (ptrs.tpcZS == nullptr || ptrs.tpcPackedDigits->tpcDigitsMC == nullptr)) + (int32_t)(ptrs.clustersNative != nullptr) + (int32_t)(ptrs.tpcCompressedClusters != nullptr) != 1) {
770 throw std::runtime_error("Invalid input for gpu tracking");
771 }
772
773 const auto& holdData = o2::tpc::TPCTrackingDigitsPreCheck::runPrecheck(&ptrs, mConfig.get());
774
775 calibObjectStruct oldCalibObjects;
776 doCalibUpdates(pc, oldCalibObjects);
777
778 lockDecodeInput.reset();
779
780 if (mConfParam->dump) {
781 if (mNTFs == 1) {
782 mGPUReco->DumpSettings();
783 }
784 mGPUReco->DumpEvent(mNTFs - 1, &ptrs);
785 }
786 std::unique_ptr<GPUTrackingInOutPointers> ptrsDump;
787 if (mConfParam->dumpBadTFMode == 2) {
788 ptrsDump.reset(new GPUTrackingInOutPointers);
789 memcpy((void*)ptrsDump.get(), (const void*)&ptrs, sizeof(ptrs));
790 }
791
792 int32_t retVal = 0;
793 if (mSpecConfig.enableDoublePipeline) {
794 if (!pipelineContext->jobSubmitted) {
795 enqueuePipelinedJob(&ptrs, &outputRegions, pipelineContext.get(), true);
796 } else {
797 finalizeInputPipelinedJob(&ptrs, &outputRegions, pipelineContext.get());
798 }
799 std::unique_lock lk(pipelineContext->jobFinishedMutex);
800 pipelineContext->jobFinishedNotify.wait(lk, [context = pipelineContext.get()]() { return context->jobFinished; });
801 retVal = pipelineContext->jobReturnValue;
802 } else {
803 // uint32_t threadIndex = pc.services().get<ThreadPool>().threadIndex;
804 uint32_t threadIndex = mNextThreadIndex;
805 if (mConfig->configProcessing.doublePipeline) {
806 mNextThreadIndex = (mNextThreadIndex + 1) % 2;
807 }
808
809 retVal = runMain(&pc, &ptrs, &outputRegions, threadIndex);
810 }
811 if (retVal != 0) {
812 debugTFDump = true;
813 }
814 cleanOldCalibsTPCPtrs(oldCalibObjects);
815
816 o2::utils::DebugStreamer::instance()->flush(); // flushing debug output to file
817
818 if (debugTFDump && mNDebugDumps < mConfParam->dumpBadTFs) {
819 mNDebugDumps++;
820 if (mConfParam->dumpBadTFMode <= 1) {
821 std::string filename = std::string("tpc_dump_") + std::to_string(pc.services().get<const o2::framework::DeviceSpec>().inputTimesliceId) + "_" + std::to_string(mNDebugDumps) + ".dump";
822 FILE* fp = fopen(filename.c_str(), "w+b");
823 std::vector<InputSpec> filter = {{"check", ConcreteDataTypeMatcher{gDataOriginTPC, "RAWDATA"}, Lifetime::Timeframe}};
824 for (auto const& ref : InputRecordWalker(pc.inputs(), filter)) {
825 auto data = pc.inputs().get<gsl::span<char>>(ref);
826 if (mConfParam->dumpBadTFMode == 1) {
827 uint64_t size = data.size();
828 fwrite(&size, 1, sizeof(size), fp);
829 }
830 fwrite(data.data(), 1, data.size(), fp);
831 }
832 fclose(fp);
833 } else if (mConfParam->dumpBadTFMode == 2) {
834 mGPUReco->DumpEvent(mNDebugDumps - 1, ptrsDump.get());
835 }
836 }
837
838 if (mConfParam->dump == 2) {
839 return;
840 }
841
842 // ------------------------------ Varios postprocessing steps ------------------------------
843
844 bool createEmptyOutput = false;
845 if (retVal != 0) {
846 if (retVal == 3 && mConfig->configProcessing.ignoreNonFatalGPUErrors) {
847 if (mConfig->configProcessing.throttleAlarms) {
848 LOG(warning) << "GPU Reconstruction aborted with non fatal error code, ignoring";
849 } else {
850 LOG(alarm) << "GPU Reconstruction aborted with non fatal error code, ignoring";
851 }
852 createEmptyOutput = !mConfParam->partialOutputForNonFatalErrors;
853 } else {
854 throw std::runtime_error("GPU Reconstruction error: error code " + std::to_string(retVal));
855 }
856 }
857
858 std::unique_ptr<o2::tpc::ClusterNativeAccess> tmpEmptyClNative;
859 if (createEmptyOutput) {
860 memset(&ptrs, 0, sizeof(ptrs));
861 for (uint32_t i = 0; i < outputRegions.count(); i++) {
862 if (outputBuffers[i].first) {
863 size_t toSize = 0;
864 if (i == outputRegions.getIndex(outputRegions.compressedClusters)) {
865 toSize = sizeof(*ptrs.tpcCompressedClusters);
866 } else if (i == outputRegions.getIndex(outputRegions.clustersNative)) {
867 toSize = sizeof(o2::tpc::ClusterCountIndex);
868 }
869 outputBuffers[i].first->get().resize(toSize);
870 outputBuffers[i].second = outputBuffers[i].first->get().data();
871 if (toSize) {
872 memset(outputBuffers[i].second, 0, toSize);
873 }
874 }
875 }
876 tmpEmptyClNative = std::make_unique<o2::tpc::ClusterNativeAccess>();
877 memset(tmpEmptyClNative.get(), 0, sizeof(*tmpEmptyClNative));
878 ptrs.clustersNative = tmpEmptyClNative.get();
879 if (mSpecConfig.processMC) {
880 MCLabelContainer cont;
881 cont.flatten_to(clustersMCBuffer.first);
882 clustersMCBuffer.second = clustersMCBuffer.first;
883 tmpEmptyClNative->clustersMCTruth = &clustersMCBuffer.second;
884 }
885 } else {
886 gsl::span<const o2::tpc::TrackTPC> spanOutputTracks = {ptrs.outputTracksTPCO2, ptrs.nOutputTracksTPCO2};
887 gsl::span<const uint32_t> spanOutputClusRefs = {ptrs.outputClusRefsTPCO2, ptrs.nOutputClusRefsTPCO2};
888 gsl::span<const o2::MCCompLabel> spanOutputTracksMCTruth = {ptrs.outputTracksTPCO2MC, ptrs.outputTracksTPCO2MC ? ptrs.nOutputTracksTPCO2 : 0};
889 if (!mConfParam->allocateOutputOnTheFly) {
890 for (uint32_t i = 0; i < outputRegions.count(); i++) {
891 if (outputRegions.asArray()[i].ptrBase) {
892 if (outputRegions.asArray()[i].size == 1) {
893 throw std::runtime_error("Preallocated buffer size exceeded");
894 }
895 outputRegions.asArray()[i].checkCurrent();
896 downSizeBuffer(outputBuffers[i], (char*)outputRegions.asArray()[i].ptrCurrent - (char*)outputBuffers[i].second);
897 }
898 }
899 }
900 downSizeBufferToSpan(outputRegions.tpcTracksO2, spanOutputTracks);
901 downSizeBufferToSpan(outputRegions.tpcTracksO2ClusRefs, spanOutputClusRefs);
902 downSizeBufferToSpan(outputRegions.tpcTracksO2Labels, spanOutputTracksMCTruth);
903
904 // if requested, tune TPC tracks
905 if (ptrs.nOutputTracksTPCO2) {
906 doTrackTuneTPC(ptrs, outputBuffers[outputRegions.getIndex(outputRegions.tpcTracksO2)].first->get().data());
907 }
908
909 if (mClusterOutputIds.size() > 0 && (void*)ptrs.clustersNative->clustersLinear != (void*)(outputBuffers[outputRegions.getIndex(outputRegions.clustersNative)].second + sizeof(o2::tpc::ClusterCountIndex))) {
910 throw std::runtime_error("cluster native output ptrs out of sync"); // sanity check
911 }
912 }
913
914 if (mConfig->configWorkflow.outputs.isSet(GPUDataTypes::InOutType::TPCMergedTracks)) {
915 LOG(info) << "found " << ptrs.nOutputTracksTPCO2 << " track(s)";
916 }
917
918 if (mSpecConfig.outputCompClusters) {
921 }
922
923 if (mClusterOutputIds.size() > 0) {
924 o2::tpc::ClusterNativeAccess const& accessIndex = *ptrs.clustersNative;
925 if (mSpecConfig.sendClustersPerSector) {
926 // Clusters are shipped by sector, we are copying into per-sector buffers (anyway only for ROOT output)
927 for (uint32_t i = 0; i < NSectors; i++) {
928 if (mTPCSectorMask & (1ul << i)) {
930 clusterOutputSectorHeader.sectorBits = (1ul << i);
931 char* buffer = pc.outputs().make<char>({gDataOriginTPC, "CLUSTERNATIVE", subspec, {clusterOutputSectorHeader}}, accessIndex.nClustersSector[i] * sizeof(*accessIndex.clustersLinear) + sizeof(o2::tpc::ClusterCountIndex)).data();
932 o2::tpc::ClusterCountIndex* outIndex = reinterpret_cast<o2::tpc::ClusterCountIndex*>(buffer);
933 memset(outIndex, 0, sizeof(*outIndex));
934 for (int32_t j = 0; j < o2::tpc::constants::MAXGLOBALPADROW; j++) {
935 outIndex->nClusters[i][j] = accessIndex.nClusters[i][j];
936 }
937 memcpy(buffer + sizeof(*outIndex), accessIndex.clusters[i][0], accessIndex.nClustersSector[i] * sizeof(*accessIndex.clustersLinear));
938 if (mSpecConfig.processMC && accessIndex.clustersMCTruth) {
939 MCLabelContainer cont;
940 for (uint32_t j = 0; j < accessIndex.nClustersSector[i]; j++) {
941 const auto& labels = accessIndex.clustersMCTruth->getLabels(accessIndex.clusterOffset[i][0] + j);
942 for (const auto& label : labels) {
943 cont.addElement(j, label);
944 }
945 }
946 ConstMCLabelContainer contflat;
947 cont.flatten_to(contflat);
948 pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, {clusterOutputSectorHeader}}, contflat);
949 }
950 }
951 }
952 } else {
953 // Clusters are shipped as single message, fill ClusterCountIndex
954 DataHeader::SubSpecificationType subspec = NSectors;
955 o2::tpc::ClusterCountIndex* outIndex = reinterpret_cast<o2::tpc::ClusterCountIndex*>(outputBuffers[outputRegions.getIndex(outputRegions.clustersNative)].second);
956 static_assert(sizeof(o2::tpc::ClusterCountIndex) == sizeof(accessIndex.nClusters));
957 memcpy(outIndex, &accessIndex.nClusters[0][0], sizeof(o2::tpc::ClusterCountIndex));
958 if (mSpecConfig.processMC && mSpecConfig.caClusterer && accessIndex.clustersMCTruth) {
959 pc.outputs().snapshot({gDataOriginTPC, "CLNATIVEMCLBL", subspec, {clusterOutputSectorHeader}}, clustersMCBuffer.first);
960 }
961 }
962 }
963 if (mSpecConfig.outputQA) {
964 TObjArray out;
965 bool sendQAOutput = !createEmptyOutput && outputRegions.qa.newQAHistsCreated;
966 auto getoutput = [sendQAOutput](auto ptr) { return sendQAOutput && ptr ? *ptr : std::decay_t<decltype(*ptr)>(); };
967 std::vector<TH1F> copy1 = getoutput(outputRegions.qa.hist1); // Internally, this will also be used as output, so we need a non-const copy
968 std::vector<TH2F> copy2 = getoutput(outputRegions.qa.hist2);
969 std::vector<TH1D> copy3 = getoutput(outputRegions.qa.hist3);
970 std::vector<TGraphAsymmErrors> copy4 = getoutput(outputRegions.qa.hist4);
971 if (sendQAOutput) {
972 mQA->postprocessExternal(copy1, copy2, copy3, copy4, out, mQATaskMask ? mQATaskMask : -1);
973 }
974 pc.outputs().snapshot({gDataOriginTPC, "TRACKINGQA", 0}, out);
975 if (sendQAOutput) {
976 mQA->cleanup();
977 }
978 }
979 if (mSpecConfig.outputErrorQA) {
980 pc.outputs().snapshot({gDataOriginGPU, "ERRORQA", 0}, mErrorQA);
981 mErrorQA.clear(); // FIXME: This is a race condition once we run multi-threaded!
982 }
983 if (mSpecConfig.outputSharedClusterMap && !outputsCreated.contains("TPCOCCUPANCYMAP")) {
985 }
986 if (mSpecConfig.tpcTriggerHandling && !outputsCreated.contains("TRIGGERWORDS")) {
988 }
989 mTimer->Stop();
990 LOG(info) << "GPU Reconstruction time for this TF " << mTimer->CpuTime() - cput << " s (cpu), " << mTimer->RealTime() - realt << " s (wall)";
991}
992
993void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, calibObjectStruct& oldCalibObjects)
994{
995 GPUCalibObjectsConst newCalibObjects;
996 GPUNewCalibValues newCalibValues;
997 // check for updates of TPC calibration objects
998 bool needCalibUpdate = false;
999 if (mGRPGeomUpdated) {
1000 mGRPGeomUpdated = false;
1001 needCalibUpdate = true;
1002
1003 if (!mITSGeometryCreated) {
1006 mITSGeometryCreated = true;
1007 }
1008
1009 if (mAutoSolenoidBz) {
1010 newCalibValues.newSolenoidField = true;
1011 newCalibValues.solenoidField = mConfig->configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*GRPGeomHelper::instance().getGRPMagField());
1012 // Propagator::Instance()->setBz(newCalibValues.solenoidField); // Take value from o2::Propagator::UpdateField from GRPGeomHelper
1013 LOG(info) << "Updating solenoid field " << newCalibValues.solenoidField;
1014 }
1015 if (mAutoContinuousMaxTimeBin) {
1016 newCalibValues.newContinuousMaxTimeBin = true;
1017 newCalibValues.continuousMaxTimeBin = mConfig->configGRP.grpContinuousMaxTimeBin = GPUO2InterfaceUtils::getTpcMaxTimeBinFromNHbf(mTFSettings->nHBFPerTF);
1018 LOG(info) << "Updating max time bin " << newCalibValues.continuousMaxTimeBin << " (" << mTFSettings->nHBFPerTF << " orbits)";
1019 }
1020
1021 if (!mPropagatorInstanceCreated) {
1022 newCalibObjects.o2Propagator = mConfig->configCalib.o2Propagator = Propagator::Instance();
1023 if (mConfig->configProcessing.o2PropagatorUseGPUField) {
1024 mGPUReco->UseGPUPolynomialFieldInPropagator(Propagator::Instance());
1025 }
1026 mPropagatorInstanceCreated = true;
1027 }
1028
1029 if (!mMatLUTCreated) {
1030 if (mConfParam->matLUTFile.size() == 0) {
1031 newCalibObjects.matLUT = GRPGeomHelper::instance().getMatLUT();
1032 LOG(info) << "Loaded material budget lookup table";
1033 }
1034 mMatLUTCreated = true;
1035 }
1036 if (!mTRDGeometryCreated) {
1037 if (mSpecConfig.readTRDtracklets) {
1038 auto gm = o2::trd::Geometry::instance();
1039 gm->createPadPlaneArray();
1040 gm->createClusterMatrixArray();
1041 mTRDGeometry = std::make_unique<o2::trd::GeometryFlat>(*gm);
1042 newCalibObjects.trdGeometry = mConfig->configCalib.trdGeometry = mTRDGeometry.get();
1043 LOG(info) << "Loaded TRD geometry";
1044 }
1045 mTRDGeometryCreated = true;
1046 }
1047 }
1048 needCalibUpdate = fetchCalibsCCDBTPC(pc, newCalibObjects, oldCalibObjects) || needCalibUpdate;
1049 if (mSpecConfig.runITSTracking) {
1050 needCalibUpdate = fetchCalibsCCDBITS(pc) || needCalibUpdate;
1051 }
1052 if (mTPCCutAtTimeBin != mConfig->configGRP.tpcCutTimeBin) {
1053 newCalibValues.newTPCTimeBinCut = true;
1054 newCalibValues.tpcTimeBinCut = mConfig->configGRP.tpcCutTimeBin = mTPCCutAtTimeBin;
1055 needCalibUpdate = true;
1056 }
1057 if (needCalibUpdate) {
1058 LOG(info) << "Updating GPUReconstruction calibration objects";
1059 mGPUReco->UpdateCalibration(newCalibObjects, newCalibValues);
1060 }
1061}
1062
1064{
1065 Options opts;
1066 if (mSpecConfig.enableDoublePipeline) {
1067 bool send = mSpecConfig.enableDoublePipeline == 2;
1068 char* o2jobid = getenv("O2JOBID");
1069 char* numaid = getenv("NUMAID");
1070 int32_t chanid = o2jobid ? atoi(o2jobid) : (numaid ? atoi(numaid) : 0);
1071 std::string chan = std::string("name=gpu-prepare-channel,type=") + (send ? "push" : "pull") + ",method=" + (send ? "connect" : "bind") + ",address=ipc://@gpu-prepare-channel-" + std::to_string(chanid) + "-{timeslice0},transport=shmem,rateLogging=0";
1072 opts.emplace_back(o2::framework::ConfigParamSpec{"channel-config", o2::framework::VariantType::String, chan, {"Out-of-band channel config"}});
1073 }
1074 if (mSpecConfig.enableDoublePipeline == 2) {
1075 return opts;
1076 }
1077 if (mSpecConfig.outputTracks) {
1079 }
1080 return opts;
1081}
1082
1084{
1085 Inputs inputs;
1086 if (mSpecConfig.zsDecoder) {
1087 // All ZS raw data is published with subspec 0 by the o2-raw-file-reader-workflow and DataDistribution
1088 // creates subspec fom CRU and endpoint id, we create one single input route subscribing to all TPC/RAWDATA
1089 inputs.emplace_back(InputSpec{"zsraw", ConcreteDataTypeMatcher{"TPC", "RAWDATA"}, Lifetime::Timeframe});
1090 if (mSpecConfig.askDISTSTF) {
1091 inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe);
1092 }
1093 }
1094 if (mSpecConfig.enableDoublePipeline == 2) {
1095 if (!mSpecConfig.zsDecoder) {
1096 LOG(fatal) << "Double pipeline mode can only work with zsraw input";
1097 }
1098 return inputs;
1099 } else if (mSpecConfig.enableDoublePipeline == 1) {
1100 inputs.emplace_back("pipelineprepare", gDataOriginGPU, "PIPELINEPREPARE", 0, Lifetime::Timeframe);
1101 }
1102 if (mSpecConfig.outputTracks || mSpecConfig.caClusterer) {
1103 // calibration objects for TPC clusterization
1104 inputs.emplace_back("tpcgain", gDataOriginTPC, "PADGAINFULL", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalPadGainFull)));
1105 inputs.emplace_back("tpcaltrosync", gDataOriginTPC, "ALTROSYNCSIGNAL", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::AltroSyncSignal)));
1106 }
1107 if (mSpecConfig.outputTracks) {
1108 // calibration objects for TPC tracking
1109 const auto mapSources = mSpecConfig.tpcDeadMapSources;
1110 if (mapSources != 0) {
1111 tpc::SourcesDeadMap sources((mapSources > -1) ? static_cast<tpc::SourcesDeadMap>(mapSources) : tpc::SourcesDeadMap::All);
1113 inputs.emplace_back("tpcidcpadflags", gDataOriginTPC, "IDCPADFLAGS", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalIDCPadStatusMapA), {}, 1)); // time-dependent
1114 }
1116 inputs.emplace_back("tpcruninfo", gDataOriginTPC, "TPCRUNINFO", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::ConfigRunInfo)));
1117 }
1118 }
1119
1120 inputs.emplace_back("tpcgainresidual", gDataOriginTPC, "PADGAINRESIDUAL", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalPadGainResidual), {}, 1)); // time-dependent
1121 if (mSpecConfig.tpcUseMCTimeGain) {
1122 inputs.emplace_back("tpctimegain", gDataOriginTPC, "TIMEGAIN", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalTimeGainMC), {}, 1)); // time-dependent
1123 } else {
1124 inputs.emplace_back("tpctimegain", gDataOriginTPC, "TIMEGAIN", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalTimeGain), {}, 1)); // time-dependent
1125 }
1126 inputs.emplace_back("tpctopologygain", gDataOriginTPC, "TOPOLOGYGAIN", 0, Lifetime::Condition, ccdbParamSpec(o2::tpc::CDBTypeMap.at(o2::tpc::CDBType::CalTopologyGain)));
1127 inputs.emplace_back("tpcthreshold", gDataOriginTPC, "PADTHRESHOLD", 0, Lifetime::Condition, ccdbParamSpec("TPC/Config/FEEPad"));
1129 Options optsDummy;
1130 o2::tpc::CorrectionMapsLoaderGloOpts gloOpts{mSpecConfig.lumiScaleType, mSpecConfig.lumiScaleMode, mSpecConfig.enableMShape, mSpecConfig.enableCTPLumi};
1131 mCalibObjects.mFastTransformHelper->requestCCDBInputs(inputs, optsDummy, gloOpts); // option filled here is lost
1132 }
1133 if (mSpecConfig.decompressTPC) {
1134 inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, mSpecConfig.decompressTPCFromROOT ? o2::header::DataDescription("COMPCLUSTERS") : o2::header::DataDescription("COMPCLUSTERSFLAT")}, Lifetime::Timeframe});
1135 } else if (mSpecConfig.caClusterer) {
1136 // We accept digits and MC labels also if we run on ZS Raw data, since they are needed for MC label propagation
1137 if ((!mSpecConfig.zsOnTheFly || mSpecConfig.processMC) && !mSpecConfig.zsDecoder) {
1138 inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe});
1139 mPolicyData->emplace_back(o2::framework::InputSpec{"digits", o2::framework::ConcreteDataTypeMatcher{"TPC", "DIGITS"}});
1140 }
1141 } else if (mSpecConfig.runTPCTracking) {
1142 inputs.emplace_back(InputSpec{"input", ConcreteDataTypeMatcher{gDataOriginTPC, "CLUSTERNATIVE"}, Lifetime::Timeframe});
1143 mPolicyData->emplace_back(o2::framework::InputSpec{"clusters", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}});
1144 }
1145 if (mSpecConfig.processMC) {
1146 if (mSpecConfig.caClusterer) {
1147 if (!mSpecConfig.zsDecoder) {
1148 inputs.emplace_back(InputSpec{"mclblin", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITSMCTR"}, Lifetime::Timeframe});
1149 mPolicyData->emplace_back(o2::framework::InputSpec{"digitsmc", o2::framework::ConcreteDataTypeMatcher{"TPC", "DIGITSMCTR"}});
1150 }
1151 } else {
1152 inputs.emplace_back(InputSpec{"mclblin", ConcreteDataTypeMatcher{gDataOriginTPC, "CLNATIVEMCLBL"}, Lifetime::Timeframe});
1153 mPolicyData->emplace_back(o2::framework::InputSpec{"clustersmc", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLNATIVEMCLBL"}});
1154 }
1155 }
1156
1157 if (mSpecConfig.zsOnTheFly) {
1158 inputs.emplace_back(InputSpec{"zsinput", ConcreteDataTypeMatcher{"TPC", "TPCZS"}, Lifetime::Timeframe});
1159 inputs.emplace_back(InputSpec{"zsinputsizes", ConcreteDataTypeMatcher{"TPC", "ZSSIZES"}, Lifetime::Timeframe});
1160 }
1161 if (mSpecConfig.readTRDtracklets) {
1162 inputs.emplace_back("trdctracklets", o2::header::gDataOriginTRD, "CTRACKLETS", 0, Lifetime::Timeframe);
1163 inputs.emplace_back("trdtracklets", o2::header::gDataOriginTRD, "TRACKLETS", 0, Lifetime::Timeframe);
1164 inputs.emplace_back("trdtriggerrec", o2::header::gDataOriginTRD, "TRKTRGRD", 0, Lifetime::Timeframe);
1165 inputs.emplace_back("trdtrigrecmask", o2::header::gDataOriginTRD, "TRIGRECMASK", 0, Lifetime::Timeframe);
1166 }
1167
1168 if (mSpecConfig.runITSTracking) {
1169 inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe);
1170 inputs.emplace_back("patterns", "ITS", "PATTERNS", 0, Lifetime::Timeframe);
1171 inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe);
1172 if (mSpecConfig.itsTriggerType == 1) {
1173 inputs.emplace_back("phystrig", "ITS", "PHYSTRIG", 0, Lifetime::Timeframe);
1174 } else if (mSpecConfig.itsTriggerType == 2) {
1175 inputs.emplace_back("phystrig", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe);
1176 }
1177 inputs.emplace_back("itscldict", "ITS", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary"));
1178 inputs.emplace_back("itsalppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam"));
1179
1180 if (mSpecConfig.itsOverrBeamEst) {
1181 inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1));
1182 }
1183 if (mSpecConfig.processMC) {
1184 inputs.emplace_back("itsmclabels", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe);
1185 inputs.emplace_back("ITSMC2ROframes", "ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe);
1186 }
1187 }
1188
1189 return inputs;
1190};
1191
1193{
1194 constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR;
1195 std::vector<OutputSpec> outputSpecs;
1196 if (mSpecConfig.enableDoublePipeline == 2) {
1197 outputSpecs.emplace_back(gDataOriginGPU, "PIPELINEPREPARE", 0, Lifetime::Timeframe);
1198 return outputSpecs;
1199 }
1200 if (mSpecConfig.outputTracks) {
1201 outputSpecs.emplace_back(gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe);
1202 outputSpecs.emplace_back(gDataOriginTPC, "CLUSREFS", 0, Lifetime::Timeframe);
1203 }
1204 if (mSpecConfig.processMC && mSpecConfig.outputTracks) {
1205 outputSpecs.emplace_back(gDataOriginTPC, "TRACKSMCLBL", 0, Lifetime::Timeframe);
1206 }
1207 if (mSpecConfig.outputCompClusters) {
1208 outputSpecs.emplace_back(gDataOriginTPC, "COMPCLUSTERS", 0, Lifetime::Timeframe);
1209 }
1210 if (mSpecConfig.outputCompClustersFlat) {
1211 outputSpecs.emplace_back(gDataOriginTPC, "COMPCLUSTERSFLAT", 0, Lifetime::Timeframe);
1212 }
1213 if (mSpecConfig.outputCAClusters) {
1214 for (auto const& sector : mTPCSectors) {
1215 mClusterOutputIds.emplace_back(sector);
1216 }
1217 if (mSpecConfig.sendClustersPerSector) {
1218 outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVETMP", NSectors, Lifetime::Timeframe); // Dummy buffer the TPC tracker writes the inital linear clusters to
1219 for (const auto sector : mTPCSectors) {
1220 outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", sector, Lifetime::Timeframe);
1221 }
1222 } else {
1223 outputSpecs.emplace_back(gDataOriginTPC, "CLUSTERNATIVE", NSectors, Lifetime::Timeframe);
1224 }
1225 if (mSpecConfig.processMC) {
1226 if (mSpecConfig.sendClustersPerSector) {
1227 for (const auto sector : mTPCSectors) {
1228 outputSpecs.emplace_back(gDataOriginTPC, "CLNATIVEMCLBL", sector, Lifetime::Timeframe);
1229 }
1230 } else {
1231 outputSpecs.emplace_back(gDataOriginTPC, "CLNATIVEMCLBL", NSectors, Lifetime::Timeframe);
1232 }
1233 }
1234 }
1235 if (mSpecConfig.outputSharedClusterMap) {
1236 outputSpecs.emplace_back(gDataOriginTPC, "CLSHAREDMAP", 0, Lifetime::Timeframe);
1237 outputSpecs.emplace_back(gDataOriginTPC, "TPCOCCUPANCYMAP", 0, Lifetime::Timeframe);
1238 }
1239 if (mSpecConfig.tpcTriggerHandling) {
1240 outputSpecs.emplace_back(gDataOriginTPC, "TRIGGERWORDS", 0, Lifetime::Timeframe);
1241 }
1242 if (mSpecConfig.outputQA) {
1243 outputSpecs.emplace_back(gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe);
1244 }
1245 if (mSpecConfig.outputErrorQA) {
1246 outputSpecs.emplace_back(gDataOriginGPU, "ERRORQA", 0, Lifetime::Timeframe);
1247 }
1248
1249 if (mSpecConfig.runITSTracking) {
1250 outputSpecs.emplace_back(gDataOriginITS, "TRACKS", 0, Lifetime::Timeframe);
1251 outputSpecs.emplace_back(gDataOriginITS, "TRACKCLSID", 0, Lifetime::Timeframe);
1252 outputSpecs.emplace_back(gDataOriginITS, "ITSTrackROF", 0, Lifetime::Timeframe);
1253 outputSpecs.emplace_back(gDataOriginITS, "VERTICES", 0, Lifetime::Timeframe);
1254 outputSpecs.emplace_back(gDataOriginITS, "VERTICESROF", 0, Lifetime::Timeframe);
1255 outputSpecs.emplace_back(gDataOriginITS, "IRFRAMES", 0, Lifetime::Timeframe);
1256
1257 if (mSpecConfig.processMC) {
1258 outputSpecs.emplace_back(gDataOriginITS, "VERTICESMCTR", 0, Lifetime::Timeframe);
1259 outputSpecs.emplace_back(gDataOriginITS, "TRACKSMCTR", 0, Lifetime::Timeframe);
1260 outputSpecs.emplace_back(gDataOriginITS, "ITSTrackMC2ROF", 0, Lifetime::Timeframe);
1261 }
1262 }
1263
1264 return outputSpecs;
1265};
1266
1268{
1269 ExitPipeline();
1270 mQA.reset(nullptr);
1271 mDisplayFrontend.reset(nullptr);
1272 mGPUReco.reset(nullptr);
1273}
1274
1275} // namespace o2::gpu
Simple interface to the CDB manager.
Definition of container class for dE/dx corrections.
Class of a TPC cluster in TPC-native coordinates (row, time)
Container to store compressed TPC cluster data.
A const (ready only) version of MCTruthContainer.
Helper class to access correction maps.
Helper class to access load maps from CCDB.
A parser and sequencer utility for raw pages within DPL input.
A raw page parser for DPL input.
Wrapper container for different reconstructed object types.
Definition of the TPC Digit.
Helper class for memory management of TPC Data Formats, external from the actual data type classes to...
Definition of class for writing debug informations.
Definition of the GeometryManager class.
int32_t i
int32_t retVal
Helper for geometry and GRP related CCDB requests.
Definition of the GeometryTGeo class.
A helper class to iteratate over all parts of all input routes.
Declarations for the wrapper for the set of cylindrical material layers.
Definition of the Names Generator class.
Utilities for parsing of data sequences.
uint32_t j
Definition RawData.h:0
Struct for input data required by TRD tracking workflow.
Type wrappers for enfording a specific serialization method.
class to create TPC fast transformation
Definition of TPCFastTransform class.
Wrapper class for TPC CA Tracker algorithm.
TBranch * ptr
Configurable params for tracks ad hoc tuning.
Helper class to extract VDrift from different sources.
Helper class to obtain TPC clusters / digits / labels from DPL.
Definitions of TPC Zero Suppression Data Headers.
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
static MatLayerCylSet * loadFromFile(const std::string &inpFName="matbud.root")
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:143
gsl::span< const TruthElement > getLabels(uint32_t dataindex) const
static mask_t getSourcesMask(const std::string_view srcList)
static constexpr std::string_view NONE
keywork for no sources
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
size_t flatten_to(ContainerType &container) const
static constexpr ID TPC
Definition DetID.h:64
This utility handles transparently the DPL inputs and triggers a customizable action on sequences of ...
void snapshot(const Output &spec, T const &object)
decltype(auto) make(const Output &spec, Args... args)
ServiceRegistryRef services()
Definition InitContext.h:34
A helper class to iteratate over all parts of all input routes.
int getPos(const char *name) const
decltype(auto) get(R binding, int part=0) const
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.
static GPUDisplayFrontendInterface * getFrontend(const char *type)
static uint32_t getTpcMaxTimeBinFromNHbf(uint32_t nHbf)
static float getNominalGPUBz(T &src)
o2::framework::Outputs outputs()
std::vector< framework::InputSpec > CompletionPolicyData
void init(o2::framework::InitContext &ic) final
void endOfStream(o2::framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
o2::framework::Inputs inputs()
void run(o2::framework::ProcessingContext &pc) final
void stop() final
This is invoked on stop.
void finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj) final
GPURecoWorkflowSpec(CompletionPolicyData *policyData, Config const &specconfig, std::vector< int32_t > const &tpcsectors, uint64_t tpcSectorMask, std::shared_ptr< o2::base::GRPGeomRequest > &ggr, std::function< bool(o2::framework::DataProcessingHeader::StartTime)> **gPolicyOrder=nullptr)
o2::framework::Options options()
static void RunZSEncoderCreateMeta(const uint64_t *buffer, const uint32_t *sizes, void **ptrs, GPUTrackingInOutZS *out)
static GeometryTGeo * Instance()
void fillMatrixCache(int mask) override
ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer ConstMCLabelContainerViewWithBuffer
static void addOptions(std::vector< o2::framework::ConfigParamSpec > &options)
static constexpr int MAXSECTOR
Definition Sector.h:44
static precheckModifiedData runPrecheck(o2::gpu::GPUTrackingInOutPointers *ptrs, o2::gpu::GPUO2InterfaceConfiguration *config)
static void requestCCDBInputs(std::vector< o2::framework::InputSpec > &inputs, bool laser=true, bool itstpcTgl=true)
static Geometry * instance()
Definition Geometry.h:33
GLint GLsizei count
Definition glcorearb.h:399
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
GLdouble GLdouble right
Definition glcorearb.h:4077
GLint left
Definition glcorearb.h:1979
GLboolean * data
Definition glcorearb.h:298
GLintptr offset
Definition glcorearb.h:660
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLuint start
Definition glcorearb.h:469
GLint ref
Definition glcorearb.h:291
GLint GLuint mask
Definition glcorearb.h:291
GLsizei GLenum * sources
Definition glcorearb.h:2516
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
constexpr o2::header::DataOrigin gDataOriginTRD
Definition DataHeader.h:577
constexpr o2::header::DataOrigin gDataOriginITS
Definition DataHeader.h:570
constexpr o2::header::DataOrigin gDataOriginGPU
Definition DataHeader.h:592
constexpr int NSectors
Definition of a container to keep/associate and arbitrary number of labels associated to an index wit...
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
o2::header::DataDescription DataDescription
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
std::vector< InputSpec > Inputs
std::vector< OutputSpec > Outputs
O2 data header classes and API, v0.1.
Definition DetID.h:49
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
Descriptor< gSizeDataDescriptionString > DataDescription
Definition DataHeader.h:551
constexpr int MAXGLOBALPADROW
Definition Constants.h:34
@ ZS
final Zero Suppression (can be ILBZS, DLBZS)
const std::unordered_map< CDBType, const std::string > CDBTypeMap
Storage name in CCDB for each calibration and parameter type.
Definition CDBTypes.h:95
@ FEEConfig
use fee config
@ IDCPadStatus
use idc pad status map
@ CalIDCPadStatusMapA
Status map of the pads (dead etc. obatined from CalIDC0)
@ CalPadGainFull
Full pad gain calibration.
@ CalPadGainResidual
ResidualpPad gain calibration (e.g. from tracks)
@ CalTimeGain
Gain variation over time.
@ CalTimeGainMC
Gain variation over time for MC.
@ AltroSyncSignal
timing of Altro chip sync. signal
auto getRecoInputContainer(o2::framework::ProcessingContext &pc, o2::gpu::GPUTrackingInOutPointers *ptrs, const o2::globaltracking::RecoContainer *inputTracks, bool mc=false)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
std::string filename()
size_t inputTimesliceId
The time pipelining id of this particular device.
Definition DeviceSpec.h:68
void requestTracks(o2::dataformats::GlobalTrackID::mask_t src, bool mc)
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
S< o2::trd::GeometryFlat >::type * trdGeometry
S< o2::base::PropagatorImpl< float > >::type * o2Propagator
S< o2::base::MatLayerCylSet >::type * matLUT
const std::vector< TGraphAsymmErrors > * hist4
std::function< void *(size_t)> allocator
std::array< const o2::dataformats::ConstMCTruthContainerView< o2::MCCompLabel > *, o2::tpc::constants::MAXSECTOR > v
const o2::tpc::Digit * tpcDigits[NSECTORS]
const GPUTPCDigitsMCInput * tpcDigitsMC
const o2::tpc::ClusterNativeAccess * clustersNative
const o2::tpc::CompressedClustersFlat * tpcCompressedClusters
const GPUSettingsTF * settingsTF
const GPUTrackingInOutZS * tpcZS
const o2::MCCompLabel * outputTracksTPCO2MC
const o2::tpc::TrackTPC * outputTracksTPCO2
const GPUTrackingInOutDigits * tpcPackedDigits
GPUTrackingInOutZSSector sector[NSECTORS]
static constexpr uint32_t NSECTORS
static constexpr uint32_t NENDPOINTS
GPUOutputControl * asArray()
GPUOutputControl tpcTracksO2Labels
GPUOutputControl tpcTracksO2ClusRefs
size_t getIndex(const GPUOutputControl &v)
static constexpr size_t count()
GPUOutputControl sharedClusterMap
GPUOutputControl compressedClusters
uint32_t SubSpecificationType
Definition DataHeader.h:620
static constexpr int T2L
Definition Cartesian.h:55
static constexpr int T2GRot
Definition Cartesian.h:57
static constexpr int T2G
Definition Cartesian.h:56
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int nClustersSector[constants::MAXSECTOR]
const o2::dataformats::ConstMCTruthContainerView< o2::MCCompLabel > * clustersMCTruth
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clustersLinear
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"