Skip to content

Commit ab76552

Browse files
committed
GPU: Use double-pipeline within DPL
1 parent 71cc61c commit ab76552

4 files changed

Lines changed: 147 additions & 106 deletions

File tree

GPU/GPUTracking/Interface/GPUO2Interface.cxx

Lines changed: 87 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#include "CalibdEdxContainer.h"
2727
#include <iostream>
2828
#include <fstream>
29+
#include <thread>
30+
#include <optional>
31+
#include <mutex>
2932

3033
using namespace o2::gpu;
3134

@@ -37,77 +40,99 @@ GPUO2Interface::~GPUO2Interface() { Deinitialize(); }
3740

3841
int GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config)
3942
{
40-
if (mInitialized) {
43+
if (mNContexts) {
4144
return (1);
4245
}
4346
mConfig.reset(new GPUO2InterfaceConfiguration(config));
44-
mContinuous = mConfig->configGRP.continuousMaxTimeBin != 0;
45-
mRec.reset(GPUReconstruction::CreateInstance(mConfig->configDeviceBackend));
46-
if (mRec == nullptr) {
47-
GPUError("Error obtaining instance of GPUReconstruction");
48-
return 1;
49-
}
50-
mChain = mRec->AddChain<GPUChainTracking>(mConfig->configInterface.maxTPCHits, mConfig->configInterface.maxTRDTracklets);
51-
mChain->mConfigDisplay = &mConfig->configDisplay;
52-
mChain->mConfigQA = &mConfig->configQA;
47+
mNContexts = mConfig->configProcessing.doublePipeline ? 2 : 1;
48+
mCtx.reset(new GPUO2Interface::processingContext[mNContexts]);
5349
if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCRaw)) {
5450
mConfig->configGRP.needsClusterer = 1;
5551
}
5652
if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCCompressedClusters)) {
5753
mConfig->configGRP.doCompClusterDecode = 1;
5854
}
59-
mRec->SetSettings(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow);
60-
mChain->SetCalibObjects(mConfig->configCalib);
61-
62-
if (mConfig->configWorkflow.steps.isSet(GPUDataTypes::RecoStep::ITSTracking)) {
63-
mChainITS = mRec->AddChain<GPUChainITS>();
64-
}
55+
for (unsigned int i = 0; i < mNContexts; i++) {
56+
if (i) {
57+
mConfig->configDeviceBackend.master = mCtx[0].mRec.get();
58+
}
59+
mCtx[i].mRec.reset(GPUReconstruction::CreateInstance(mConfig->configDeviceBackend));
60+
mConfig->configDeviceBackend.master = nullptr;
61+
if (mCtx[i].mRec == nullptr) {
62+
GPUError("Error obtaining instance of GPUReconstruction");
63+
mNContexts = 0;
64+
mCtx.reset(nullptr);
65+
return 1;
66+
}
67+
mCtx[i].mChain = mCtx[i].mRec->AddChain<GPUChainTracking>(mConfig->configInterface.maxTPCHits, mConfig->configInterface.maxTRDTracklets);
68+
mCtx[i].mChain->mConfigDisplay = &mConfig->configDisplay;
69+
mCtx[i].mChain->mConfigQA = &mConfig->configQA;
70+
mCtx[i].mRec->SetSettings(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow);
71+
mCtx[i].mChain->SetCalibObjects(mConfig->configCalib);
72+
73+
if (i == 0 && mConfig->configWorkflow.steps.isSet(GPUDataTypes::RecoStep::ITSTracking)) {
74+
mChainITS = mCtx[i].mRec->AddChain<GPUChainITS>();
75+
}
6576

66-
mOutputRegions.reset(new GPUTrackingOutputs);
67-
if (mConfig->configInterface.outputToExternalBuffers) {
68-
for (unsigned int i = 0; i < mOutputRegions->count(); i++) {
69-
mChain->SetSubOutputControl(i, &mOutputRegions->asArray()[i]);
77+
mCtx[i].mOutputRegions.reset(new GPUTrackingOutputs);
78+
if (mConfig->configInterface.outputToExternalBuffers) {
79+
for (unsigned int j = 0; j < mCtx[i].mOutputRegions->count(); j++) {
80+
mCtx[i].mChain->SetSubOutputControl(j, &mCtx[i].mOutputRegions->asArray()[j]);
81+
}
82+
GPUOutputControl dummy;
83+
dummy.set([](size_t size) -> void* {throw std::runtime_error("invalid output memory request, no common output buffer set"); return nullptr; });
84+
mCtx[i].mRec->SetOutputControl(dummy);
7085
}
71-
GPUOutputControl dummy;
72-
dummy.set([](size_t size) -> void* {throw std::runtime_error("invalid output memory request, no common output buffer set"); return nullptr; });
73-
mRec->SetOutputControl(dummy);
74-
}
7586

76-
if (mRec->Init()) {
77-
return (1);
87+
if (i == 0 && mCtx[i].mRec->Init()) {
88+
mNContexts = 0;
89+
mCtx.reset(nullptr);
90+
return (1);
91+
}
92+
if (!mCtx[i].mRec->IsGPU() && mCtx[i].mRec->GetProcessingSettings().memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) {
93+
mCtx[i].mRec->MemoryScalers()->factor *= 2;
94+
}
7895
}
79-
if (!mRec->IsGPU() && mRec->GetProcessingSettings().memoryAllocationStrategy == GPUMemoryResource::ALLOCATION_INDIVIDUAL) {
80-
mRec->MemoryScalers()->factor *= 2;
96+
if (mConfig->configProcessing.doublePipeline) {
97+
mPipelineThread.reset(new std::thread([this]() { mCtx[0].mRec->RunPipelineWorker(); }));
8198
}
82-
mInitialized = true;
8399
return (0);
84100
}
85101

86102
void GPUO2Interface::Deinitialize()
87103
{
88-
if (mInitialized) {
89-
mRec->Finalize();
90-
mRec.reset();
104+
if (mNContexts) {
105+
if (mConfig->configProcessing.doublePipeline) {
106+
mCtx[0].mRec->TerminatePipelineWorker();
107+
mPipelineThread->join();
108+
}
109+
for (unsigned int i = 0; i < mNContexts; i++) {
110+
mCtx[i].mRec->Finalize();
111+
}
112+
mCtx[0].mRec->Exit();
113+
for (int i = mNContexts - 1; i >= 0; i--) {
114+
mCtx[i].mRec.reset();
115+
}
91116
}
92-
mInitialized = false;
117+
mNContexts = 0;
93118
}
94119

95120
void GPUO2Interface::DumpEvent(int nEvent, GPUTrackingInOutPointers* data)
96121
{
97122
if (mConfig->configProcessing.doublePipeline) {
98123
throw std::runtime_error("Cannot dump events in double pipeline mode");
99124
}
100-
mChain->ClearIOPointers();
101-
mChain->mIOPtrs = *data;
125+
mCtx[0].mChain->ClearIOPointers();
126+
mCtx[0].mChain->mIOPtrs = *data;
102127
char fname[1024];
103128
snprintf(fname, 1024, "event.%d.dump", nEvent);
104-
mChain->DumpData(fname);
129+
mCtx[0].mChain->DumpData(fname);
105130
if (nEvent == 0) {
106131
#ifdef GPUCA_BUILD_QA
107132
if (mConfig->configProcessing.runMC) {
108-
mChain->ForceInitQA();
133+
mCtx[0].mChain->ForceInitQA();
109134
snprintf(fname, 1024, "mc.%d.dump", nEvent);
110-
mChain->GetQA()->DumpO2MCData(fname);
135+
mCtx[0].mChain->GetQA()->DumpO2MCData(fname);
111136
}
112137
#endif
113138
}
@@ -118,61 +143,55 @@ void GPUO2Interface::DumpSettings()
118143
if (mConfig->configProcessing.doublePipeline) {
119144
throw std::runtime_error("Cannot dump events in double pipeline mode");
120145
}
121-
mChain->DoQueuedCalibUpdates(-1);
122-
mRec->DumpSettings();
146+
mCtx[0].mChain->DoQueuedCalibUpdates(-1);
147+
mCtx[0].mRec->DumpSettings();
123148
}
124149

125-
int GPUO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs)
150+
int GPUO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs, unsigned int iThread)
126151
{
127-
if (!mInitialized) {
152+
if (mNContexts <= iThread) {
128153
return (1);
129154
}
130155

131-
mChain->mIOPtrs = *data;
156+
mCtx[iThread].mChain->mIOPtrs = *data;
132157
if (mConfig->configInterface.outputToExternalBuffers) {
133-
for (unsigned int i = 0; i < mOutputRegions->count(); i++) {
158+
for (unsigned int i = 0; i < mCtx[iThread].mOutputRegions->count(); i++) {
134159
if (outputs->asArray()[i].allocator) {
135-
mOutputRegions->asArray()[i].set(outputs->asArray()[i].allocator);
160+
mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].allocator);
136161
} else if (outputs->asArray()[i].ptrBase) {
137-
mOutputRegions->asArray()[i].set(outputs->asArray()[i].ptrBase, outputs->asArray()[i].size);
162+
mCtx[iThread].mOutputRegions->asArray()[i].set(outputs->asArray()[i].ptrBase, outputs->asArray()[i].size);
138163
} else {
139-
mOutputRegions->asArray()[i].reset();
164+
mCtx[iThread].mOutputRegions->asArray()[i].reset();
140165
}
141166
}
142167
}
143168

144-
int retVal = mRec->RunChains();
169+
int retVal = mCtx[iThread].mRec->RunChains();
145170
if (retVal == 2) {
146171
retVal = 0; // 2 signals end of event display, ignore
147172
}
148-
if (mConfig->configQA.shipToQC && mChain->QARanForTF()) {
149-
outputs->qa.hist1 = &mChain->GetQA()->getHistograms1D();
150-
outputs->qa.hist2 = &mChain->GetQA()->getHistograms2D();
151-
outputs->qa.hist3 = &mChain->GetQA()->getHistograms1Dd();
152-
outputs->qa.hist4 = &mChain->GetQA()->getGraphs();
173+
if (mConfig->configQA.shipToQC && mCtx[iThread].mChain->QARanForTF()) {
174+
outputs->qa.hist1 = &mCtx[iThread].mChain->GetQA()->getHistograms1D();
175+
outputs->qa.hist2 = &mCtx[iThread].mChain->GetQA()->getHistograms2D();
176+
outputs->qa.hist3 = &mCtx[iThread].mChain->GetQA()->getHistograms1Dd();
177+
outputs->qa.hist4 = &mCtx[iThread].mChain->GetQA()->getGraphs();
153178
outputs->qa.newQAHistsCreated = true;
154179
}
155-
*data = mChain->mIOPtrs;
180+
*data = mCtx[iThread].mChain->mIOPtrs;
156181

157182
return retVal;
158183
}
159184

160-
void GPUO2Interface::Clear(bool clearOutputs) { mRec->ClearAllocatedMemory(clearOutputs); }
161-
162-
void GPUO2Interface::GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const
163-
{
164-
mRec->GetParam().GetClusterErrors2(row, z, sinPhi, DzDs, ErrY2, ErrZ2);
165-
mRec->GetParam().UpdateClusterError2ByState(clusterState, ErrY2, ErrZ2);
166-
}
185+
void GPUO2Interface::Clear(bool clearOutputs, unsigned int iThread) { mCtx[iThread].mRec->ClearAllocatedMemory(clearOutputs); }
167186

168187
int GPUO2Interface::registerMemoryForGPU(const void* ptr, size_t size)
169188
{
170-
return mRec->registerMemoryForGPU(ptr, size);
189+
return mCtx[0].mRec->registerMemoryForGPU(ptr, size);
171190
}
172191

173192
int GPUO2Interface::unregisterMemoryForGPU(const void* ptr)
174193
{
175-
return mRec->unregisterMemoryForGPU(ptr);
194+
return mCtx[0].mRec->unregisterMemoryForGPU(ptr);
176195
}
177196

178197
std::unique_ptr<TPCPadGainCalib> GPUO2Interface::getPadGainCalibDefault()
@@ -190,15 +209,17 @@ std::unique_ptr<o2::tpc::CalibdEdxContainer> GPUO2Interface::getCalibdEdxContain
190209
return std::make_unique<o2::tpc::CalibdEdxContainer>();
191210
}
192211

193-
int GPUO2Interface::UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals)
212+
int GPUO2Interface::UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, unsigned int iThread)
194213
{
195-
mChain->SetUpdateCalibObjects(newCalib, newVals);
214+
mCtx[iThread].mChain->SetUpdateCalibObjects(newCalib, newVals);
196215
return 0;
197216
}
198217

