Skip to content

Commit 5240f6e

Browse files
committed
faster mat LUT
Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch>
1 parent 407208a commit 5240f6e

3 files changed

Lines changed: 55 additions & 17 deletions

File tree

Detectors/Base/include/DetectorsBase/MatLayerCyl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class MatLayerCyl : public o2::gpu::FlatObject
9696
// obtain material cell, cell ID must be valid
9797
GPUd() const MatCell& getCellPhiBin(int iphi, int iz) const { return mCells[getCellIDPhiBin(iphi, iz)]; }
9898
GPUd() const MatCell& getCell(int iphiSlice, int iz) const { return mCells[getCellID(iphiSlice, iz)]; }
99+
GPUd() const MatCell* getCellRow(int iphiSlice) const { return mCells + iphiSlice * getNZBins(); }
99100

100101
#ifndef GPUCA_ALIGPUCODE // this part is unvisible on GPU version
101102
MatCell& getCellPhiBin(int iphi, int iz)

Detectors/Base/include/DetectorsBase/MatLayerCylSet.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ class MatLayerCylSet : public o2::gpu::FlatObject
115115
/// searches a layer based on r2 input, using a lookup table
116116
GPUd() int searchLayerFast(float r2, int low = -1, int high = -1) const;
117117

118+
/// resolves a layer from an already loaded lookup-table entry
119+
GPUd() int resolveLayerRange(float r2, int voxel, uint16_t entry) const;
120+
121+
/// voxel holding this radius; the caller must have checked that r2 is inside the LUT
122+
GPUd() int voxelIndex(float r2) const { return int(o2::gpu::CAMath::Sqrt(r2) * InvVoxelRDelta); }
123+
118124
#ifndef GPUCA_GPUCODE
119125
//-----------------------------------------------------------
120126
std::size_t estimateFlatBufferSize() const;
@@ -139,8 +145,10 @@ class MatLayerCylSet : public o2::gpu::FlatObject
139145
static constexpr float VoxelRDelta = 0.05; // voxel spacing for layer lookup; seems a natural choice - corresponding ~ to smallest spacing
140146
static constexpr float InvVoxelRDelta = 1.f / VoxelRDelta;
141147
static constexpr int NumVoxels = int(LayerRMax / VoxelRDelta);
148+
static constexpr uint16_t VoxelAmbiguousBit = 0x8000u;
149+
static constexpr uint16_t VoxelSegmentMask = 0x7fffu;
142150

143-
uint16_t mLayerVoxelLU[2 * NumVoxels]; //! helper structure to lookup a layer based on known radius (static dimension for easy copy to GPU)
151+
uint16_t mLayerVoxelLU[NumVoxels]; //! first interval based on known radius, plus the ambiguity flag (static dimension for easy copy to GPU)
144152
bool mInitializedLayerVoxelLU = false; //! if the voxels have been initialized
145153

146154
ClassDefNV(MatLayerCylSet, 1);

