Skip to content

Commit 13be6aa

Browse files
MCKinematicsReader: load and release the track references per event
The track references of a source were loaded for all events at the first access and never released. They are now loaded per event on demand (with the baskets dropped at the end of a TTree cluster, as for the tracks) and releaseTracksForSourceAndEvent frees them together with the tracks. For a PbPb TF (10 signal events, 1.75M references): +304 MB held from the first access until the end before, now +135 MB at peak and +55 MB after releasing all events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 333cdd5 commit 13be6aa

2 files changed

Lines changed: 43 additions & 16 deletions

File tree

‎Steer/include/Steer/MCKinematicsReader.h‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class MCKinematicsReader
8787
/// variant returning all tracks for source and event at once
8888
std::vector<MCTrack> const& getTracks(int source, int event) const;
8989

90-
/// API to ask releasing tracks (freeing memory) for source + event
90+
/// API to ask releasing tracks and track references (freeing memory) for source + event
9191
void releaseTracksForSourceAndEvent(int source, int event);
9292

9393
/// variant returning all tracks for an event id (source = 0) at once
@@ -129,7 +129,8 @@ class MCKinematicsReader
129129
void initTracksForSource(int source) const;
130130
void loadTracksForSourceAndEvent(int source, int eventID) const;
131131
void loadHeadersForSource(int source) const;
132-
void loadTrackRefsForSource(int source) const;
132+
void initTrackRefsForSource(int source) const;
133+
void loadTrackRefsForSourceAndEvent(int source, int event) const;
133134
void initIndexedTrackRefs(std::vector<o2::TrackReference>& refs, o2::dataformats::MCTruthContainer<o2::TrackReference>& indexedrefs) const;
134135

135136
DigitizationContext const* mDigitizationContext = nullptr;
@@ -142,6 +143,7 @@ class MCKinematicsReader
142143
mutable std::vector<std::vector<std::vector<o2::MCTrack>*>> mTracks; // the in-memory track container
143144
mutable std::vector<std::vector<o2::dataformats::MCEventHeader>> mHeaders; // the in-memory header container
144145
mutable std::vector<std::vector<o2::dataformats::MCTruthContainer<o2::TrackReference>>> mIndexedTrackRefs; // the in-memory track ref container
146+
mutable std::vector<std::vector<bool>> mTrackRefsLoaded; // whether the track refs of a source/event are in memory
145147

146148
bool mInitialized = false; // whether initialized
147149
};
@@ -206,23 +208,29 @@ inline gsl::span<o2::TrackReference> MCKinematicsReader::getTrackRefs(int source
206208
}
207209
auto& perEvent = mIndexedTrackRefs[source];
208210
if (perEvent.size() == 0) {
209-
loadTrackRefsForSource(source);
211+
initTrackRefsForSource(source);
210212
}
211213
if (static_cast<size_t>(event) >= perEvent.size()) {
212214
return {};
213215
}
216+
if (!mTrackRefsLoaded[source][event]) {
217+
loadTrackRefsForSourceAndEvent(source, event);
218+
}
214219
return perEvent[event].getLabels(track);
215220
}
216221

217222
inline const std::vector<o2::TrackReference>& MCKinematicsReader::getTrackRefsByEvent(int source, int event) const
218223
{
219224
auto const& perEvent = mIndexedTrackRefs.at(source);
220225
if (perEvent.size() == 0) {
221-
loadTrackRefsForSource(source);
226+
initTrackRefsForSource(source);
222227
}
223228
if (static_cast<size_t>(event) >= perEvent.size()) {
224229
reportMissingEvent("events of track references", source, event, perEvent.size());
225230
}
231+
if (!mTrackRefsLoaded[source][event]) {
232+
loadTrackRefsForSourceAndEvent(source, event);
233+
}
226234
return perEvent[event].getTruthArray();
227235
}
228236

