Skip to content

Commit 1bc7c3d

Browse files
bernhardmgruberagheata
authored andcommitted
Keep some Track members in registers
It is beneficial to keep some of the Track members in registers for the duration of the kernel. The track variables are loaded at the beginning of the kernel and written back when the track survives. The signature of InitAsSecondary() had to be changed to not load from the track again. The results of the simulation change slighly because nvcc now generates a few fma instructions in different places (thx to hahnjo for finding out!).
1 parent 9377092 commit 1bc7c3d

File tree

24 files changed

+788
-656
lines changed

24 files changed

+788
-656
lines changed

examples/Example13/electrons.cu

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2021 CERN
1+
// SPDX-FileCopyrightText: 2022 CERN
22
// SPDX-License-Identifier: Apache-2.0
33

44
#include "example13.cuh"
@@ -47,18 +47,29 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
4747
for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < activeSize; i += blockDim.x * gridDim.x) {
4848
const int slot = (*active)[i];
4949
Track &currentTrack = electrons[slot];
50-
auto volume = currentTrack.navState.Top();
51-
int volumeID = volume->id();
50+
auto energy = currentTrack.energy;
51+
auto pos = currentTrack.pos;
52+
auto dir = currentTrack.dir;
53+
auto navState = currentTrack.navState;
54+
const auto volume = navState.Top();
55+
const int volumeID = volume->id();
5256
// the MCC vector is indexed by the logical volume id
53-
int lvolID = volume->GetLogicalVolume()->id();
54-
int theMCIndex = MCIndex[lvolID];
57+
const int theMCIndex = MCIndex[volume->GetLogicalVolume()->id()];
58+
59+
auto survive = [&] {
60+
currentTrack.energy = energy;
61+
currentTrack.pos = pos;
62+
currentTrack.dir = dir;
63+
currentTrack.navState = navState;
64+
activeQueue->push_back(slot);
65+
};
5566

5667
// Init a track with the needed data to call into G4HepEm.
5768
G4HepEmElectronTrack elTrack;
5869
G4HepEmTrack *theTrack = elTrack.GetTrack();
59-
theTrack->SetEKin(currentTrack.energy);
70+
theTrack->SetEKin(energy);
6071
theTrack->SetMCIndex(theMCIndex);
61-
theTrack->SetOnBoundary(currentTrack.navState.IsOnBoundary());
72+
theTrack->SetOnBoundary(navState.IsOnBoundary());
6273
theTrack->SetCharge(Charge);
6374
G4HepEmMSCTrackData *mscData = elTrack.GetMSCTrackData();
6475
mscData->fIsFirstStep = currentTrack.initialRange < 0;
@@ -73,8 +84,8 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
7384

7485
// Compute safety, needed for MSC step limit.
7586
double safety = 0;
76-
if (!currentTrack.navState.IsOnBoundary()) {
77-
safety = BVHNavigator::ComputeSafety(currentTrack.pos, currentTrack.navState);
87+
if (!navState.IsOnBoundary()) {
88+
safety = BVHNavigator::ComputeSafety(pos, navState);
7889
}
7990
theTrack->SetSafety(safety);
8091

@@ -97,7 +108,6 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
97108
currentTrack.dynamicRangeFactor = mscData->fDynamicRangeFactor;
98109
currentTrack.tlimitMin = mscData->fTlimitMin;
99110

100-
101111
// Get result into variables.
102112
double geometricalStepLengthFromPhysics = theTrack->GetGStepLength();
103113
// The phyiscal step length is the amount that the particle experiences
@@ -115,22 +125,20 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
115125
vecgeom::NavStateIndex nextState;
116126
if (BzFieldValue != 0) {
117127
geometryStepLength = fieldPropagatorBz.ComputeStepAndNextVolume<BVHNavigator>(
118-
currentTrack.energy, Mass, Charge, geometricalStepLengthFromPhysics, currentTrack.pos, currentTrack.dir,
119-
currentTrack.navState, nextState, propagated, safety);
128+
energy, Mass, Charge, geometricalStepLengthFromPhysics, pos, dir, navState, nextState, propagated, safety);
120129
} else {
121-
geometryStepLength =
122-
BVHNavigator::ComputeStepAndNextVolume(currentTrack.pos, currentTrack.dir, geometricalStepLengthFromPhysics,
123-
currentTrack.navState, nextState, kPush);
124-
currentTrack.pos += geometryStepLength * currentTrack.dir;
130+
geometryStepLength = BVHNavigator::ComputeStepAndNextVolume(pos, dir, geometricalStepLengthFromPhysics, navState,
131+
nextState, kPush);
132+
pos += geometryStepLength * dir;
125133
}
126134

127135
// Set boundary state in navState so the next step and secondaries get the
128-
// correct information (currentTrack.navState = nextState only if relocated
136+
// correct information (navState = nextState only if relocated
129137
// in case of a boundary; see below)
130-
currentTrack.navState.SetBoundaryState(nextState.IsOnBoundary());
138+
navState.SetBoundaryState(nextState.IsOnBoundary());
131139

132140
// Propagate information from geometrical step to MSC.
133-
theTrack->SetDirection(currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z());
141+
theTrack->SetDirection(dir.x(), dir.y(), dir.z());
134142
theTrack->SetGStepLength(geometryStepLength);
135143
theTrack->SetOnBoundary(nextState.IsOnBoundary());
136144

@@ -139,7 +147,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
139147

140148
// Collect the direction change and displacement by MSC.
141149
const double *direction = theTrack->GetDirection();
142-
currentTrack.dir.Set(direction[0], direction[1], direction[2]);
150+
dir.Set(direction[0], direction[1], direction[2]);
143151
if (!nextState.IsOnBoundary()) {
144152
const double *mscDisplacement = mscData->GetDisplacement();
145153
vecgeom::Vector3D<Precision> displacement(mscDisplacement[0], mscDisplacement[1], mscDisplacement[2]);
@@ -156,18 +164,18 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
156164
// Apply displacement, depending on how close we are to a boundary.
157165
// 1a. Far away from geometry boundary:
158166
if (reducedSafety > 0.0 && dispR <= reducedSafety) {
159-
currentTrack.pos += displacement;
167+
pos += displacement;
160168
} else {
161169
// Recompute safety.
162-
safety = BVHNavigator::ComputeSafety(currentTrack.pos, currentTrack.navState);
170+
safety = BVHNavigator::ComputeSafety(pos, navState);
163171
reducedSafety = sFact * safety;
164172

165173
// 1b. Far away from geometry boundary:
166174
if (reducedSafety > 0.0 && dispR <= reducedSafety) {
167-
currentTrack.pos += displacement;
175+
pos += displacement;
168176
// 2. Push to boundary:
169177
} else if (reducedSafety > kGeomMinLength) {
170-
currentTrack.pos += displacement * (reducedSafety / dispR);
178+
pos += displacement * (reducedSafety / dispR);
171179
}
172180
// 3. Very small safety: do nothing.
173181
}
@@ -179,7 +187,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
179187
atomicAdd(&scoringPerVolume->chargedTrackLength[volumeID], elTrack.GetPStepLength());
180188

181189
// Collect the changes in energy and deposit.
182-
currentTrack.energy = theTrack->GetEKin();
190+
energy = theTrack->GetEKin();
183191
double energyDeposit = theTrack->GetEnergyDeposit();
184192
atomicAdd(&globalScoring->energyDeposit, energyDeposit);
185193
atomicAdd(&scoringPerVolume->energyDeposit[volumeID], energyDeposit);
@@ -204,13 +212,13 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
204212
double sinPhi, cosPhi;
205213
sincos(phi, &sinPhi, &cosPhi);
206214

207-
gamma1.InitAsSecondary(/*parent=*/currentTrack);
215+
gamma1.InitAsSecondary(pos, navState);
208216
newRNG.Advance();
209217
gamma1.rngState = newRNG;
210218
gamma1.energy = copcore::units::kElectronMassC2;
211219
gamma1.dir.Set(sint * cosPhi, sint * sinPhi, cost);
212220

213-
gamma2.InitAsSecondary(/*parent=*/currentTrack);
221+
gamma2.InitAsSecondary(pos, navState);
214222
// Reuse the RNG state of the dying track.
215223
gamma2.rngState = currentTrack.rngState;
216224
gamma2.energy = copcore::units::kElectronMassC2;
@@ -226,21 +234,21 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
226234

227235
// Kill the particle if it left the world.
228236
if (nextState.Top() != nullptr) {
229-
activeQueue->push_back(slot);
230-
BVHNavigator::RelocateToNextVolume(currentTrack.pos, currentTrack.dir, nextState);
237+
BVHNavigator::RelocateToNextVolume(pos, dir, nextState);
231238

232239
// Move to the next boundary.
233-
currentTrack.navState = nextState;
240+
navState = nextState;
241+
survive();
234242
}
235243
continue;
236244
} else if (!propagated) {
237245
// Did not yet reach the interaction point due to error in the magnetic
238246
// field propagation. Try again next time.
239-
activeQueue->push_back(slot);
247+
survive();
240248
continue;
241249
} else if (winnerProcessIndex < 0) {
242250
// No discrete process, move on.
243-
activeQueue->push_back(slot);
251+
survive();
244252
continue;
245253
}
246254

@@ -251,7 +259,7 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
251259
// Check if a delta interaction happens instead of the real discrete process.
252260
if (G4HepEmElectronManager::CheckDelta(&g4HepEmData, theTrack, currentTrack.Uniform())) {
253261
// A delta interaction happened, move on.
254-
activeQueue->push_back(slot);
262+
survive();
255263
continue;
256264
}
257265

@@ -262,7 +270,6 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
262270
// numbers after MSC used up a fair share for sampling the displacement.
263271
currentTrack.rngState.Advance();
264272

265-
const double energy = currentTrack.energy;
266273
const double theElCut = g4HepEmData.fTheMatCutData->fMatCutData[theMCIndex].fSecElProdCutE;
267274

268275
switch (winnerProcessIndex) {
@@ -271,22 +278,21 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
271278
double deltaEkin = (IsElectron) ? G4HepEmElectronInteractionIoni::SampleETransferMoller(theElCut, energy, &rnge)
272279
: G4HepEmElectronInteractionIoni::SampleETransferBhabha(theElCut, energy, &rnge);
273280

274-
double dirPrimary[] = {currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z()};
281+
double dirPrimary[] = {dir.x(), dir.y(), dir.z()};
275282
double dirSecondary[3];
276283
G4HepEmElectronInteractionIoni::SampleDirections(energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
277284

278285
Track &secondary = secondaries.electrons.NextTrack();
279286
atomicAdd(&globalScoring->numElectrons, 1);
280287

281-
secondary.InitAsSecondary(/*parent=*/currentTrack);
288+
secondary.InitAsSecondary(pos, navState);
282289
secondary.rngState = newRNG;
283290
secondary.energy = deltaEkin;
284291
secondary.dir.Set(dirSecondary[0], dirSecondary[1], dirSecondary[2]);
285292

286-
currentTrack.energy = energy - deltaEkin;
287-
currentTrack.dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
288-
// The current track continues to live.
289-
activeQueue->push_back(slot);
293+
energy -= deltaEkin;
294+
dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
295+
survive();
290296
break;
291297
}
292298
case 1: {
@@ -298,27 +304,26 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
298304
: G4HepEmElectronInteractionBrem::SampleETransferRB(&g4HepEmData, energy, logEnergy,
299305
theMCIndex, &rnge, IsElectron);
300306

301-
double dirPrimary[] = {currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z()};
307+
double dirPrimary[] = {dir.x(), dir.y(), dir.z()};
302308
double dirSecondary[3];
303309
G4HepEmElectronInteractionBrem::SampleDirections(energy, deltaEkin, dirSecondary, dirPrimary, &rnge);
304310

305311
Track &gamma = secondaries.gammas.NextTrack();
306312
atomicAdd(&globalScoring->numGammas, 1);
307313

308-
gamma.InitAsSecondary(/*parent=*/currentTrack);
314+
gamma.InitAsSecondary(pos, navState);
309315
gamma.rngState = newRNG;
310316
gamma.energy = deltaEkin;
311317
gamma.dir.Set(dirSecondary[0], dirSecondary[1], dirSecondary[2]);
312318

313-
currentTrack.energy = energy - deltaEkin;
314-
currentTrack.dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
315-
// The current track continues to live.
316-
activeQueue->push_back(slot);
319+
energy -= deltaEkin;
320+
dir.Set(dirPrimary[0], dirPrimary[1], dirPrimary[2]);
321+
survive();
317322
break;
318323
}
319324
case 2: {
320325
// Invoke annihilation (in-flight) for e+
321-
double dirPrimary[] = {currentTrack.dir.x(), currentTrack.dir.y(), currentTrack.dir.z()};
326+
double dirPrimary[] = {dir.x(), dir.y(), dir.z()};
322327
double theGamma1Ekin, theGamma2Ekin;
323328
double theGamma1Dir[3], theGamma2Dir[3];
324329
G4HepEmPositronInteractionAnnihilation::SampleEnergyAndDirectionsInFlight(
@@ -328,12 +333,12 @@ static __device__ __forceinline__ void TransportElectrons(Track *electrons, cons
328333
Track &gamma2 = secondaries.gammas.NextTrack();
329334
atomicAdd(&globalScoring->numGammas, 2);
330335

331-
gamma1.InitAsSecondary(/*parent=*/currentTrack);
336+
gamma1.InitAsSecondary(pos, navState);
332337
gamma1.rngState = newRNG;
333338
gamma1.energy = theGamma1Ekin;
334339
gamma1.dir.Set(theGamma1Dir[0], theGamma1Dir[1], theGamma1Dir[2]);
335340

336-
gamma2.InitAsSecondary(/*parent=*/currentTrack);
341+
gamma2.InitAsSecondary(pos, navState);
337342
// Reuse the RNG state of the dying track.
338343
gamma2.rngState = currentTrack.rngState;
339344
gamma2.energy = theGamma2Ekin;

examples/Example13/example13.cuh

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2021 CERN
1+
// SPDX-FileCopyrightText: 2022 CERN
22
// SPDX-License-Identifier: Apache-2.0
33

44
#ifndef EXAMPLE13_CUH
@@ -34,7 +34,8 @@ struct Track {
3434

3535
__host__ __device__ double Uniform() { return rngState.Rndm(); }
3636

37-
__host__ __device__ void InitAsSecondary(const Track &parent)
37+
__host__ __device__ void InitAsSecondary(const vecgeom::Vector3D<Precision> &parentPos,
38+
const vecgeom::NavStateIndex &parentNavState)
3839
{
3940
// The caller is responsible to branch a new RNG state and to set the energy.
4041
this->numIALeft[0] = -1.0;
@@ -47,8 +48,8 @@ struct Track {
4748

4849
// A secondary inherits the position of its parent; the caller is responsible
4950
// to update the directions.
50-
this->pos = parent.pos;
51-
this->navState = parent.navState;
51+
this->pos = parentPos;
52+
this->navState = parentNavState;
5253
}
5354
};
5455

0 commit comments

Comments
 (0)