Detectors/Base/src/MatLayerCylSet.cxx

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ void MatLayerCylSet::finalizeStructures()
234234
o2::gpu::FlatObject::resizeArray(get()->mR2Intervals, 0, nR2Int);
235235
o2::gpu::FlatObject::resizeArray(get()->mInterval2LrID, 0, nR2Int);
236236
get()->mR2Intervals[0] = get()->mRMin2;
237-
get()->mR2Intervals[1] = get()->mRMax2;
237+
get()->mR2Intervals[1] = getLayer(0).getRMax2();
238238
get()->mInterval2LrID[0] = 0;
239239
auto& nRIntervals = get()->mNRIntervals;
240240
nRIntervals = 1;
@@ -319,14 +319,17 @@ void MatLayerCylSet::initLayerVoxelLU()
319319
if (LayerRMax < get()->mRMax) {
320320
LOG(fatal) << "Cannot initialized layer voxel lookup due to dimension problem (fix constants in MatLayerCylSet.h)";
321321
}
322+
// the top bit of an entry carries the ambiguity flag, so the interval index has one bit less
323+
if (get()->mNRIntervals > VoxelSegmentMask) {
324+
LOG(fatal) << "Too many R intervals (" << get()->mNRIntervals << ") to pack into a layer voxel lookup entry";
325+
}
322326
for (int voxel = 0; voxel < NumVoxels; ++voxel) {
323327
// check the 2 extremes of this voxel "covering"
324328
const auto lowerR = voxel * VoxelRDelta;
325329
const auto upperR = lowerR + VoxelRDelta;
326330
const auto lowerSegment = searchSegment(lowerR * lowerR);
327331
const auto upperSegment = searchSegment(upperR * upperR);
328-
mLayerVoxelLU[2 * voxel] = lowerSegment;
329-
mLayerVoxelLU[2 * voxel + 1] = upperSegment;
332+
mLayerVoxelLU[voxel] = uint16_t(lowerSegment) | (lowerSegment != upperSegment ? VoxelAmbiguousBit : uint16_t{0});
330333
}
331334
mInitializedLayerVoxelLU = true;
332335
}
@@ -477,7 +480,10 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
477480
tEndPhi = cross2;
478481
checkMorePhi = false;
479482
} else { // last phi slice still not reached
480-
tEndPhi = ray.crossRadial(lr, (stepPhiID > 0 ? phiID + 1 : phiID) % nphiSlices);
483+
const int boundaryPhiID = stepPhiID > 0 ? phiID + 1 : phiID;
484+
// phiID may be offset by one revolution to handle wrapping, but never by more.
485+
const int wrappedBoundaryPhiID = boundaryPhiID < nphiSlices ? boundaryPhiID : boundaryPhiID - nphiSlices;
486+
tEndPhi = ray.crossRadial(lr, wrappedBoundaryPhiID);
481487
if (tEndPhi == Ray::InvalidT) {
482488
break; // ray parallel to radial line, abandon check for phi bin change
483489
}
@@ -490,6 +496,8 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
490496
}
491497
auto zID = lr.getZBinID(ray.getZ(tStartPhi));
492498
auto zIDLast = lr.getZBinID(ray.getZ(tEndPhi));
499+
const int wrappedPhiID = phiID < nphiSlices ? phiID : phiID - nphiSlices;
500+
const auto* cellRow = lr.getCellRow(wrappedPhiID);
493501
// check if Zbins are crossed
494502

495503
#ifdef _DBG_LOC_
@@ -512,7 +520,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
512520
}
513521
// account materials of this step
514522
float step = tEndZ > tStartZ ? tEndZ - tStartZ : tStartZ - tEndZ; // the real step is ray.getDist(tEnd-tStart), will rescale all later
515-
const auto& cell = lr.getCell(phiID % nphiSlices, zID);
523+
const auto& cell = cellRow[zID];
516524
rval.meanRho += cell.meanRho * step;
517525
rval.meanX2X0 += cell.meanX2X0 * step;
518526
rval.length += step;
@@ -523,7 +531,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
523531
printf(
524532
"Lr#%3d / cross#%d : account %f<t<%f at phiSlice %d | Zbin: %3d (%3d) |[%+e %+e +%e]:[%+e %+e %+e] "
525533
"Step: %.3e StrpCor: %.3e\n",
526-
lrID, ic, tEndZ, tStartZ, phiID % nphiSlices, zID, zIDLast,
534+
lrID, ic, tEndZ, tStartZ, wrappedPhiID, zID, zIDLast,
527535
pos0[0], pos0[1], pos0[2], pos1[0], pos1[1], pos1[2], step, ray.getDist(step));
528536
#endif
529537