‎Steer/src/MCKinematicsReader.cxx‎

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ void MCKinematicsReader::releaseTracksForSourceAndEvent(int source, int eventID)
111111
delete mTracks[source][eventID];
112112
mTracks[source][eventID] = nullptr;
113113
}
114+
// the track references of this event as well (reloaded on demand)
115+
if (static_cast<size_t>(eventID) < mTrackRefsLoaded.at(source).size() && mTrackRefsLoaded[source][eventID]) {
116+
mIndexedTrackRefs[source][eventID] = o2::dataformats::MCTruthContainer<o2::TrackReference>();
117+
mTrackRefsLoaded[source][eventID] = false;
118+
}
114119
}
115120

116121
void MCKinematicsReader::loadHeadersForSource(int source) const
@@ -135,31 +140,43 @@ void MCKinematicsReader::loadHeadersForSource(int source) const
135140
}
136141
}
137142

138-
void MCKinematicsReader::loadTrackRefsForSource(int source) const
143+
void MCKinematicsReader::initTrackRefsForSource(int source) const
139144
{
140145
auto chain = mInputChains[source];
141146
if (chain) {
142147
// todo: get name from NameConfig
143148
auto br = chain->GetBranch("TrackRefs");
144149
if (br) {
145-
std::vector<o2::TrackReference>* refs = nullptr;
146-
br->SetAddress(&refs);
147150
mIndexedTrackRefs[source].resize(br->GetEntries());
148-
for (int event = 0; event < br->GetEntries(); ++event) {
149-
br->GetEntry(event);
150-
if (refs) {
151-
// we convert the original flat vector into an indexed structure
152-
initIndexedTrackRefs(*refs, mIndexedTrackRefs[source][event]);
153-
delete refs;
154-
refs = nullptr;
155-
}
156-
}
151+
mTrackRefsLoaded[source].assign(br->GetEntries(), false);
157152
} else {
158153
LOG(warn) << "TrackRefs branch not found";
159154
}
160155
}
161156
}
162157

158+
void MCKinematicsReader::loadTrackRefsForSourceAndEvent(int source, int event) const
159+
{
160+
// todo: get name from NameConfig
161+
auto br = mInputChains[source]->GetBranch("TrackRefs");
162+
std::vector<o2::TrackReference>* refs = nullptr; // allocated by ROOT, owned by us
163+
br->SetAddress(&refs);
164+
br->GetEntry(event);
165+
if (refs) {
166+
// we convert the original flat vector into an indexed structure
167+
initIndexedTrackRefs(*refs, mIndexedTrackRefs[source][event]);
168+
delete refs;
169+
}
170+
br->ResetAddress();
171+
// free the decompressed baskets if no later entry reads them, i.e. at the end of the cluster of this event
172+
auto clusterIt = br->GetTree()->GetClusterIterator(event);
173+
clusterIt.Next();
174+
if (event + 1 >= clusterIt.GetNextEntry()) {
175+
br->DropBaskets("all");
176+
}
177+
mTrackRefsLoaded[source][event] = true;
178+
}
179+
163180
bool MCKinematicsReader::initFromDigitContext(o2::steer::DigitizationContext const* context)
164181
{
165182
if (mInitialized) {
@@ -177,6 +194,7 @@ bool MCKinematicsReader::initFromDigitContext(o2::steer::DigitizationContext con
177194
mTracks.resize(mInputChains.size());
178195
mHeaders.resize(mInputChains.size());
179196
mIndexedTrackRefs.resize(mInputChains.size());
197+
mTrackRefsLoaded.resize(mInputChains.size());
180198

181199
// actual loading will be done only if someone asks
182200
// the first time for a particular source ...
@@ -210,6 +228,7 @@ bool MCKinematicsReader::initFromKinematics(std::string_view name)
210228
mTracks.resize(1);
211229
mHeaders.resize(1);
212230
mIndexedTrackRefs.resize(1);
231+
mTrackRefsLoaded.resize(1);
213232
mInitialized = true;
214233

215234
return true;

0 commit comments

Comments
 (0)