18#include <TObjString.h>
86#include <TStopwatch.h>
91#include <TGraphAsymmErrors.h>
103#include <unordered_set>
115GPURecoWorkflowSpec::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)
118 throw std::runtime_error(
"inconsistent configuration: cluster output is only possible if CA clusterer or CompCluster decompression is activated");
122 mConfParam.reset(
new GPUSettingsO2);
124 mTimer.reset(
new TStopwatch);
128 *gPolicyOrder = &mPolicyOrder;
140 mConfig->configGRP.solenoidBzNominalGPU = 0;
141 mTFSettings->hasSimStartOrbit = 1;
143 mTFSettings->simStartOrbit = hbfu.getFirstIRofTF(
o2::InteractionRecord(0, hbfu.orbitFirstSampled)).orbit;
145 *mConfParam = mConfig->ReadConfigurableParam();
147 if (mConfParam->display) {
149 mConfig->configProcessing.eventDisplay = mDisplayFrontend.get();
150 if (mConfig->configProcessing.eventDisplay !=
nullptr) {
151 LOG(info) <<
"Event display enabled";
153 throw std::runtime_error(
"GPU Event Display frontend could not be created!");
157 mConfig->configProcessing.doublePipeline = 1;
160 mAutoSolenoidBz = mConfParam->solenoidBzNominalGPU == -1e6f;
161 mAutoContinuousMaxTimeBin = mConfig->configGRP.grpContinuousMaxTimeBin < 0;
162 if (mAutoContinuousMaxTimeBin) {
165 if (mConfig->configProcessing.deviceNum == -2) {
168 mConfig->configProcessing.deviceNum = myId;
169 LOG(info) <<
"GPU device number selected from pipeline id: " << myId <<
" / " << idMax;
171 if (mConfig->configProcessing.debugLevel >= 3 && mVerbosity == 0) {
174 mConfig->configProcessing.runMC = mSpecConfig.
processMC;
176 if (!mSpecConfig.
processMC && !mConfig->configQA.clusterRejectionHistograms) {
177 throw std::runtime_error(
"Need MC information to create QA plots");
180 mConfig->configQA.noMC =
true;
182 mConfig->configQA.shipToQC =
true;
183 if (!mConfig->configProcessing.runQA) {
184 mConfig->configQA.enableLocalOutput =
false;
186 mConfig->configProcessing.runQA = -mQATaskMask;
189 mConfig->configInterface.outputToExternalBuffers =
true;
199 GPUO2Interface::ApplySyncSettings(mConfig->configProcessing, mConfig->configReconstruction, mConfig->configWorkflow.steps, mConfParam->synchronousProcessing, runTracking ? mConfParam->rundEdx : -2);
217 if (mTPCSectorMask != 0xFFFFFFFFF) {
218 throw std::invalid_argument(
"Cannot run TPC decompression with a sector mask");
231 mConfig->configProcessing.outputSharedClusterMap =
true;
234 mConfig->configProcessing.createO2Output = 0;
238 if (mConfParam->transformationFile.size() || mConfParam->transformationSCFile.size()) {
239 LOG(fatal) <<
"Deprecated configurable param options GPU_global.transformationFile or transformationSCFile used\n"
240 <<
"Instead, link the corresponding file as <somedir>/TPC/Calib/CorrectionMap/snapshot.root and use it via\n"
241 <<
"--condition-remap file://<somdir>=TPC/Calib/CorrectionMap option";
247 LOG(fatal) <<
"GPU two-threaded pipeline works only with TPC-only processing, and with ZS input";
251 mGPUReco = std::make_unique<GPUO2Interface>();
254 initFunctionTPCCalib(ic);
257 if (mConfig->configCalib.fastTransform ==
nullptr) {
258 throw std::invalid_argument(
"GPU workflow: initialization of the TPC transformation failed");
261 if (mConfParam->matLUTFile.size()) {
262 LOGP(info,
"Loading matlut file {}", mConfParam->matLUTFile.c_str());
264 if (mConfig->configCalib.matLUT ==
nullptr) {
265 LOGF(fatal,
"Error loading matlut file");
267 }
else if (mConfig->configProcessing.lateO2MatLutProvisioningSize <= 0) {
268 mConfig->configProcessing.lateO2MatLutProvisioningSize = 55 * 1024 * 1024;
272 mTRDGeometry = std::make_unique<o2::trd::GeometryFlat>();
273 mConfig->configCalib.trdGeometry = mTRDGeometry.get();
275 mTRDRecoParam = std::make_unique<GPUTRDRecoParam>();
276 mConfig->configCalib.trdRecoParam = mTRDRecoParam.get();
279 mConfig->configProcessing.willProvideO2PropagatorLate =
true;
280 mConfig->configProcessing.o2PropagatorUseGPUField =
true;
281 if (mConfig->configReconstruction.tpc.trackReferenceX == 1000.f) {
282 mConfig->configReconstruction.tpc.trackReferenceX = 83.f;
286 mConfig->configProcessing.printSettings =
true;
287 if (mConfParam->printSettings > 1) {
288 mConfig->PrintParam();
293 if (mGPUReco->Initialize(config) != 0) {
294 throw std::invalid_argument(
"GPU Reconstruction initialization failed");
297 mQA = std::make_unique<GPUO2InterfaceQA>(mConfig.get());
300 mGPUReco->setErrorCodeOutput(&mErrorQA);
311 if (mConfParam->dump >= 2) {
312 LOG(fatal) <<
"Cannot use dump-only mode with multi-threaded pipeline";
317 callbacks.
set<CallbackService::Id::RegionInfoCallback>([
this](fair::mq::RegionInfo
const& info) {
318 if (info.size == 0) {
322 mRegionInfos.emplace_back(info);
327 if (mConfParam->registerSelectedSegmentIds != -1 && info.managed && info.id != (uint32_t)mConfParam->registerSelectedSegmentIds) {
331 if (mConfParam->mutexMemReg) {
332 mode_t
mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
333 fd = open(
"/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC,
mask);
335 throw std::runtime_error(
"Error opening memlock mutex lock file");
338 if (lockf(fd, F_LOCK, 0)) {
339 throw std::runtime_error(
"Error locking memlock mutex file");
342 std::chrono::time_point<std::chrono::high_resolution_clock>
start,
end;
343 if (mConfParam->benchmarkMemoryRegistration) {
344 start = std::chrono::high_resolution_clock::now();
346 if (mGPUReco->registerMemoryForGPU(info.ptr, info.size)) {
347 throw std::runtime_error(
"Error registering memory for GPU");
349 if (mConfParam->benchmarkMemoryRegistration) {
350 end = std::chrono::high_resolution_clock::now();
351 std::chrono::duration<double> elapsed_seconds =
end -
start;
352 LOG(info) <<
"Memory registration time (0x" << info.ptr <<
", " << info.size <<
" bytes): " << elapsed_seconds.count() <<
" s";
354 if (mConfParam->mutexMemReg) {
355 if (lockf(fd, F_ULOCK, 0)) {
356 throw std::runtime_error(
"Error unlocking memlock mutex file");
368 LOGF(info,
"GPU Reconstruction total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer->CpuTime(), mTimer->RealTime(), mTimer->Counter() - 1);
369 handlePipelineStop();
374 if (mSpecConfig.
runITSTracking && mITSTrackingInterface !=
nullptr) {
375 mITSTrackingInterface->printSummary();
377 handlePipelineEndOfStream(ec);
383 finaliseCCDBTPC(matcher, obj);
385 finaliseCCDBITS(matcher, obj);
389 mGRPGeomUpdated =
true;
394template <
class D,
class E,
class F,
class G,
class H,
class I,
class J,
class K>
395void GPURecoWorkflowSpec::processInputs(
ProcessingContext& pc, D& tpcZSmeta, E& inputZS, F& tpcZS, G& tpcZSonTheFlySizes,
bool& debugTFDump, H& compClustersDummy, I& compClustersFlatDummy, J& pCompClustersFlat, K& tmpEmptyCompClusters)
406 tpcZSmeta.Pointers[
i][
j].clear();
407 tpcZSmeta.Sizes[
i][
j].clear();
412 tpcZSonTheFlySizes = {0};
415 bool recv =
false, recvsizes =
false;
418 throw std::runtime_error(
"Received multiple ZSSIZES data");
420 tpcZSonTheFlySizes = pc.
inputs().
get<std::array<uint32_t, NEndpoints * NSectors>>(
ref);
427 throw std::runtime_error(
"Received multiple TPCZS data");
429 inputZS = pc.
inputs().
get<gsl::span<o2::tpc::ZeroSuppressedContainer8kb>>(
ref);
432 if (!recv || !recvsizes) {
433 throw std::runtime_error(
"TPC ZS on the fly data not received");
438 uint32_t pageSector = 0;
439 for (uint32_t
j = 0;
j < NEndpoints;
j++) {
440 pageSector += tpcZSonTheFlySizes[
i * NEndpoints +
j];
441 offset += tpcZSonTheFlySizes[
i * NEndpoints +
j];
443 if (mVerbosity >= 1) {
444 LOG(info) <<
"GOT ZS on the fly pages FOR SECTOR " <<
i <<
" -> pages: " << pageSector;
450 auto isSameRdh = [](
const char*
left,
const char*
right) ->
bool {
451 return o2::raw::RDHUtils::getFEEID(
left) == o2::raw::RDHUtils::getFEEID(
right) && o2::raw::RDHUtils::getDetectorField(
left) == o2::raw::RDHUtils::getDetectorField(
right);
453 auto checkForZSData = [](
const char*
ptr, uint32_t subSpec) ->
bool {
454 const auto rdhLink = o2::raw::RDHUtils::getLinkID(
ptr);
455 const auto detField = o2::raw::RDHUtils::getDetectorField(
ptr);
456 const auto feeID = o2::raw::RDHUtils::getFEEID(
ptr);
457 const auto feeLinkID = o2::tpc::rdh_utils::getLink(feeID);
459 return detField ==
o2::tpc::raw_data_types::ZS && ((feeLinkID == o2::tpc::rdh_utils::UserLogicLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == 0)) ||
460 (feeLinkID == o2::tpc::rdh_utils::ILBZSLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == o2::tpc::rdh_utils::ILBZSLinkID || rdhLink == 0)) ||
461 (feeLinkID == o2::tpc::rdh_utils::DLBZSLinkID && (rdhLink == o2::tpc::rdh_utils::UserLogicLinkID || rdhLink == o2::tpc::rdh_utils::DLBZSLinkID || rdhLink == 0)));
463 auto insertPages = [&tpcZSmeta, checkForZSData](
const char*
ptr,
size_t count, uint32_t subSpec) ->
void {
464 if (checkForZSData(
ptr, subSpec)) {
465 int32_t rawcru = o2::tpc::rdh_utils::getCRU(
ptr);
466 int32_t rawendpoint = o2::tpc::rdh_utils::getEndPoint(
ptr);
467 tpcZSmeta.Pointers[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(
ptr);
468 tpcZSmeta.Sizes[rawcru / 10][(rawcru % 10) * 2 + rawendpoint].emplace_back(
count);
473 static uint32_t nErrors = 0;
475 if (nErrors == 1 || (nErrors < 100 && nErrors % 10 == 0) || nErrors % 1000 == 0 || mNTFs % 1000 == 0) {
476 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)";
480 int32_t totalCount = 0;
483 tpcZSmeta.Pointers2[
i][
j] = tpcZSmeta.Pointers[
i][
j].data();
484 tpcZSmeta.Sizes2[
i][
j] = tpcZSmeta.Sizes[
i][
j].data();
485 tpcZS.sector[
i].zsPtr[
j] = tpcZSmeta.Pointers2[
i][
j];
486 tpcZS.sector[
i].nZSPtr[
j] = tpcZSmeta.Sizes2[
i][
j];
487 tpcZS.sector[
i].count[
j] = tpcZSmeta.Pointers[
i][
j].size();
488 totalCount += tpcZSmeta.Pointers[
i][
j].size();
494 compClustersFlatDummy.setForward(&compClustersDummy);
495 pCompClustersFlat = &compClustersFlatDummy;
499 if (pCompClustersFlat ==
nullptr) {
506 LOGF(info,
"running tracking for sector(s) 0x%09x", mTPCSectorMask);
514 if (mConfParam->dump < 2) {
515 retVal = mGPUReco->RunTracking(ptrs, outputRegions, threadIndex, inputUpdateCallback);
518 retVal = runITSTracking(*pc);
523 mGPUReco->Clear(
false, threadIndex);
528void GPURecoWorkflowSpec::cleanOldCalibsTPCPtrs(calibObjectStruct& oldCalibObjects)
530 if (mOldCalibObjects.size() > 0) {
531 mOldCalibObjects.pop();
533 mOldCalibObjects.emplace(std::move(oldCalibObjects));
541 auto cput = mTimer->CpuTime();
542 auto realt = mTimer->RealTime();
543 mTimer->Start(
false);
546 std::vector<gsl::span<const char>>
inputs;
554 std::array<uint32_t, NEndpoints * NSectors> tpcZSonTheFlySizes;
555 gsl::span<const o2::tpc::ZeroSuppressedContainer8kb> inputZS;
556 std::unique_ptr<char[]> tmpEmptyCompClusters;
558 bool getWorkflowTPCInput_clusters =
false, getWorkflowTPCInput_mc =
false, getWorkflowTPCInput_digits =
false;
559 bool debugTFDump =
false;
562 getWorkflowTPCInput_mc =
true;
565 getWorkflowTPCInput_clusters =
true;
568 getWorkflowTPCInput_digits =
true;
573 auto lockDecodeInput = std::make_unique<std::lock_guard<std::mutex>>(mPipeline->mutexDecodeInput);
581 LOG(fatal) <<
"configKeyValue tpcTriggeredMode does not match GRP isDetContinuousReadOut(TPC) setting";
586 processInputs(pc, tpcZSmeta, inputZS, tpcZS, tpcZSonTheFlySizes, debugTFDump, compClustersDummy, compClustersFlatDummy, pCompClustersFlat, tmpEmptyCompClusters);
587 const auto& inputsClustersDigits = o2::tpc::getWorkflowTPCInput(pc, mVerbosity, getWorkflowTPCInput_mc, getWorkflowTPCInput_clusters, mTPCSectorMask, getWorkflowTPCInput_digits);
590 mTFSettings->tfStartOrbit = tinfo.firstTForbit;
591 mTFSettings->hasTfStartOrbit = 1;
592 mTFSettings->hasNHBFPerTF = 1;
594 mTFSettings->hasRunStartOrbit = 0;
599 LOG(info) <<
"TF firstTForbit " << mTFSettings->tfStartOrbit <<
" nHBF " << mTFSettings->nHBFPerTF <<
" runStartOrbit " << mTFSettings->runStartOrbit <<
" simStartOrbit " << mTFSettings->simStartOrbit;
601 if (mConfParam->checkFirstTfOrbit) {
602 static uint32_t lastFirstTFOrbit = -1;
603 static uint32_t lastTFCounter = -1;
604 if (lastFirstTFOrbit != -1 && lastTFCounter != -1) {
605 int32_t diffOrbit = tinfo.firstTForbit - lastFirstTFOrbit;
606 int32_t diffCounter = tinfo.tfCounter - lastTFCounter;
607 if (diffOrbit != diffCounter * mTFSettings->nHBFPerTF) {
608 LOG(error) <<
"Time frame has mismatching firstTfOrbit - Last orbit/counter: " << lastFirstTFOrbit <<
" " << lastTFCounter <<
" - Current: " << tinfo.firstTForbit <<
" " << tinfo.tfCounter;
611 lastFirstTFOrbit = tinfo.firstTForbit;
612 lastTFCounter = tinfo.tfCounter;
625 void* ptrEp[NSectors * NEndpoints] = {};
626 bool doInputDigits =
false, doInputDigitsMC =
false;
630 const uint64_t*
buffer =
reinterpret_cast<const uint64_t*
>(&inputZS[0]);
633 doInputDigits = doInputDigitsMC = mSpecConfig.
processMC;
637 throw std::runtime_error(
"Cannot process MC information, none available");
640 doInputDigits =
true;
646 if (mTPCSectorMask != 0xFFFFFFFFF) {
648 for (uint32_t
i = 0;
i < NSectors;
i++) {
649 if (!(mTPCSectorMask & (1ul <<
i))) {
665 if (doInputDigitsMC) {
668 for (uint32_t
i = 0;
i < NSectors;
i++) {
669 tpcDigitsMap.
tpcDigits[
i] = inputsClustersDigits->inputDigits[
i].data();
670 tpcDigitsMap.
nTPCDigits[
i] = inputsClustersDigits->inputDigits[
i].size();
671 if (doInputDigitsMC) {
672 tpcDigitsMapMC.
v[
i] = inputsClustersDigits->inputDigitsMCPtrs[
i];
678 if (mClusterOutputIds.size() > 0) {
679 clusterOutputSectorHeader.
sectorBits = mTPCSectorMask;
681 clusterOutputSectorHeader.activeSectors = mTPCSectorMask;
686 std::unique_ptr<GPURecoWorkflow_QueueObject> pipelineContext;
688 if (handlePipeline(pc, ptrs, tpcZSmeta, tpcZS, pipelineContext)) {
696 using outputDataType =
char;
698 using outputBufferType = std::pair<std::optional<std::reference_wrapper<outputBufferUninitializedVector>>, outputDataType*>;
700 std::unordered_set<std::string> outputsCreated;
702 auto setOutputAllocator = [
this, &outputBuffers, &outputRegions, &pc, &outputsCreated](
const char*
name,
bool condition,
GPUOutputControl& region,
auto&& outputSpec,
size_t offset = 0) {
705 if (mConfParam->allocateOutputOnTheFly) {
706 region.allocator = [
this,
name, &
buffer, &pc, outputSpec = std::move(outputSpec),
offset, &outputsCreated](
size_t size) ->
void* {
709 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);
711 std::chrono::time_point<std::chrono::high_resolution_clock>
start,
end;
713 start = std::chrono::high_resolution_clock::now();
716 outputsCreated.insert(
name);
718 end = std::chrono::high_resolution_clock::now();
719 std::chrono::duration<double> elapsed_seconds =
end -
start;
720 LOG(info) <<
"Allocation time for " <<
name <<
" (" <<
size <<
" bytes)"
721 <<
": " << elapsed_seconds.count() <<
"s";
729 outputsCreated.insert(
name);
734 auto downSizeBuffer = [](outputBufferType&
buffer,
size_t size) {
739 throw std::runtime_error(
"Invalid buffer size requested");
743 throw std::runtime_error(
"Inconsistent buffer address after downsize");
752 auto downSizeBufferToSpan = [&outputBuffers, &outputRegions, &downSizeBuffer](
GPUOutputControl& region,
auto span) {
757 if (span.size() &&
buffer.second != (
char*)span.data()) {
758 throw std::runtime_error(
"Buffer does not match span");
760 downSizeBuffer(
buffer, span.size() *
sizeof(*span.data()));
782 throw std::runtime_error(
"Invalid input for gpu tracking");
787 calibObjectStruct oldCalibObjects;
788 doCalibUpdates(pc, oldCalibObjects);
790 lockDecodeInput.reset();
792 uint32_t threadIndex;
793 if (mConfParam->dump) {
795 while (pipelineContext->jobThreadIndex == -1) {
797 threadIndex = pipelineContext->jobThreadIndex;
802 std::string dir =
"";
803 if (mConfParam->dumpFolder !=
"") {
804 dir = std::regex_replace(mConfParam->dumpFolder, std::regex(
"\\[P\\]"),
std::to_string(getpid()));
806 mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
811 mGPUReco->DumpSettings(threadIndex, dir.c_str());
813 if (tinfo.tfCounter >= mConfParam->dumpFirst && (mConfParam->dumpLast == -1 || tinfo.tfCounter <= mConfParam->dumpLast)) {
814 mGPUReco->DumpEvent(mNTFDumps, &ptrs, threadIndex, dir.c_str());
819 std::unique_ptr<GPUTrackingInOutPointers> ptrsDump;
820 if (mConfParam->dumpBadTFMode == 2) {
822 memcpy((
void*)ptrsDump.get(), (
const void*)&ptrs,
sizeof(ptrs));
827 if (!pipelineContext->jobSubmitted) {
828 enqueuePipelinedJob(&ptrs, &outputRegions, pipelineContext.get(),
true);
830 finalizeInputPipelinedJob(&ptrs, &outputRegions, pipelineContext.get());
832 std::unique_lock lk(pipelineContext->jobFinishedMutex);
833 pipelineContext->jobFinishedNotify.wait(lk, [context = pipelineContext.get()]() { return context->jobFinished; });
834 retVal = pipelineContext->jobReturnValue;
835 threadIndex = pipelineContext->jobThreadIndex;
838 threadIndex = mNextThreadIndex;
839 if (mConfig->configProcessing.doublePipeline) {
840 mNextThreadIndex = (mNextThreadIndex + 1) % 2;
843 retVal = runMain(&pc, &ptrs, &outputRegions, threadIndex);
848 cleanOldCalibsTPCPtrs(oldCalibObjects);
850 o2::utils::DebugStreamer::instance()->flush();
852 if (debugTFDump && mNDebugDumps < mConfParam->dumpBadTFs) {
854 if (mConfParam->dumpBadTFMode <= 1) {
856 FILE* fp = fopen(
filename.c_str(),
"w+b");
860 if (mConfParam->dumpBadTFMode == 1) {
864 fwrite(
data.data(), 1,
data.size(), fp);
867 }
else if (mConfParam->dumpBadTFMode == 2) {
868 mGPUReco->DumpEvent(mNDebugDumps - 1, ptrsDump.get(), threadIndex);
872 if (mConfParam->dump == 2) {
878 if (mConfig->configProcessing.tpcWriteClustersAfterRejection) {
881 bool createEmptyOutput =
false;
883 if (
retVal == 3 && mConfig->configProcessing.ignoreNonFatalGPUErrors) {
884 if (mConfig->configProcessing.throttleAlarms) {
885 LOG(warning) <<
"GPU Reconstruction aborted with non fatal error code, ignoring";
887 LOG(alarm) <<
"GPU Reconstruction aborted with non fatal error code, ignoring";
889 createEmptyOutput = !mConfParam->partialOutputForNonFatalErrors;
891 LOG(fatal) <<
"GPU Reconstruction aborted with error code " <<
retVal <<
" - errors are not ignored - terminating";
895 std::unique_ptr<o2::tpc::ClusterNativeAccess> tmpEmptyClNative;
896 if (createEmptyOutput) {
897 memset(&ptrs, 0,
sizeof(ptrs));
898 for (uint32_t
i = 0;
i < outputRegions.
count();
i++) {
899 if (outputBuffers[
i].
first) {
906 outputBuffers[
i].first->get().resize(toSize);
907 outputBuffers[
i].second = outputBuffers[
i].first->get().data();
909 memset(outputBuffers[
i].second, 0, toSize);
913 tmpEmptyClNative = std::make_unique<o2::tpc::ClusterNativeAccess>();
914 memset(tmpEmptyClNative.get(), 0,
sizeof(*tmpEmptyClNative));
919 clustersMCBuffer.second = clustersMCBuffer.first;
920 tmpEmptyClNative->clustersMCTruth = &clustersMCBuffer.second;
926 if (!mConfParam->allocateOutputOnTheFly) {
927 for (uint32_t
i = 0;
i < outputRegions.
count();
i++) {
930 throw std::runtime_error(
"Preallocated buffer size exceeded");
933 downSizeBuffer(outputBuffers[
i], (
char*)outputRegions.
asArray()[
i].
ptrCurrent - (
char*)outputBuffers[
i].second);
937 downSizeBufferToSpan(outputRegions.
tpcTracksO2, spanOutputTracks);
943 doTrackTuneTPC(ptrs, outputBuffers[outputRegions.
getIndex(outputRegions.
tpcTracksO2)].first->get().data());
947 throw std::runtime_error(
"cluster native output ptrs out of sync");
960 if (mClusterOutputIds.size() > 0) {
964 for (uint32_t
i = 0;
i < NSectors;
i++) {
965 if (mTPCSectorMask & (1ul <<
i)) {
967 clusterOutputSectorHeader.sectorBits = (1ul <<
i);
970 memset(outIndex, 0,
sizeof(*outIndex));
1003 auto getoutput = [sendQAOutput](
auto ptr) {
return sendQAOutput &&
ptr ? *
ptr : std::decay_t<decltype(*ptr)>(); };
1004 std::vector<TH1F> copy1 = getoutput(outputRegions.
qa.
hist1);
1005 std::vector<TH2F> copy2 = getoutput(outputRegions.
qa.
hist2);
1006 std::vector<TH1D> copy3 = getoutput(outputRegions.
qa.
hist3);
1007 std::vector<TGraphAsymmErrors> copy4 = getoutput(outputRegions.
qa.
hist4);
1009 mQA->postprocessExternal(copy1, copy2, copy3, copy4, out, mQATaskMask ? mQATaskMask : -1);
1027 LOG(info) <<
"GPU Reconstruction time for this TF " << mTimer->CpuTime() - cput <<
" s (cpu), " << mTimer->RealTime() - realt <<
" s (wall)";
1035 md.SetOwnerKeyValue();
1036 md.Add(
new TObjString(o2::gpu::internal::GPUConfigurableParamGPUSettingsRecTPC::Instance().
getName().c_str()),
new TObjString(
o2::conf::ConfigurableParam::asJSON(o2::gpu::internal::GPUConfigurableParamGPUSettingsRecTPC::Instance().
getName()).c_str()));
1037 md.Add(
new TObjString(o2::gpu::internal::GPUConfigurableParamGPUSettingsRec::Instance().
getName().c_str()),
new TObjString(
o2::conf::ConfigurableParam::asJSON(o2::gpu::internal::GPUConfigurableParamGPUSettingsRec::Instance().
getName()).c_str()));
1038 md.Add(
new TObjString(o2::gpu::internal::GPUConfigurableParamGPUSettingsProcessingParam::Instance().
getName().c_str()),
new TObjString(
o2::conf::ConfigurableParam::asJSON(o2::gpu::internal::GPUConfigurableParamGPUSettingsProcessingParam::Instance().
getName()).c_str()));
1039 md.Add(
new TObjString(o2::gpu::internal::GPUConfigurableParamGPUSettingsProcessing::Instance().
getName().c_str()),
new TObjString(
o2::conf::ConfigurableParam::asJSON(o2::gpu::internal::GPUConfigurableParamGPUSettingsProcessing::Instance().
getName()).c_str()));
1040 md.Add(
new TObjString(o2::gpu::internal::GPUConfigurableParamGPUSettingsO2::Instance().
getName().c_str()),
new TObjString(
o2::conf::ConfigurableParam::asJSON(o2::gpu::internal::GPUConfigurableParamGPUSettingsO2::Instance().
getName()).c_str()));
1058 bool needCalibUpdate =
false;
1059 if (mGRPGeomUpdated) {
1060 mGRPGeomUpdated =
false;
1061 needCalibUpdate =
true;
1066 mITSGeometryCreated =
true;
1069 if (mAutoSolenoidBz) {
1075 if (mAutoContinuousMaxTimeBin) {
1078 LOG(info) <<
"Updating max time bin " << newCalibValues.
continuousMaxTimeBin <<
" (" << mTFSettings->nHBFPerTF <<
" orbits)";
1081 if (!mPropagatorInstanceCreated) {
1083 if (mConfig->configProcessing.o2PropagatorUseGPUField) {
1086 mPropagatorInstanceCreated =
true;
1089 if (!mMatLUTCreated) {
1090 if (mConfParam->matLUTFile.size() == 0) {
1092 LOG(info) <<
"Loaded material budget lookup table";
1094 mMatLUTCreated =
true;
1097 if (!mTRDGeometryCreated) {
1099 gm->createPadPlaneArray();
1100 gm->createClusterMatrixArray();
1101 mTRDGeometry = std::make_unique<o2::trd::GeometryFlat>(*gm);
1102 newCalibObjects.
trdGeometry = mConfig->configCalib.trdGeometry = mTRDGeometry.get();
1103 LOG(info) <<
"Loaded TRD geometry";
1104 mTRDGeometryCreated =
true;
1106 if (!mTRDRecoParamCreated) {
1107 mTRDRecoParam = std::make_unique<GPUTRDRecoParam>();
1108 newCalibObjects.
trdRecoParam = mConfig->configCalib.trdRecoParam = mTRDRecoParam.get();
1109 mTRDRecoParamCreated =
true;
1113 needCalibUpdate = fetchCalibsCCDBTPC(pc, newCalibObjects, oldCalibObjects) || needCalibUpdate;
1115 needCalibUpdate = fetchCalibsCCDBITS(pc) || needCalibUpdate;
1117 if (mTPCCutAtTimeBin != mConfig->configGRP.tpcCutTimeBin) {
1119 newCalibValues.
tpcTimeBinCut = mConfig->configGRP.tpcCutTimeBin = mTPCCutAtTimeBin;
1120 needCalibUpdate =
true;
1124 std::ofstream out(
path, std::ios::binary | std::ios::trunc);
1125 if (!out.is_open()) {
1126 throw std::runtime_error(
"Failed to open output file: " +
path);
1129 out.write(
buffer,
static_cast<std::streamsize
>(validSize));
1131 throw std::runtime_error(
"Failed while writing data to: " +
path);
1134 for (
int i = 0;
i < 3;
i++) {
1139 LOG(info) <<
"Dumped TPC clusterizer NN " <<
i <<
" to file " <<
path;
1143 if (needCalibUpdate) {
1144 LOG(info) <<
"Updating GPUReconstruction calibration objects";
1145 mGPUReco->UpdateCalibration(newCalibObjects, newCalibValues);
1154 char* o2jobid = getenv(
"O2JOBID");
1155 char* numaid = getenv(
"NUMAID");
1156 int32_t chanid = o2jobid ? atoi(o2jobid) : (numaid ? atoi(numaid) : 0);
1157 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";
1174 inputs.emplace_back(
"stdDist",
"FLP",
"DISTSUBTIMEFRAME", 0, Lifetime::Timeframe);
1179 LOG(fatal) <<
"Double pipeline mode can only work with zsraw input";
1183 inputs.emplace_back(
"pipelineprepare",
gDataOriginGPU,
"PIPELINEPREPARE", 0, Lifetime::Timeframe);
1193 if (mapSources != 0) {
1253 for (
unsigned int iLay{0}; iLay < (mSpecConfig.
itsStaggered ? 7 : 1); ++iLay) {
1254 inputs.emplace_back(
"compClusters",
"ITS",
"COMPCLUSTERS", iLay, Lifetime::Timeframe);
1255 inputs.emplace_back(
"patterns",
"ITS",
"PATTERNS", iLay, Lifetime::Timeframe);
1256 inputs.emplace_back(
"ROframes",
"ITS",
"CLUSTERSROF", iLay, Lifetime::Timeframe);
1258 inputs.emplace_back(
"itsmclabels",
"ITS",
"CLUSTERSMCTR", iLay, Lifetime::Timeframe);
1262 inputs.emplace_back(
"phystrig",
"ITS",
"PHYSTRIG", 0, Lifetime::Timeframe);
1264 inputs.emplace_back(
"phystrig",
"TRD",
"TRKTRGRD", 0, Lifetime::Timeframe);
1267 if (mSpecConfig.
isITS3) {
1268 inputs.emplace_back(
"cldict",
"IT3",
"CLUSDICT", 0, Lifetime::Condition,
ccdbParamSpec(
"IT3/Calib/ClusterDictionary"));
1269 inputs.emplace_back(
"alppar",
"ITS",
"ALPIDEPARAM", 0, Lifetime::Condition,
ccdbParamSpec(
"ITS/Config/AlpideParam"));
1271 inputs.emplace_back(
"itscldict",
"ITS",
"CLUSDICT", 0, Lifetime::Condition,
ccdbParamSpec(
"ITS/Calib/ClusterDictionary"));
1272 inputs.emplace_back(
"itsalppar",
"ITS",
"ALPIDEPARAM", 0, Lifetime::Condition,
ccdbParamSpec(
"ITS/Config/AlpideParam"));
1275 inputs.emplace_back(
"meanvtx",
"GLO",
"MEANVERTEX", 0, Lifetime::Condition,
ccdbParamSpec(
"GLO/Calib/MeanVertex", {}, 1));
1281 *mConfParam = mConfig->ReadConfigurableParam();
1282 if (mConfig->configProcessing.nn.nnLoadFromCCDB) {
1284 LOG(info) <<
"(NN CLUS) Enabling fetching of TPC NN clusterizer from CCDB";
1286 mSpecConfig.
nnDumpToFile = mConfig->configProcessing.nn.nnCCDBDumpToFile;
1287 GPUSettingsProcessingNNclusterizer& nnClusterizerSettings = mConfig->configProcessing.nn;
1289 std::map<std::string, std::string> metadata;
1290 metadata[
"inputDType"] = nnClusterizerSettings.nnInferenceInputDType;
1291 metadata[
"outputDType"] = nnClusterizerSettings.nnInferenceOutputDType;
1292 metadata[
"nnCCDBWithMomentum"] = nnClusterizerSettings.nnCCDBWithMomentum;
1293 metadata[
"nnCCDBLayerType"] = nnClusterizerSettings.nnCCDBClassificationLayerType;
1294 metadata[
"nnCCDBInteractionRate"] = nnClusterizerSettings.nnCCDBInteractionRate;
1295 metadata[
"nnCCDBBeamType"] = nnClusterizerSettings.nnCCDBBeamType;
1296 metadata[
"nnCCDBExtraMetadata"] = nnClusterizerSettings.nnCCDBExtraMetadata;
1298 auto convert_map_to_metadata = [](
const std::map<std::string, std::string>& inputMap, std::vector<o2::framework::CCDBMetadata>& outputMetadata) {
1299 for (
const auto& [
key,
value] : inputMap) {
1301 outputMetadata.push_back({
key,
value});
1307 std::vector<o2::framework::CCDBMetadata> ccdb_metadata;
1309 if (mConfParam->printSettings) {
1310 auto printSettings = [](
const std::map<std::string, std::string>& settings) {
1311 LOG(info) <<
"(NN CLUS) NN Clusterizer CCDB settings:";
1312 for (
const auto& [
key,
value] : settings) {
1316 printSettings(metadata);
1320 metadata[
"nnCCDBEvalType"] =
"classification_c1";
1321 convert_map_to_metadata(metadata, ccdb_metadata);
1322 inputs.emplace_back(
"nn_classification_c1",
gDataOriginTPC,
"NNCLUSTERIZER_C1", 0, Lifetime::Condition,
ccdbParamSpec(nnClusterizerSettings.nnCCDBPath +
"/" + metadata[
"nnCCDBEvalType"], ccdb_metadata, 0));
1323 }
else if (mSpecConfig.
nnEvalMode[0] ==
"c2") {
1324 metadata[
"nnCCDBLayerType"] = nnClusterizerSettings.nnCCDBRegressionLayerType;
1325 metadata[
"nnCCDBEvalType"] =
"classification_c2";
1326 convert_map_to_metadata(metadata, ccdb_metadata);
1327 inputs.emplace_back(
"nn_classification_c2",
gDataOriginTPC,
"NNCLUSTERIZER_C2", 0, Lifetime::Condition,
ccdbParamSpec(nnClusterizerSettings.nnCCDBPath +
"/" + metadata[
"nnCCDBEvalType"], ccdb_metadata, 0));
1330 metadata[
"nnCCDBEvalType"] =
"regression_c1";
1331 metadata[
"nnCCDBLayerType"] = nnClusterizerSettings.nnCCDBRegressionLayerType;
1332 convert_map_to_metadata(metadata, ccdb_metadata);
1333 inputs.emplace_back(
"nn_regression_c1",
gDataOriginTPC,
"NNCLUSTERIZER_R1", 0, Lifetime::Condition,
ccdbParamSpec(nnClusterizerSettings.nnCCDBPath +
"/" + metadata[
"nnCCDBEvalType"], ccdb_metadata, 0));
1336 metadata[
"nnCCDBEvalType"] =
"regression_c2";
1337 convert_map_to_metadata(metadata, ccdb_metadata);
1338 inputs.emplace_back(
"nn_regression_c2",
gDataOriginTPC,
"NNCLUSTERIZER_R2", 0, Lifetime::Condition,
ccdbParamSpec(nnClusterizerSettings.nnCCDBPath +
"/" + metadata[
"nnCCDBEvalType"], ccdb_metadata, 0));
1348 std::vector<OutputSpec> outputSpecs;
1350 outputSpecs.emplace_back(
gDataOriginGPU,
"PIPELINEPREPARE", 0, Lifetime::Timeframe);
1361 outputSpecs.emplace_back(
gDataOriginTPC,
"COMPCLUSTERS", 0, Lifetime::Timeframe);
1364 outputSpecs.emplace_back(
gDataOriginTPC,
"COMPCLUSTERSFLAT", 0, Lifetime::Timeframe);
1367 for (
auto const& sector : mTPCSectors) {
1368 mClusterOutputIds.emplace_back(sector);
1371 outputSpecs.emplace_back(
gDataOriginTPC,
"CLUSTERNATIVETMP", NSectors, Lifetime::Timeframe);
1372 for (
const auto sector : mTPCSectors) {
1380 for (
const auto sector : mTPCSectors) {
1389 outputSpecs.emplace_back(
gDataOriginTPC,
"CLSHAREDMAP", 0, Lifetime::Timeframe);
1390 outputSpecs.emplace_back(
gDataOriginTPC,
"TPCOCCUPANCYMAP", 0, Lifetime::Timeframe);
1393 outputSpecs.emplace_back(
gDataOriginTPC,
"TRIGGERWORDS", 0, Lifetime::Timeframe);
1396 outputSpecs.emplace_back(
gDataOriginTPC,
"TRACKINGQA", 0, Lifetime::Timeframe);
1399 outputSpecs.emplace_back(
gDataOriginGPU,
"ERRORQA", 0, Lifetime::Timeframe);
1401 outputSpecs.emplace_back(
"META",
"GPUTRACKER", 0, Lifetime::Sporadic);
1404 outputSpecs.emplace_back(
gDataOriginITS,
"TRACKS", 0, Lifetime::Timeframe);
1405 outputSpecs.emplace_back(
gDataOriginITS,
"TRACKCLSID", 0, Lifetime::Timeframe);
1406 outputSpecs.emplace_back(
gDataOriginITS,
"ITSTrackROF", 0, Lifetime::Timeframe);
1407 outputSpecs.emplace_back(
gDataOriginITS,
"VERTICES", 0, Lifetime::Timeframe);
1408 outputSpecs.emplace_back(
gDataOriginITS,
"VERTICESROF", 0, Lifetime::Timeframe);
1409 outputSpecs.emplace_back(
gDataOriginITS,
"IRFRAMES", 0, Lifetime::Timeframe);
1412 outputSpecs.emplace_back(
gDataOriginITS,
"VERTICESMCTR", 0, Lifetime::Timeframe);
1413 outputSpecs.emplace_back(
gDataOriginITS,
"VERTICESMCPUR", 0, Lifetime::Timeframe);
1414 outputSpecs.emplace_back(
gDataOriginITS,
"TRACKSMCTR", 0, Lifetime::Timeframe);
1425 mDisplayFrontend.reset(
nullptr);
1426 mGPUReco.reset(
nullptr);
std::vector< std::string > labels
Simple interface to the CDB manager.
Definition of container class for dE/dx corrections.
void dumpToFile(std::string fileName, const CathodeSegmentation &seg, const std::vector< Point > &points)
Class of a TPC cluster in TPC-native coordinates (row, time)
Container to store compressed TPC cluster data.
std::string getName(const TDataMember *dm, int index, int size)
A const (ready only) version of MCTruthContainer.
A parser and sequencer utility for raw pages within DPL input.
A raw page parser for DPL input.
Definition of class for writing debug informations.
Definition of the GeometryManager class.
Helper for geometry and GRP related CCDB requests.
Definition of the GeometryTGeo class.
Declarations for the wrapper for the set of cylindrical material layers.
Definition of the Names Generator class.
Class to serialize ONNX objects for ROOT snapshots of CCDB objects at runtime.
Type wrappers for enfording a specific serialization method.
Wrapper class for TPC CA Tracker algorithm.
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")
static std::string getConfigOutputFileName(const std::string &procName, const std::string &confName="", bool json=true)
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
static const HBFUtils & Instance()
static std::string asJSON(std::string const &keyOnly="")
static void write(std::string const &filename, std::string const &keyOnly="")
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()
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)
static void ApplySyncSettings(GPUSettingsProcessing &proc, GPUSettingsRec &rec, gpudatatypes::RecoStepField &steps, bool syncMode, int32_t dEdxMode=-2)
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.
~GPURecoWorkflowSpec() override
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 constexpr int MAXSECTOR
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()
GLuint const GLchar * name
GLsizei const GLfloat * value
GLuint GLsizei const GLchar * label
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLsizei const GLchar *const * path
constexpr o2::header::DataOrigin gDataOriginCTP
constexpr o2::header::DataOrigin gDataOriginTPC
constexpr o2::header::DataOrigin gDataOriginTRD
constexpr o2::header::DataOrigin gDataOriginITS
constexpr o2::header::DataOrigin gDataOriginGPU
Defining ITS Vertex explicitly as messageable.
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
constexpr int MAXGLOBALPADROW
@ 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.
@ 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)
std::string name
The name of the associated DataProcessorSpec.
size_t inputTimesliceId
The time pipelining id of this particular device.
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< GPUTRDRecoParam >::type * trdRecoParam
S< o2::base::PropagatorImpl< float > >::type * o2Propagator
S< o2::base::MatLayerCylSet >::type * matLUT
S< o2::tpc::ORTRootSerializer >::type * nnClusterizerNetworks[3]
const std::vector< TH1F > * hist1
const std::vector< TGraphAsymmErrors > * hist4
const std::vector< TH1D > * hist3
const std::vector< TH2F > * hist2
bool newContinuousMaxTimeBin
uint32_t continuousMaxTimeBin
GPUSettingsProcessing configProcessing
std::function< void *(size_t)> allocator
std::vector< std::string > nnEvalMode
int32_t tpcDeadMapSources
bool decompressTPCFromROOT
bool outputCompClustersRoot
bool sendClustersPerSector
int32_t enableDoublePipeline
bool outputSharedClusterMap
bool useFilteredOutputSpecs
bool outputCompClustersFlat
const o2::tpc::Digit * tpcDigits[NSECTORS]
size_t nTPCDigits[NSECTORS]
const GPUTPCDigitsMCInput * tpcDigitsMC
const o2::tpc::ClusterNativeAccess * clustersNative
const o2::tpc::CompressedClustersFlat * tpcCompressedClusters
const uint32_t * outputClusRefsTPCO2
const GPUSettingsTF * settingsTF
const GPUTrackingInOutZS * tpcZS
const o2::MCCompLabel * outputTracksTPCO2MC
uint32_t nOutputTracksTPCO2
const o2::tpc::ClusterNativeAccess * clustersNativeReduced
uint32_t nOutputClusRefsTPCO2
const o2::tpc::TrackTPC * outputTracksTPCO2
const GPUTrackingInOutDigits * tpcPackedDigits
const void *const * zsPtr[NENDPOINTS]
uint32_t count[NENDPOINTS]
const uint32_t * nZSPtr[NENDPOINTS]
GPUTrackingInOutZSSector sector[NSECTORS]
static constexpr uint32_t NSECTORS
static constexpr uint32_t NENDPOINTS
GPUOutputControl tpcTracksO2
GPUOutputControl clustersNative
GPUOutputControl tpcOccupancyMap
GPUOutputControl * asArray()
GPUOutputControl tpcTracksO2Labels
GPUOutputControl tpcTracksO2ClusRefs
size_t getIndex(const GPUOutputControl &v)
static constexpr size_t count()
GPUOutputControl sharedClusterMap
GPUOutputControl compressedClusters
GPUOutputControl clusterLabels
GPUOutputControl tpcTriggerWords
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
static std::vector< std::string > tokenize(const std::string &src, char delim, bool trimToken=true, bool skipEmpty=true)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"