@@ -532,7 +540,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
532540
} while (checkMoreZ);
533541
} else {
534542
float step = tEndPhi > tStartPhi ? tEndPhi - tStartPhi : tStartPhi - tEndPhi; // the real step is |ray.getDist(tEnd-tStart)|, will rescale all later
535-
const auto& cell = lr.getCell(phiID % nphiSlices, zID);
543+
const auto& cell = cellRow[zID];
536544
rval.meanRho += cell.meanRho * step;
537545
rval.meanX2X0 += cell.meanX2X0 * step;
538546
rval.length += step;
@@ -543,7 +551,7 @@ GPUd() MatBudget MatLayerCylSet::getMatBudget(float x0, float y0, float z0, floa
543551
printf(
544552
"Lr#%3d / cross#%d : account %f<t<%f at phiSlice %d | Zbin: %3d ----- |[%+e %+e +%e]:[%+e %+e %+e]"
545553
"Step: %.3e StrpCor: %.3e\n",
546-
lrID, ic, tEndPhi, tStartPhi, phiID % nphiSlices, zID,
554+
lrID, ic, tEndPhi, tStartPhi, wrappedPhiID, zID,
547555
pos0[0], pos0[1], pos0[2], pos1[0], pos1[1], pos1[2], step, ray.getDist(step));
548556
#endif
549557
}
@@ -581,12 +589,25 @@ GPUd() bool MatLayerCylSet::getLayersRange(const Ray& ray, short& lmin, short& l
581589
return false;
582590
}
583591
int lmxInt, lmnInt;
584-
if (!mInitializedLayerVoxelLU) {
592+
#ifdef GPUCA_GPUCODE
593+
// On the device the voxel table is always present
594+
constexpr bool haveVoxelLU = true;
595+
#else
596+
const bool haveVoxelLU = mInitializedLayerVoxelLU;
597+
#endif
598+
if (!haveVoxelLU) {
585599
lmxInt = rmax2 < getRMax2() ? searchSegment(rmax2, 0) : get()->mNRIntervals - 2;
586600
lmnInt = rmin2 >= getRMin2() ? searchSegment(rmin2, 0, lmxInt + 1) : 0;
587601
} else {
588-
lmxInt = rmax2 < getRMax2() ? searchLayerFast(rmax2, 0) : get()->mNRIntervals - 2;
589-
lmnInt = rmin2 >= getRMin2() ? searchLayerFast(rmin2, 0, lmxInt + 1) : 0;
602+
// The two lookups are independent so overlapping the pair is worth the clumsier shape.
603+
const bool useMax = rmax2 < getRMax2();
604+
const bool useMin = rmin2 >= getRMin2();
605+
const int ixMax = useMax ? voxelIndex(rmax2) : 0;
606+
const int ixMin = useMin ? voxelIndex(rmin2) : 0;
607+
const uint16_t eMax = mLayerVoxelLU[ixMax];
608+
const uint16_t eMin = mLayerVoxelLU[ixMin];
609+
lmxInt = useMax ? resolveLayerRange(rmax2, ixMax, eMax) : get()->mNRIntervals - 2;
610+
lmnInt = useMin ? resolveLayerRange(rmin2, ixMin, eMin) : 0;
590611
}
591612

592613
const auto* interval2LrID = get()->mInterval2LrID;
@@ -605,11 +626,19 @@ GPUd() bool MatLayerCylSet::getLayersRange(const Ray& ray, short& lmin, short& l
605626
GPUd() int MatLayerCylSet::searchLayerFast(float r2, int low, int high) const
606627
{
607628
// we can avoid the sqrt .. at the cost of more memory in the lookup
608-
const auto index = 2 * int(o2::gpu::CAMath::Sqrt(r2) * InvVoxelRDelta);
609-
const auto layersfirst = mLayerVoxelLU[index];
610-
const auto layerslast = mLayerVoxelLU[index + 1];
611-
if (layersfirst != layerslast) {
612-
// this means the voxel is undecided and we revert to search
629+
const auto index = voxelIndex(r2);
630+
return resolveLayerRange(r2, index, mLayerVoxelLU[index]);
631+
}
632+
633+
GPUd() int MatLayerCylSet::resolveLayerRange(float r2, int voxel, uint16_t entry) const
634+
{
635+
const int layersfirst = entry & VoxelSegmentMask;
636+
if (entry & VoxelAmbiguousBit) {
637+
// Recreate the upper candidate only for the small fraction of undecided voxels.
638+
// Keep the operations identical to initLayerVoxelLU so boundary behaviour is unchanged.
639+
const auto lowerR = voxel * VoxelRDelta;
640+
const auto upperR = lowerR + VoxelRDelta;
641+
const auto layerslast = searchSegment(upperR * upperR);
613642
return searchSegment(r2, layersfirst, layerslast + 1);
614643
}
615644
return layersfirst;

0 commit comments

Comments
 (0)