Skip to content

Commit 2b8e799

Browse files
committed
Implemented automatic parallelisation for external generator on HY
1 parent b122c5f commit 2b8e799

4 files changed

Lines changed: 77 additions & 6 deletions

File tree

Generators/include/Generators/Generator.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ class Generator : public FairGenerator
9999
const std::vector<TParticle>& getParticles() const { return mParticles; }; //!
100100
static unsigned int getTotalNEvents() { return gTotalNEvents; };
101101

102+
// Check if simulation is running in Hyperloop mode
103+
static bool isHyperloop();
104+
105+
// Number of parallel sub-generator clones a Hyperloop-aware generator expands into
106+
// (currently used by the external-generator-to-hybrid expansion in GeneratorFactory).
107+
static constexpr int NHyperloopParallelGenerators = 8;
108+
102109
/** other **/
103110
void clearParticles() { mParticles.clear(); };
104111

Generators/include/Generators/GeneratorPythia8.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class GeneratorPythia8 : public Generator
264264
void seedGenerator();
265265

266266
// Hyperloop flag
267-
const bool mIsHyperloop = std::getenv("IS_HYPERLOOP") && std::atoi(std::getenv("IS_HYPERLOOP"));
267+
const bool mIsHyperloop = Generator::isHyperloop();
268268

269269
/** Pythia8 **/
270270
// Show banner only when not running in Hyperloop

Generators/src/Generator.cxx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "TGrid.h"
2929
#include "CCDB/BasicCCDBManager.h"
3030
#include <filesystem>
31+
#include <cstdlib>
3132
#ifdef GENERATORS_WITH_TPCLOOPERS
3233
#include "Generators/TPCLoopers.h"
3334
#include "Generators/TPCLoopersParam.h"
@@ -40,6 +41,12 @@ namespace eventgen
4041

4142
std::atomic<int> Generator::InstanceCounter{0};
4243
unsigned int Generator::gTotalNEvents = 0;
44+
45+
bool Generator::isHyperloop()
46+
{
47+
static const bool isHY = std::getenv("IS_HYPERLOOP") && std::atoi(std::getenv("IS_HYPERLOOP"));
48+
return isHY;
49+
}
4350
/*****************************************************************/
4451
/*****************************************************************/
4552

Generators/src/GeneratorFactory.cxx

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
3535
#include <Generators/GeneratorHybrid.h>
3636
#include <Generators/GeneratorHybridParam.h>
37+
#include <rapidjson/document.h>
38+
#include <rapidjson/writer.h>
39+
#include <rapidjson/ostreamwrapper.h>
40+
#include <fstream>
41+
#include <unistd.h>
3742
#endif
3843
#include <Generators/PrimaryGenerator.h>
3944
#include <Generators/BoxGunParam.h>
@@ -49,6 +54,48 @@ namespace o2
4954
namespace eventgen
5055
{
5156

57+
#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
58+
// Builds a parallel GeneratorHybrid JSON configuration out of
59+
// 8 (Generator::NHyperloopParallelGenerators) identical "external" sub-generator entries,
60+
// using the configured GeneratorExternalParam. This makes the simulation parallelisation automatic
61+
// on Hyperloop.
62+
// To-do: Define the behaviour with ini configuration which are already definining a hybrid gen
63+
std::string buildHyperloopExternalHybridConfig(GeneratorExternalParam const& extparams)
64+
{
65+
rapidjson::Document doc;
66+
doc.SetObject();
67+
auto& alloc = doc.GetAllocator();
68+
doc.AddMember("mode", "parallel", alloc);
69+
70+
rapidjson::Value generators(rapidjson::kArrayType);
71+
rapidjson::Value fractions(rapidjson::kArrayType);
72+
for (int i = 0; i < Generator::NHyperloopParallelGenerators; ++i) {
73+
rapidjson::Value config(rapidjson::kObjectType);
74+
config.AddMember("fileName", rapidjson::Value(extparams.fileName.c_str(), alloc), alloc);
75+
config.AddMember("funcName", rapidjson::Value(extparams.funcName.c_str(), alloc), alloc);
76+
config.AddMember("iniFile", "", alloc);
77+
78+
rapidjson::Value generator(rapidjson::kObjectType);
79+
generator.AddMember("name", "external", alloc);
80+
generator.AddMember("config", config, alloc);
81+
generators.PushBack(generator, alloc);
82+
fractions.PushBack(1, alloc);
83+
}
84+
doc.AddMember("generators", generators, alloc);
85+
doc.AddMember("fractions", fractions, alloc);
86+
87+
std::string path = "hyperloop_exttohybrid_" + std::to_string(getpid()) + ".json";
88+
std::ofstream ofs(path);
89+
if (!ofs.is_open()) {
90+
LOG(fatal) << "Failed to open " << path << " for writing the Hyperloop hybrid generator configuration";
91+
}
92+
rapidjson::OStreamWrapper osw(ofs);
93+
rapidjson::Writer<rapidjson::OStreamWrapper> writer(osw);
94+
doc.Accept(writer);
95+
return path;
96+
}
97+
#endif
98+
5299
// reusable helper class
53100
// main purpose is to init a FairPrimGen given some (Sim)Config
54101
void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, FairPrimaryGenerator* primGen)
@@ -94,9 +141,20 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair
94141
o2::O2DatabasePDG::addALICEParticles(TDatabasePDG::Instance());
95142
auto genconfig = conf.getGenerator();
96143
#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
97-
if (GeneratorHybridParam::Instance().switchExtToHybrid && (genconfig.compare("external") == 0 || genconfig.compare("extgen") == 0)) {
98-
LOG(info) << "Switching external generator to hybrid mode";
99-
genconfig = "hybrid";
144+
std::string hyperloopExtHybridConfigFile; // set when IS_HYPERLOOP is defined
145+
if (genconfig.compare("external") == 0 || genconfig.compare("extgen") == 0) {
146+
if (GeneratorHybridParam::Instance().switchExtToHybrid) {
147+
LOG(info) << "Switching external generator to hybrid mode";
148+
genconfig = "hybrid";
149+
} else if (Generator::isHyperloop()) {
150+
// Running under Hyperloop: transparently expand the single external generator
151+
// configuration into a parallel hybrid of Generator::NHyperloopParallelGenerators
152+
// clones, to increase on-the-fly MC-generation throughput.
153+
LOG(info) << "IS_HYPERLOOP detected: expanding external generator into "
154+
<< Generator::NHyperloopParallelGenerators << " parallel hybrid sub-generators";
155+
hyperloopExtHybridConfigFile = buildHyperloopExternalHybridConfig(GeneratorExternalParam::Instance());
156+
genconfig = "hybrid";
157+
}
100158
}
101159
#endif
102160
LOG(info) << "** Generator to use: '" << genconfig << "'";
@@ -278,8 +336,7 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair
278336
#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3)
279337
} else if (genconfig.compare("hybrid") == 0) { // hybrid using multiple generators
280338
LOG(info) << "Init hybrid generator";
281-
auto& hybridparam = GeneratorHybridParam::Instance();
282-
std::string config = hybridparam.configFile;
339+
std::string config = !hyperloopExtHybridConfigFile.empty() ? hyperloopExtHybridConfigFile : GeneratorHybridParam::Instance().configFile;
283340
// check if config string points to an existing and not empty file
284341
if (config.empty()) {
285342
LOG(fatal) << "No configuration file provided for hybrid generator";

0 commit comments

Comments
 (0)