199218
void GPUO2Interface::setErrorCodeOutput(std::vector<std::array<unsigned int, 4>>* v)
200219
{
201-
mRec->setErrorCodeOutput(v);
220+
for (unsigned int i = 0; i < mNContexts; i++) {
221+
mCtx[i].mRec->setErrorCodeOutput(v);
222+
}
202223
}
203224

204225
void GPUO2Interface::GetITSTraits(o2::its::TrackerTraits*& trackerTraits, o2::its::VertexerTraits*& vertexerTraits, o2::its::TimeFrame*& timeFrame)

GPU/GPUTracking/Interface/GPUO2Interface.h

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
#include <vector>
3232
#include "GPUCommonDef.h"
3333
#include "GPUDataTypes.h"
34+
35+
namespace std
36+
{
37+
class thread;
38+
} // namespace std
39+
3440
namespace o2::tpc
3541
{
3642
struct ClusterNativeAccess;
@@ -66,18 +72,15 @@ class GPUO2Interface
6672
int Initialize(const GPUO2InterfaceConfiguration& config);
6773
void Deinitialize();
6874

69-
int RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs = nullptr);
70-
void Clear(bool clearOutputs);
75+
int RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceOutputs* outputs = nullptr, unsigned int iThread = 0);
76+
void Clear(bool clearOutputs, unsigned int iThread = 0);
7177
void DumpEvent(int nEvent, GPUTrackingInOutPointers* data);
7278
void DumpSettings();
7379

