Skip to content

Commit 0d0bc49

Browse files
committed
Fix CPU accounting for external generator subprocesses
GeneratorFileOrCmd forks an external generator but the child was only reaped from ~GeneratorHepMC(), which is not reached on the DPL device teardown path. Its CPU therefore never showed up in RUSAGE_CHILDREN. Generators: add Generator::stop(), called from GeneratorTask::run() once the stream ends, to reap the child deterministically. Framework: add a Monitoring .stop callback to take the final CPU measurement on the RUNNING -> READY transition. This also covers devices that end their own stream via readyToQuit(), for which postEOS is never invoked. Fixes https://its.cern.ch/jira/browse/O2-7096 Assisted by Claude Opus 5
1 parent 94d9198 commit 0d0bc49

7 files changed

Lines changed: 43 additions & 1 deletion

File tree

Framework/Core/src/CommonServices.cxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ o2::framework::ServiceSpec CommonServices::monitoringSpec()
127127
monitoring->setRunNumber(std::stoul(extRunNumber));
128128
} catch (...) {
129129
} },
130+
// Final measurement here rather than in ~Monitoring() at .exit, which is
131+
// not reliably reached before the process exits. Unlike postEOS this also
132+
// covers devices that quit themselves via readyToQuit().
133+
.stop = [](ServiceRegistryRef, void* service) {
134+
auto* monitoring = reinterpret_cast<Monitoring*>(service);
135+
monitoring->finalizeProcessMonitoring(); },
130136
.exit = [](ServiceRegistryRef registry, void* service) {
131137
auto* monitoring = reinterpret_cast<Monitoring*>(service);
132138
monitoring->flushBuffer();

Generators/include/Generators/Generator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ class Generator : public FairGenerator
105105
/** notification methods **/
106106
virtual void notifyEmbedding(const o2::dataformats::MCEventHeader* eventHeader){};
107107

108+
/** Release external resources (forked subprocesses, open files, ...) once
109+
* the generator is no longer needed, without relying on destructor timing **/
110+
virtual void stop() {}
111+
108112
void setTriggerOkHook(std::function<void(std::vector<TParticle> const& p, int eventCount)> f) { mTriggerOkHook = f; }
109113
void setTriggerFalseHook(std::function<void(std::vector<TParticle> const& p, int eventCount)> f) { mTriggerFalseHook = f; }
110114

Generators/include/Generators/GeneratorHepMC.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ class GeneratorHepMC : public Generator, public GeneratorFileOrCmd
8686
*/
8787
Bool_t importParticles() override;
8888

89+
/** Terminate the background command (if any), see Generator::stop(). */
90+
void stop() override;
91+
8992
/** setters **/
9093
void setEventsToSkip(uint64_t val) { mEventsToSkip = val; };
9194
void setVersion(const int& ver) { mVersion = ver; };

Generators/include/Generators/GeneratorService.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class GeneratorService
7070
void generateEvent_MCTracks(o2::pmr::vector<MCTrack>& tracks, o2::dataformats::MCEventHeader& header);
7171
void generateEvent_TParticles(std::vector<TParticle>& tparts, o2::dataformats::MCEventHeader& header);
7272

73+
/** Calls Generator::stop() on all registered generators **/
74+
void stopGenerators();
75+
7376
private:
7477
PrimaryGenerator mPrimGen;
7578
o2::data::Stack mStack;

Generators/src/GeneratorHepMC.cxx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,20 @@ GeneratorHepMC::~GeneratorHepMC()
6666
if (mEvent) {
6767
delete mEvent;
6868
}
69+
stop();
70+
removeTemp();
71+
}
72+
73+
/*****************************************************************/
74+
75+
void GeneratorHepMC::stop()
76+
{
6977
if (not mCmd.empty()) {
7078
// Must be executed before removing the temporary file
7179
// otherwise the current child process might still be writing on it
7280
// causing unwanted stdout messages which could slow down the system
7381
terminateCmd();
7482
}
75-
removeTemp();
7683
}
7784

7885
/*****************************************************************/

Generators/src/GeneratorService.cxx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include "SimConfig/SimConfig.h"
1515
#include "Generators/Generator.h"
1616
#include "DataFormatsCalibration/MeanVertexObject.h"
17+
#include <TCollection.h>
18+
#include <TObjArray.h>
1719

1820
using namespace o2::eventgen;
1921

@@ -90,3 +92,17 @@ void GeneratorService::generateEvent_TParticles(std::vector<TParticle>& tracks,
9092
tracks.clear();
9193
tracks = mStack.getPrimaries();
9294
}
95+
96+
void GeneratorService::stopGenerators()
97+
{
98+
auto* generators = mPrimGen.GetListOfGenerators();
99+
if (!generators) {
100+
return;
101+
}
102+
TIter next(generators);
103+
while (TObject* obj = next()) {
104+
if (auto* gen = dynamic_cast<o2::eventgen::Generator*>(obj)) {
105+
gen->stop();
106+
}
107+
}
108+
}

run/dpl_eventgen.cxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ struct GeneratorTask {
132132
}
133133
}
134134
if (eventCounter >= nEvents || time_expired) {
135+
// terminate and reap external generator subprocesses here: device
136+
// teardown is not guaranteed to run the generators' destructors
137+
genservice->stopGenerators();
135138
pc.services().get<ControlService>().endOfStream();
136139
pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
137140

0 commit comments

Comments
 (0)