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");
102 mROOTDump = GPUROOTDumpCore::getAndCreate();
109 GPUError(
"GPU Reconstruction not properly deinitialized!");
113void GPUReconstruction::GetITSTraits(std::unique_ptr<o2::its::TrackerTraits>* trackerTraits, std::unique_ptr<o2::its::VertexerTraits>* vertexerTraits, std::unique_ptr<o2::its::TimeFrame>* timeFrame)
118 if (vertexerTraits) {
128 return std::max<int32_t>(0, tbb::this_task_arena::current_thread_index());
134 throw std::runtime_error(
"Must not call init on slave!");
140 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
143 GPUError(
"Error initialization slave (before deviceinit)");
162 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
170 GPUError(
"Error initialization slave (deviceinit)");
174 GPUError(
"Error initialization slave (permanent memory)");
185 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
190 GPUError(
"Error initialization slave (after device init)");
200static uint32_t getDefaultNThreads()
202 const char* tbbEnv = getenv(
"TBB_NUM_THREADS");
203 uint32_t tbbNum = tbbEnv ? atoi(tbbEnv) : 0;
207 const char* ompEnv = getenv(
"OMP_NUM_THREADS");
208 uint32_t ompNum = ompEnv ? atoi(ompEnv) : 0;
212 return tbb::info::default_concurrency();
220 printf(
"\nConfig Dump %s\n",
mMaster ?
"Slave" :
"Master");
223 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
267#ifndef GPUCA_DETERMINISTIC_MODE
268 GPUError(
"WARNING, deterministicGPUReconstruction needs GPUCA_DETERMINISTIC_MODE for being fully deterministic, without only most indeterminism by concurrency is removed, but floating point effects remain!");
272 if (
param().
rec.tpc.looperInterpolationInExtraPass == -1) {
273 param().
rec.tpc.looperInterpolationInExtraPass = 0;
280#ifdef GPUCA_DETERMINISTIC_MODE
281 GPUError(
"WARNING, compiled with GPUCA_DETERMINISTIC_MODE but deterministicGPUReconstruction not set, only compile-time determinism and deterministic math enforced, not fully deterministic!");
313 GPUFatal(
"Must not use both nHostThreads and ompThreads at the same time!");
316 GPUWarning(
"You are using the deprecated ompThreads option, please switch to nHostThreads!");
326 mThreading = std::make_shared<GPUReconstructionThreading>();
327 mThreading->control = std::make_unique<tbb::global_control>(tbb::global_control::max_allowed_parallelism,
mMaxHostThreads);
350 GPUError(
"Must use double pipeline mode only with exactly one chain that must support it");
359 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
363 mChains[
i]->RegisterPermanentMemoryAndProcessors();
364 size_t memPrimary, memPageLocked;
365 mChains[
i]->MemorySize(memPrimary, memPageLocked);
367 memPageLocked = memPrimary;
394 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
395 mChains[
i]->RegisterGPUProcessors();
407 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
432 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
443 for (uint32_t
i = 0;
i <
mSlaves.size();
i++) {
445 GPUError(
"Error exiting slave");
474 auto& re = it->second;
475 if (proc ==
nullptr || re.proc == proc) {
477 resMain.mOverrideSize = 0;
478 for (uint32_t
i = 0;
i < re.res.size();
i++) {
480 resMain.mOverrideSize = std::max<size_t>(resMain.mOverrideSize, ptrDiff(
res.SetPointers((
void*)1), (
char*)1));
500 throw std::bad_alloc();
509 it->second.res.emplace_back(
retVal);
518 GPUInfo(
"Allocating memory %p", (
void*)proc);
531 GPUInfo(
"Allocating memory done");
539 GPUInfo(
"Allocating Permanent Memory");
542 GPUError(
"Must not allocate permanent memory while volatile chunks are allocated");
543 throw std::bad_alloc();
554 GPUInfo(
"Permanent Memory Done");
561 if (
res->mReuse >= 0) {
563 if (
ptr ==
nullptr) {
564 GPUError(
"Invalid reuse ptr (%s)",
res->mName);
565 throw std::bad_alloc();
570 throw std::bad_alloc();
573 std::cout <<
"Reused (" << device <<
") " <<
res->mName <<
": " <<
retVal <<
"\n";
577 if (memorypool ==
nullptr) {
578 GPUError(
"Cannot allocate memory from uninitialized pool");
579 throw std::bad_alloc();
583 retVal = ptrDiff((
res->*setPtr)((
char*)1), (
char*)(1));
584 memorypoolend = (
void*)((
char*)memorypoolend - GPUProcessor::getAlignmentMod<GPUCA_MEMALIGN>(memorypoolend));
585 if (retVal < res->mOverrideSize) {
588 retVal += GPUProcessor::getAlignment<GPUCA_MEMALIGN>(
retVal);
589 memorypoolend = (
char*)memorypoolend -
retVal;
594 memorypool = (
char*)((
res->*setPtr)(
ptr));
596 if (retVal < res->mOverrideSize) {
598 memorypool = (
char*)
ptr +
res->mOverrideSize;
600 memorypool = (
void*)((
char*)memorypool + GPUProcessor::getAlignment<GPUCA_MEMALIGN>(memorypool));
602 if (memorypoolend ? (memorypool > memorypoolend) : ((size_t)ptrDiff(memorypool, memorybase) > memorysize)) {
603 std::cerr <<
"Memory pool size exceeded (" << device <<
") (" <<
res->mName <<
": " << (memorypoolend ? (memorysize + ptrDiff(memorypool, memorypoolend)) : ptrDiff(memorypool, memorybase)) <<
" > " << memorysize <<
"\n";
604 throw std::bad_alloc();
607 std::cout <<
"Allocated (" << device <<
") " <<
res->mName <<
": " <<
retVal <<
" - available: " << (memorypoolend ? ptrDiff(memorypoolend, memorypool) : (memorysize - ptrDiff(memorypool, memorybase))) <<
"\n";
616 if (
res->mPtrDevice &&
res->mReuse < 0) {
619 res->mSize = std::max((
size_t)
res->SetPointers((
void*)1) - 1,
res->mOverrideSize);
620 if (
res->mReuse >= 0) {
622 GPUError(
"Invalid reuse, insufficient size: %ld < %ld", (int64_t)
mMemoryResources[
res->mReuse].mSize, (int64_t)
res->mSize);
623 throw std::bad_alloc();
629 res->mPtr = GPUProcessor::alignPointer<GPUCA_BUFFER_ALIGNMENT>(
res->mPtrDevice);
630 res->SetPointers(
res->mPtr);
632 std::cout << (
res->mReuse >= 0 ?
"Reused " :
"Allocated ") <<
res->mName <<
": " <<
res->mSize <<
"\n";
638 GPUError(
"Got buffer with insufficient alignment");
639 throw std::bad_alloc();
643 if (
res->mPtr !=
nullptr) {
644 GPUError(
"Double allocation! (%s)",
res->mName);
645 throw std::bad_alloc();
653 res->mSize = std::max((
size_t)
res->SetPointers((
void*)1) - 1,
res->mOverrideSize);
654 res->mPtr = control->
allocator(CAMath::nextMultipleOf<GPUCA_BUFFER_ALIGNMENT>(
res->mSize));
655 res->mSize = std::max<size_t>(ptrDiff(
res->SetPointers(
res->mPtr),
res->mPtr),
res->mOverrideSize);
657 std::cout <<
"Allocated (from callback) " <<
res->mName <<
": " <<
res->mSize <<
"\n";
660 void* dummy =
nullptr;
667 GPUError(
"Got buffer with insufficient alignment");
668 throw std::bad_alloc();
672 if (
res->mProcessor->mLinkedProcessor ==
nullptr) {
673 GPUError(
"Device Processor not set (%s)",
res->mName);
674 throw std::bad_alloc();
677 GPUError(
"Must not allocate non-stacked device memory while volatile chunks are allocated");
678 throw std::bad_alloc();
684 }
else if (
size !=
res->mSize) {
685 GPUError(
"Inconsistent device memory allocation (%s: device %lu vs %lu)",
res->mName,
size,
res->mSize);
686 throw std::bad_alloc();
689 GPUError(
"Got buffer with insufficient alignment");
690 throw std::bad_alloc();
710 return res->mReuse >= 0 ? 0 :
res->mSize;
726 throw std::runtime_error(
"Requested invalid memory typo for direct allocation");
729 GPUError(
"Must not allocate direct memory while volatile chunks are allocated");
730 throw std::bad_alloc();
737 poolend = (
char*)poolend -
size;
738 poolend = (
char*)poolend - GPUProcessor::getAlignmentMod<GPUCA_MEMALIGN>(poolend);
743 if (pool > poolend) {
744 GPUError(
"Insufficient unmanaged memory: missing %ld bytes", ptrDiff(pool, poolend));
745 throw std::bad_alloc();
766 throw std::bad_alloc();
823 size_t size = ptrDiff(
res->SetPointers(basePtr), basePtr);
824 if (basePtr &&
size > std::max(
res->mSize,
res->mOverrideSize)) {
825 std::cerr <<
"Updated pointers exceed available memory size: " <<
size <<
" > " << std::max(
res->mSize,
res->mOverrideSize) <<
" - host - " <<
res->mName <<
"\n";
826 throw std::bad_alloc();
831 size_t size = ptrDiff(
res->SetDevicePointers(basePtr), basePtr);
832 if (basePtr &&
size > std::max(
res->mSize,
res->mOverrideSize)) {
833 std::cerr <<
"Updated pointers exceed available memory size: " <<
size <<
" > " << std::max(
res->mSize,
res->mOverrideSize) <<
" - GPU - " <<
res->mName <<
"\n";
834 throw std::bad_alloc();
856 std::cout <<
"Freeing " <<
res->mName <<
": size " <<
res->mSize <<
" (reused " <<
res->mReuse <<
")\n";
862 res->mPtrDevice =
nullptr;
876 GPUFatal(
"Trying to pop memory state from empty stack");
891 if (
res->mReuse < 0) {
895 res->mPtrDevice =
nullptr;
905 throw std::runtime_error(
"temporary memory stack already blocked");
914 throw std::runtime_error(
"cannot unblock while there is stacked memory");
964 printf(
"Memory Allocation: Host %'13zd / %'13zu (Permanent %'13zd, Data %'13zd, Scratch %'13zd), Device %'13zd / %'13zu, (Permanent %'13zd, Data %'13zd, Scratch %'13zd) %zu chunks\n",
965 ptrDiff(
mHostMemoryPool,
mHostMemoryBase) + ptrDiff((
char*)
mHostMemoryBase +
mHostMemorySize,
mHostMemoryPoolEnd),
mHostMemorySize, ptrDiff(
mHostMemoryPermanent,
mHostMemoryBase), ptrDiff(
mHostMemoryPool,
mHostMemoryPermanent), ptrDiff((
char*)
mHostMemoryBase +
mHostMemorySize,
mHostMemoryPoolEnd),
966 ptrDiff(
mDeviceMemoryPool,
mDeviceMemoryBase) + ptrDiff((
char*)
mDeviceMemoryBase +
mDeviceMemorySize,
mDeviceMemoryPoolEnd),
mDeviceMemorySize, ptrDiff(
mDeviceMemoryPermanent,
mDeviceMemoryBase), ptrDiff(
mDeviceMemoryPool,
mDeviceMemoryPermanent), ptrDiff((
char*)
mDeviceMemoryBase +
mDeviceMemorySize,
mDeviceMemoryPoolEnd),
973 std::map<std::string, std::array<size_t, 3>>
sizes;
976 if (
res.mReuse >= 0) {
983 if (
res.mPtrDevice) {
990 printf(
"%59s CPU / %9s GPU\n",
"",
"");
991 for (
auto it =
sizes.begin(); it !=
sizes.end(); it++) {
992 printf(
"Allocation %30s %s: Size %'14zu / %'14zu\n", it->first.c_str(), it->second[2] ?
"P" :
" ", it->second[0], it->second[1]);
995 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
996 mChains[
i]->PrintMemoryStatistics();
1030constexpr static inline int32_t getStepNum(T step,
bool validCheck, int32_t N,
const char* err =
"Invalid step num")
1032 static_assert(
sizeof(step) ==
sizeof(uint32_t),
"Invalid step enum size");
1033 int32_t
retVal = 8 *
sizeof(uint32_t) - 1 - CAMath::Clz((uint32_t)step);
1034 if ((uint32_t)step == 0 ||
retVal >= N) {
1038 throw std::runtime_error(
"Invalid General Step");
1051 throw std::invalid_argument(
"Cannot start double pipeline mode");
1054 GPUInfo(
"Pipeline worker started");
1056 bool terminate =
false;
1057 while (!terminate) {
1062 GPUReconstructionPipelineQueue* q;
1071 q->retVal = q->chain->RunChain();
1074 std::lock_guard<std::mutex> lk(q->m);
1080 GPUInfo(
"Pipeline worker ended");
1093 std::unique_ptr<GPUReconstructionPipelineQueue> qu(
new GPUReconstructionPipelineQueue);
1094 GPUReconstructionPipelineQueue* q = qu.get();
1095 q->chain = terminate ? nullptr :
mChains[0].get();
1096 q->op = terminate ? 1 : 0;
1097 std::unique_lock<std::mutex> lkdone(q->m);
1101 throw std::runtime_error(
"Must not enqueue work after termination request");
1107 q->c.wait(lkdone, [&q]() {
return q->done; });
1114 return mChains[0]->FinalizePipelinedProcessing();
1128 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1147 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1165 throw std::runtime_error(
"GPU Backend Failure");
1174 f +=
"settings.dump";
1176 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1209 f +=
"settings.dump";
1215 for (uint32_t
i = 0;
i <
mChains.size();
i++) {
1238 GPUError(
"Cannot update settings while initialized");
1239 throw std::runtime_error(
"Settings updated while initialized");
1272 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