7480
void GetITSTraits(o2::its::TrackerTraits*& trackerTraits, o2::its::VertexerTraits*& vertexerTraits, o2::its::TimeFrame*& timeFrame);
7581

7682
// Updates all calibration objects that are != nullptr in newCalib
77-
int UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals);
78-
79-
bool GetParamContinuous() { return (mContinuous); }
80-
void GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const;
83+
int UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, unsigned int iThread = 0);
8184

8285
static std::unique_ptr<TPCPadGainCalib> getPadGainCalibDefault();
8386
static std::unique_ptr<TPCPadGainCalib> getPadGainCalib(const o2::tpc::CalDet<float>& in);
@@ -90,18 +93,24 @@ class GPUO2Interface
9093

9194
const GPUO2InterfaceConfiguration& getConfig() const { return *mConfig; }
9295

96+
struct processingContext {
97+
std::unique_ptr<GPUReconstruction> mRec;
98+
GPUChainTracking* mChain = nullptr;
99+
std::unique_ptr<GPUTrackingOutputs> mOutputRegions;
100+
};
101+
93102
private:
94103
GPUO2Interface(const GPUO2Interface&);
95104
GPUO2Interface& operator=(const GPUO2Interface&);
96105

97-
bool mInitialized = false;
98106
bool mContinuous = false;
99107

