23#include <condition_variable>
54struct GPUReconstructionPipelineQueue {
58 std::condition_variable c;
65 std::queue<GPUReconstructionPipelineQueue*>
queue;
67 std::condition_variable
cond;
78static ptrdiff_t ptrDiff(
void*
a,
void*
b) {
return (
char*)
a - (
char*)
b; }
84 throw std::invalid_argument(
"device type of master and slave GPUReconstruction does not match");
87 throw std::invalid_argument(
"Cannot be slave to a slave");
103 mROOTDump = GPUROOTDumpCore::getAndCreate();
110 GPUError(
"GPU Reconstruction not properly deinitialized!");
114void GPUReconstruction::GetITSTraits(std::unique_ptr<o2::its::TrackerTraits>* trackerTraits, std::unique_ptr<o2::its::VertexerTraits>* vertexerTraits, std::unique_ptr<o2::its::TimeFrame>* timeFrame)
119 if (vertexerTraits) {
129 return std::max<int32_t>(0, tbb::this_task_arena::current_thread_index());
135 throw std::runtime_error(
"Must not call init on slave!");
141 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
144 GPUError(
"Error initialization slave (before deviceinit)");
163 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
171 GPUError(
"Error initialization slave (deviceinit)");
175 GPUError(
"Error initialization slave (permanent memory)");
186 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
191 GPUError(
"Error initialization slave (after device init)");
201static uint32_t getDefaultNThreads()
203 const char* tbbEnv = getenv(
"TBB_NUM_THREADS");
204 uint32_t tbbNum = tbbEnv ? atoi(tbbEnv) : 0;
208 const char* ompEnv = getenv(
"OMP_NUM_THREADS");
209 uint32_t ompNum = ompEnv ? atoi(ompEnv) : 0;
213 return tbb::info::default_concurrency();
221 printf(
"\nConfig Dump %s\n",
mMaster ?
"Slave" :
"Master");
224 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
268#ifndef GPUCA_DETERMINISTIC_MODE
269 GPUError(
"WARNING, deterministicGPUReconstruction needs GPUCA_DETERMINISTIC_MODE for being fully deterministic, without only most indeterminism by concurrency is removed, but floating point effects remain!");
273 if (
param().
rec.tpc.looperInterpolationInExtraPass == -1) {
274 param().
rec.tpc.looperInterpolationInExtraPass = 0;
281#ifdef GPUCA_DETERMINISTIC_MODE
282 GPUError(
"WARNING, compiled with GPUCA_DETERMINISTIC_MODE but deterministicGPUReconstruction not set, only compile-time determinism and deterministic math enforced, not fully deterministic!");
314 GPUFatal(
"Must not use both nHostThreads and ompThreads at the same time!");
317 GPUWarning(
"You are using the deprecated ompThreads option, please switch to nHostThreads!");
327 mThreading = std::make_shared<GPUReconstructionThreading>();
328 mThreading->control = std::make_unique<tbb::global_control>(tbb::global_control::max_allowed_parallelism,
mMaxHostThreads);
351 GPUError(
"Must use double pipeline mode only with exactly one chain that must support it");
360 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
364 mChains[
i]->RegisterPermanentMemoryAndProcessors();
365 size_t memPrimary, memPageLocked;
366 mChains[
i]->MemorySize(memPrimary, memPageLocked);
368 memPageLocked = memPrimary;
395 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
396 mChains[
i]->RegisterGPUProcessors();
408 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
433 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
444 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
446 GPUError(
"Error exiting slave");
475 auto& re = it->second;
476 if (proc ==
nullptr || re.proc == proc) {
478 resMain.mOverrideSize = 0;
479 for (uint32_t
i = 0;
i < re.res.size();
i++) {
481 resMain.mOverrideSize = std::max<size_t>(resMain.mOverrideSize, ptrDiff(
res.SetPointers((
void*)1), (
char*)1));
501 throw std::bad_alloc();
510 it->second.res.emplace_back(
retVal);
519 GPUInfo(
"Allocating memory %p", (
void*)proc);
532 GPUInfo(
"Allocating memory done");
540 GPUInfo(
"Allocating Permanent Memory");
543 GPUError(
"Must not allocate permanent memory while volatile chunks are allocated");
544 throw std::bad_alloc();
555 GPUInfo(
"Permanent Memory Done");
562 if (
res->mReuse >= 0) {
564 if (
ptr ==
nullptr) {
565 GPUError(
"Invalid reuse ptr (%s)",
res->mName);
566 throw std::bad_alloc();
571 throw std::bad_alloc();
574 std::cout <<
"Reused (" << device <<
") " <<
res->mName <<
": " <<
retVal <<
"\n";
578 if (memorypool ==
nullptr) {
579 GPUError(
"Cannot allocate memory from uninitialized pool");
580 throw std::bad_alloc();
584 retVal = ptrDiff((
res->*setPtr)((
char*)1), (
char*)(1));
585 memorypoolend = (
void*)((
char*)memorypoolend - GPUProcessor::getAlignmentMod<GPUCA_MEMALIGN>(memorypoolend));
586 if (retVal < res->mOverrideSize) {
589 retVal += GPUProcessor::getAlignment<GPUCA_MEMALIGN>(
retVal);
590 memorypoolend = (
char*)memorypoolend -
retVal;
595 memorypool = (
char*)((
res->*setPtr)(
ptr));
597 if (retVal < res->mOverrideSize) {
599 memorypool = (
char*)
ptr +
res->mOverrideSize;
601 memorypool = (
void*)((
char*)memorypool + GPUProcessor::getAlignment<GPUCA_MEMALIGN>(memorypool));
603 if (memorypoolend ? (memorypool > memorypoolend) : ((size_t)ptrDiff(memorypool, memorybase) > memorysize)) {
604 std::cerr <<
"Memory pool size exceeded (" << device <<
") (" <<
res->mName <<
": " << (memorypoolend ? (memorysize + ptrDiff(memorypool, memorypoolend)) : ptrDiff(memorypool, memorybase)) <<
" > " << memorysize <<
"\n";
605 throw std::bad_alloc();
608 std::cout <<
"Allocated (" << device <<
") " <<
res->mName <<
": " <<
retVal <<
" - available: " << (memorypoolend ? ptrDiff(memorypoolend, memorypool) : (memorysize - ptrDiff(memorypool, memorybase))) <<
"\n";
617 if (
res->mPtrDevice &&
res->mReuse < 0) {
620 res->mSize = std::max((
size_t)
res->SetPointers((
void*)1) - 1,
res->mOverrideSize);
621 if (
res->mReuse >= 0) {
623 GPUError(
"Invalid reuse, insufficient size: %ld < %ld", (int64_t)
mMemoryResources[
res->mReuse].mSize, (int64_t)
res->mSize);
624 throw std::bad_alloc();
630 res->mPtr = GPUProcessor::alignPointer<GPUCA_BUFFER_ALIGNMENT>(
res->mPtrDevice);
631 res->SetPointers(
res->mPtr);
633 std::cout << (
res->mReuse >= 0 ?
"Reused " :
"Allocated ") <<
res->mName <<
": " <<
res->mSize <<
"\n";
639 GPUError(
"Got buffer with insufficient alignment");
640 throw std::bad_alloc();
644 if (
res->mPtr !=
nullptr) {
645 GPUError(
"Double allocation! (%s)",
res->mName);
646 throw std::bad_alloc();
654 res->mSize = std::max((
size_t)
res->SetPointers((
void*)1) - 1,
res->mOverrideSize);
655 res->mPtr = control->
allocator(CAMath::nextMultipleOf<GPUCA_BUFFER_ALIGNMENT>(
res->mSize));
656 res->mSize = std::max<size_t>(ptrDiff(
res->SetPointers(
res->mPtr),
res->mPtr),
res->mOverrideSize);
658 std::cout <<
"Allocated (from callback) " <<
res->mName <<
": " <<
res->mSize <<
"\n";
661 void* dummy =
nullptr;
668 GPUError(
"Got buffer with insufficient alignment");
669 throw std::bad_alloc();
673 if (
res->mProcessor->mLinkedProcessor ==
nullptr) {
674 GPUError(
"Device Processor not set (%s)",
res->mName);
675 throw std::bad_alloc();
678 GPUError(
"Must not allocate non-stacked device memory while volatile chunks are allocated");
679 throw std::bad_alloc();
685 }
else if (
size !=
res->mSize) {
686 GPUError(
"Inconsistent device memory allocation (%s: device %lu vs %lu)",
res->mName,
size,
res->mSize);
687 throw std::bad_alloc();
690 GPUError(
"Got buffer with insufficient alignment");
691 throw std::bad_alloc();
711 return res->mReuse >= 0 ? 0 :
res->mSize;
727 throw std::runtime_error(
"Requested invalid memory typo for direct allocation");
730 GPUError(
"Must not allocate direct memory while volatile chunks are allocated");
731 throw std::bad_alloc();
738 poolend = (
char*)poolend -
size;
739 poolend = (
char*)poolend - GPUProcessor::getAlignmentMod<GPUCA_MEMALIGN>(poolend);
744 if (pool > poolend) {
745 GPUError(
"Insufficient unmanaged memory: missing %ld bytes", ptrDiff(pool, poolend));
746 throw std::bad_alloc();
767 throw std::bad_alloc();
824 size_t size = ptrDiff(
res->SetPointers(basePtr), basePtr);
825 if (basePtr &&
size > std::max(
res->mSize,
res->mOverrideSize)) {
826 std::cerr <<
"Updated pointers exceed available memory size: " <<
size <<
" > " << std::max(
res->mSize,
res->mOverrideSize) <<
" - host - " <<
res->mName <<
"\n";
827 throw std::bad_alloc();
832 size_t size = ptrDiff(
res->SetDevicePointers(basePtr), basePtr);
833 if (basePtr &&
size > std::max(
res->mSize,
res->mOverrideSize)) {
834 std::cerr <<
"Updated pointers exceed available memory size: " <<
size <<
" > " << std::max(
res->mSize,
res->mOverrideSize) <<
" - GPU - " <<
res->mName <<
"\n";
835 throw std::bad_alloc();
857 std::cout <<
"Freeing " <<
res->mName <<
": size " <<
res->mSize <<
" (reused " <<
res->mReuse <<
")\n";
863 res->mPtrDevice =
nullptr;
877 GPUFatal(
"Trying to pop memory state from empty stack");
892 if (
res->mReuse < 0) {
896 res->mPtrDevice =
nullptr;
906 throw std::runtime_error(
"temporary memory stack already blocked");
915 throw std::runtime_error(
"cannot unblock while there is stacked memory");
965 printf(
"Memory Allocation: Host %'13zd / %'13zu (Permanent %'13zd, Data %'13zd, Scratch %'13zd), Device %'13zd / %'13zu, (Permanent %'13zd, Data %'13zd, Scratch %'13zd) %zu chunks\n",
966 ptrDiff(
mHostMemoryPool,
mHostMemoryBase) + ptrDiff((
char*)
mHostMemoryBase +
mHostMemorySize,
mHostMemoryPoolEnd),
mHostMemorySize, ptrDiff(
mHostMemoryPermanent,
mHostMemoryBase), ptrDiff(
mHostMemoryPool,
mHostMemoryPermanent), ptrDiff((
char*)
mHostMemoryBase +
mHostMemorySize,
mHostMemoryPoolEnd),
967 ptrDiff(
mDeviceMemoryPool,
mDeviceMemoryBase) + ptrDiff((
char*)
mDeviceMemoryBase +
mDeviceMemorySize,
mDeviceMemoryPoolEnd),
mDeviceMemorySize, ptrDiff(
mDeviceMemoryPermanent,
mDeviceMemoryBase), ptrDiff(
mDeviceMemoryPool,
mDeviceMemoryPermanent), ptrDiff((
char*)
mDeviceMemoryBase +
mDeviceMemorySize,
mDeviceMemoryPoolEnd),
974 std::map<std::string, std::array<size_t, 3>>
sizes;
977 if (
res.mReuse >= 0) {
984 if (
res.mPtrDevice) {
991 printf(
"%59s CPU / %9s GPU\n",
"",
"");
992 for (
auto it =
sizes.begin(); it !=
sizes.end(); it++) {
993 printf(
"Allocation %30s %s: Size %'14zu / %'14zu\n", it->first.c_str(), it->second[2] ?
"P" :
" ", it->second[0], it->second[1]);
996 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
997 mChains[
i]->PrintMemoryStatistics();
1031constexpr static inline int32_t getStepNum(T step,
bool validCheck, int32_t N,
const char* err =
"Invalid step num")
1033 static_assert(
sizeof(step) ==
sizeof(uint32_t),
"Invalid step enum size");
1034 int32_t
retVal = 8 *
sizeof(uint32_t) - 1 - CAMath::Clz((uint32_t)step);
1035 if ((uint32_t)step == 0 ||
retVal >= N) {
1039 throw std::runtime_error(
"Invalid General Step");
1052 throw std::invalid_argument(
"Cannot start double pipeline mode");
1055 GPUInfo(
"Pipeline worker started");
1057 bool terminate =
false;
1058 while (!terminate) {
1063 GPUReconstructionPipelineQueue* q;
1072 q->retVal = q->chain->RunChain();
1075 std::lock_guard<std::mutex> lk(q->m);
1081 GPUInfo(
"Pipeline worker ended");
1094 std::unique_ptr<GPUReconstructionPipelineQueue> qu(
new GPUReconstructionPipelineQueue);
1095 GPUReconstructionPipelineQueue* q = qu.get();
1096 q->chain = terminate ? nullptr :
mChains[0].get();
1097 q->op = terminate ? 1 : 0;
1098 std::unique_lock<std::mutex> lkdone(q->m);
1102 throw std::runtime_error(
"Must not enqueue work after termination request");
1108 q->c.wait(lkdone, [&q]() {
return q->done; });
1115 return mChains[0]->FinalizePipelinedProcessing();
1129 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1148 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1166 throw std::runtime_error(
"GPU Backend Failure");
1175 f +=
"settings.dump";
1177 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1210 f +=
"settings.dump";
1216 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1239 GPUError(
"Cannot update settings while initialized");
1240 throw std::runtime_error(
"Settings updated while initialized");
1273 mAlloc = [&
r](
size_t n) {
return (
char*)
r->AllocateVolatileDeviceMemory(
n); };
#define GPUCA_BUFFER_ALIGNMENT
bool isSet(const bitfield &v) const
const GPUSettingsDisplay * GetEventDisplayConfig() const
const GPUSettingsQA * GetQAConfig() const
static void dumpConfig(const GPUSettingsRec *rec, const GPUSettingsProcessing *proc, const GPUSettingsQA *qa, const GPUSettingsDisplay *display, const GPUSettingsDeviceBackend *device, const GPURecoStepConfiguration *workflow)
static constexpr const char *const RECO_STEP_NAMES[]
static constexpr int32_t N_RECO_STEPS
static constexpr int32_t N_GENERAL_STEPS
void * SetDevicePointers(void *ptr)
void * SetPointers(void *ptr)
static void computePointerWithAlignment(T *&basePtr, S *&objPtr, size_t nEntries=1)
void InitGPUProcessor(GPUReconstruction *rec, ProcessorType type=PROCESSOR_TYPE_CPU, GPUProcessor *slaveProcessor=nullptr)
ProcessorType mGPUProcessorType
GPURecoStepConfiguration mRecoSteps
int32_t InitPhaseBeforeDevice()
std::unordered_set< const void * > mRegisteredMemoryPtrs
int32_t InitPhasePermanentMemory()
int16_t RegisterMemoryAllocationHelper(GPUProcessor *proc, void *(GPUProcessor::*setPtr)(void *), int32_t type, const char *name, const GPUMemoryReuse &re)
std::vector< std::unique_ptr< GPUChain > > mChains
GPUReconstruction * mMaster
void * AllocateVolatileMemory(size_t size, bool device)
ThrustVolatileAllocator getThrustVolatileDeviceAllocator()
std::unique_ptr< GPUMemorySizeScalers > mMemoryScalers
void AllocateRegisteredForeignMemory(int16_t res, GPUReconstruction *rec, GPUOutputControl *control=nullptr)
void SetInputControl(void *ptr, size_t size)
GPUConstantMem * mDeviceConstantMem
void ConstructGPUProcessor(GPUProcessor *proc)
void TerminatePipelineWorker()
std::shared_ptr< GPUROOTDumpCore > mROOTDump
void PopNonPersistentMemory(RecoStep step, uint64_t tag)
size_t AllocateRegisteredMemoryHelper(GPUMemoryResource *res, void *&ptr, void *&memorypool, void *memorybase, size_t memorysize, void *(GPUMemoryResource::*SetPointers)(void *), void *&memorypoolend, const char *device)
GPUConstantMem * processors()
void ReturnVolatileMemory()
const GPUSettingsDeviceBackend & GetDeviceBackendSettings() const
void ComputeReuseMax(GPUProcessor *proc)
void SetMemoryExternalInput(int16_t res, void *ptr)
int32_t getGeneralStepNum(GeneralStep step, bool validCheck=true)
static constexpr uint32_t NSECTORS
void MakeFutureDeviceMemoryAllocationsVolatile()
GPUOutputControl mInputControl
RecoStepField GetRecoStepsGPU() const
void SetResetTimers(bool reset)
void RegisterGPUDeviceProcessor(GPUProcessor *proc, GPUProcessor *slaveProcessor)
std::vector< GPUReconstruction * > mSlaves
std::vector< std::tuple< void *, void *, size_t, size_t, uint64_t > > mNonPersistentMemoryStack
std::unique_ptr< T > ReadStructFromFile(const char *file)
virtual void GetITSTraits(std::unique_ptr< o2::its::TrackerTraits > *trackerTraits, std::unique_ptr< o2::its::VertexerTraits > *vertexerTraits, std::unique_ptr< o2::its::TimeFrame > *timeFrame)
void UpdateDynamicSettings(const GPUSettingsRecDynamic *d)
std::unique_ptr< GPUSettingsDeviceBackend > mDeviceBackendSettings
std::vector< GPUMemoryResource > mMemoryResources
std::unique_ptr< GPUReconstructionPipelineContext > mPipelineContext
std::unique_ptr< GPUConstantMem > mHostConstantMem
size_t AllocateRegisteredPermanentMemory()
void ResetRegisteredMemoryPointers(GPUProcessor *proc)
void DumpStructToFile(const T *obj, const char *file)
void AllocateRegisteredMemoryInternal(GPUMemoryResource *res, GPUOutputControl *control, GPUReconstruction *recPool)
virtual int32_t registerMemoryForGPU_internal(const void *ptr, size_t size)=0
virtual size_t WriteToConstantMemory(size_t offset, const void *src, size_t size, int32_t stream=-1, gpu_reconstruction_kernels::deviceEvent *ev=nullptr)=0
std::unordered_map< GPUMemoryReuse::ID, MemoryReuseMeta > mMemoryReuse1to1
size_t mDeviceMemoryUsedMax
std::vector< ProcessorData > mProcessors
void ReturnVolatileDeviceMemory()
void * AllocateVolatileDeviceMemory(size_t size)
bool mDeviceMemoryAsVolatile
virtual int32_t InitDevice()=0
void SetSettings(float solenoidBzNominalGPU, const GPURecoStepConfiguration *workflow=nullptr)
virtual ~GPUReconstruction()
int32_t mMaxBackendThreads
const GPUCalibObjectsConst & GetCalib() const
const GPUTrackingInOutPointers GetIOPtrs() const
virtual std::unique_ptr< gpu_reconstruction_kernels::threadContext > GetThreadContext()=0
void UnblockStackedMemory()
GPUReconstruction(const GPUReconstruction &)=delete
static constexpr GeometryType geometryType
std::vector< std::unique_ptr< char[], alignedDeleter > > mNonPersistentIndividualDirectAllocations
void WriteConstantParams()
void FreeRegisteredMemory(GPUProcessor *proc, bool freeCustom=false, bool freePermanent=false)
std::vector< std::unique_ptr< char[], alignedDeleter > > mVolatileChunks
void UpdateMaxMemoryUsed()
virtual RecoStepField AvailableGPURecoSteps()
static constexpr const char *const IOTYPENAMES[]
std::vector< std::unique_ptr< char[], alignedDeleter > > mDirectMemoryChunks
void UpdateSettings(const GPUSettingsGRP *g, const GPUSettingsProcessing *p=nullptr, const GPUSettingsRecDynamic *d=nullptr)
DeviceType GetDeviceType() const
int32_t CheckErrorCodes(bool cpuOnly=false, bool forceShowErrors=false, std::vector< std::array< uint32_t, 4 > > *fillErrors=nullptr)
const GPUParam & GetParam() const
void ClearAllocatedMemory(bool clearOutputs=true)
static constexpr const char *const GEOMETRY_TYPE_NAMES[]
GPUOutputControl mOutputControl
size_t mHostMemoryUsedMax
void * mDeviceMemoryPoolEnd
virtual int32_t ExitDevice()=0
void PrintMemoryOverview()
std::unique_ptr< GPUSettingsGRP > mGRPSettings
std::unique_ptr< GPUSettingsProcessing > mProcessingSettings
virtual bool CanQueryMaxMemory()
void PrintMemoryStatistics()
void PushNonPersistentMemory(uint64_t tag)
int32_t getRecoStepNum(RecoStep step, bool validCheck=true)
virtual int32_t unregisterMemoryForGPU_internal(const void *ptr)=0
int32_t InitPhaseAfterDevice()
static int32_t getHostThreadIndex()
void * mDeviceMemoryPermanent
void BlockStackedMemory(GPUReconstruction *rec)
const GPUSettingsProcessing & GetProcessingSettings() const
void DumpSettings(const char *dir="")
void * AllocateDirectMemory(size_t size, int32_t type)
void * mHostMemoryPoolBlocked
int32_t unregisterMemoryForGPU(const void *ptr)
int32_t registerMemoryForGPU(const void *ptr, size_t size)
void SetDebugLevelTmp(int32_t level)
int32_t EnqueuePipeline(bool terminate=false)
std::shared_ptr< GPUReconstructionThreading > mThreading
std::vector< GPUMemoryResource * > mNonPersistentIndividualAllocations
void * mHostMemoryPoolEnd
void * mDeviceMemoryPoolBlocked
void * mVolatileMemoryStart
virtual int32_t GPUChkErrInternal(const int64_t error, const char *file, int32_t line) const
GPUChain * GetNextChainInQueue()
void * mHostMemoryPermanent
int32_t GPUChkErrA(const int64_t error, const char *file, int32_t line, bool failOnError)
size_t AllocateRegisteredMemory(GPUProcessor *proc, bool resetCustom=false)
int32_t ReadSettings(const char *dir="")
void SetOutputControl(const GPUOutputControl &v)
void SetSector(int32_t iSector)
#define TPC_MAX_FRAGMENT_LEN_GPU
#define TPC_MAX_FRAGMENT_LEN_HOST
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLint GLint GLsizei GLint GLenum GLenum type
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
std::unique_ptr< GPUDisplayFrontendInterface > eventDisplay
std::string qTag2Str(const T tag)
GPUTPCTracker tpcTrackers[GPUCA_NSECTORS]
GPUTPCClusterFinder tpcClusterer[GPUCA_NSECTORS]
GPUCalibObjectsConst calibObjects
GPUSettingsProcessing configProcessing
GPUSettingsO2 ReadConfigurableParam()
GPUSettingsRec configReconstruction
void set(void *p, size_t s)
std::function< void *(size_t)> allocator
void SetDefaults(float solenoidBz)
void UpdateSettings(const GPUSettingsGRP *g, const GPUSettingsProcessing *p=nullptr, const GPURecoStepConfiguration *w=nullptr, const GPUSettingsRecDynamic *d=nullptr)
GPUDataTypes::RecoStepField stepsGPUMask
GPUDataTypes::InOutTypeField outputs
GPUDataTypes::RecoStepField steps
GPUDataTypes::InOutTypeField inputs
std::condition_variable cond
std::queue< GPUReconstructionPipelineQueue * > queue
GPUReconstruction * master
float solenoidBzNominalGPU