100-
std::unique_ptr<GPUReconstruction> mRec; //!
101-
GPUChainTracking* mChain = nullptr; //!
102-
GPUChainITS* mChainITS = nullptr; //!
103-
std::unique_ptr<GPUO2InterfaceConfiguration> mConfig; //!
104-
std::unique_ptr<GPUTrackingOutputs> mOutputRegions; //!
108+
unsigned int mNContexts = 0;
109+
std::unique_ptr<processingContext[]> mCtx;
110+
111+
std::unique_ptr<GPUO2InterfaceConfiguration> mConfig;
112+
GPUChainITS* mChainITS = nullptr;
113+
std::unique_ptr<std::thread> mPipelineThread;
105114
};
106115
} // namespace o2::gpu
107116

GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <string>
2828
#include <array>
2929
#include <vector>
30+
#include <mutex>
3031

3132
class TStopwatch;
3233
namespace o2
@@ -138,7 +139,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task
138139
/// storing the new calib objects by overwritting the old calibs
139140
void cleanOldCalibsTPCPtrs();
140141

141-
void doCalibUpdates(o2::framework::ProcessingContext& pc);
142+
void doCalibUpdates(o2::framework::ProcessingContext& pc, unsigned int threadIndex);
142143

143144
void doTrackTuneTPC(GPUTrackingInOutPointers& ptrs, char* buffout);
144145

@@ -175,6 +176,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task
175176
std::vector<int> mTPCSectors;
176177
std::unique_ptr<o2::its::Tracker> mITSTracker;
177178
std::unique_ptr<o2::its::Vertexer> mITSVertexer;
179+
std::mutex mMutexDecodeInput;
178180
o2::its::TimeFrame* mITSTimeFrame = nullptr;
179181
const o2::itsmft::TopologyDictionary* mITSDict = nullptr;
180182
const o2::dataformats::MeanVertexObject* mMeanVertex;

0 commit comments

Comments
 (0)