Skip to content

Commit 033437c

Browse files
sawenzelclaude
andcommitted
Spawn the o2-sim hit merger before the sim workers
The merger is now listening when the workers send their first hits, so fast workers (e.g. with --noGeant) no longer wait for it at exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 6cf9a20 commit 033437c

1 file changed

Lines changed: 43 additions & 41 deletions

File tree

‎run/o2sim_parallel.cxx‎

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -634,43 +634,8 @@ int main(int argc, char* argv[])
634634
sleep(1); // otherwise wait until server is initialized
635635
}
636636

637-
auto internalfork = getenv("ALICE_SIMFORKINTERNAL");
638-
if (internalfork) {
639-
// forking will be done internally to profit from copy-on-write
640-
nworkers = 1;
641-
}
642-
for (int id = 0; id < nworkers; ++id) {
643-
// the workers
644-
std::stringstream workerlogss;
645-
workerlogss << getWorkerLogName() << id;
646-
647-
// the workers
648-
std::stringstream workerss;
649-
workerss << "worker" << id;
650-
651-
pid = fork();
652-
if (pid == 0) {
653-
int fd = open(workerlogss.str().c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
654-
dup2(fd, 1); // make stdout go to file
655-
dup2(fd, 2); // make stderr go to file - you may choose to not do this
656-
// or perhaps send stderr to another file
657-
close(fd); // fd no longer needed - the dup'ed handles are sufficient
658-
659-
const std::string name("o2-sim-device-runner");
660-
const std::string path = installpath + "/" + name;
661-
662-
execl(path.c_str(), name.c_str(), "--control", "static", "--id", workerss.str().c_str(), "--config-key",
663-
"worker", "--mq-config", localconfig.c_str(), "--severity", "info", (char*)nullptr);
664-
return 0;
665-
} else {
666-
gChildProcesses.push_back(pid);
667-
setpgid(pid, pid); // the worker processes will form their own group
668-
std::cout << "Spawning sim worker " << id << " on PID " << pid
669-
<< "; Redirect output to " << workerlogss.str() << "\n";
670-
}
671-
}
672-
673-
// the hit merger
637+
int mergerpid = -1;
638+
// the hit merger, spawned before the workers so that it listens when they send hits
674639
int pipe_mergerdriver_fd[2];
675640
if (pipe(pipe_mergerdriver_fd) != 0) {
676641
perror("problem in creating pipe");
@@ -679,6 +644,7 @@ int main(int argc, char* argv[])
679644
pid = fork();
680645

681646
std::atomic<bool> shutdown_initiated = false;
647+
std::function<bool(std::vector<int> const&)> finishCallback;
682648
if (pid == 0) {
683649
int fd = open(getMergerLogName().c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
684650
dup2(fd, 1); // make stdout go to file
@@ -696,12 +662,13 @@ int main(int argc, char* argv[])
696662
std::cout << "Spawning hit merger on PID " << pid << "; Redirect output to " << getMergerLogName() << "\n";
697663
setpgid(pid, pid);
698664
gChildProcesses.push_back(pid);
665+
mergerpid = pid;
699666
close(pipe_mergerdriver_fd[1]);
700667

701668
// A simple callback that determines if the simulation is complete and triggers
702669
// a shutdown of all child processes. This appears to be more robust than leaving
703670
// that decision upon the children (sometimes there are problems with that).
704-
auto finishCallback = [&shutdown_initiated, &conf, &externalpublishchannel](std::vector<int> const& v) {
671+
finishCallback = [&shutdown_initiated, &conf, &externalpublishchannel](std::vector<int> const& v) {
705672
std::stringstream str;
706673
str << "EVENT " << v.back() << " FINISHED " << gAskedEvents << " " << v.size();
707674
o2::simpubsub::publishMessage(externalpublishchannel, o2::simpubsub::simStatusString("O2SIM", "INFO", str.str()));
@@ -723,13 +690,48 @@ int main(int argc, char* argv[])
723690
}
724691
return true;
725692
};
693+
}
726694

727-
launchThreadMonitoringEvents(pipe_mergerdriver_fd[0], "EVENT FINISHED : ", gFinishedEvents, finishCallback);
695+
auto internalfork = getenv("ALICE_SIMFORKINTERNAL");
696+
if (internalfork) {
697+
// forking will be done internally to profit from copy-on-write
698+
nworkers = 1;
728699
}
700+
for (int id = 0; id < nworkers; ++id) {
701+
// the workers
702+
std::stringstream workerlogss;
703+
workerlogss << getWorkerLogName() << id;
729704

730-
// wait on merger (which when exiting completes the workflow)
731-
auto mergerpid = gChildProcesses.back();
705+
// the workers
706+
std::stringstream workerss;
707+
workerss << "worker" << id;
708+
709+
pid = fork();
710+
if (pid == 0) {
711+
int fd = open(workerlogss.str().c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
712+
dup2(fd, 1); // make stdout go to file
713+
dup2(fd, 2); // make stderr go to file - you may choose to not do this
714+
// or perhaps send stderr to another file
715+
close(fd); // fd no longer needed - the dup'ed handles are sufficient
716+
717+
const std::string name("o2-sim-device-runner");
718+
const std::string path = installpath + "/" + name;
719+
720+
execl(path.c_str(), name.c_str(), "--control", "static", "--id", workerss.str().c_str(), "--config-key",
721+
"worker", "--mq-config", localconfig.c_str(), "--severity", "info", (char*)nullptr);
722+
return 0;
723+
} else {
724+
gChildProcesses.push_back(pid);
725+
setpgid(pid, pid); // the worker processes will form their own group
726+
std::cout << "Spawning sim worker " << id << " on PID " << pid
727+
<< "; Redirect output to " << workerlogss.str() << "\n";
728+
}
729+
}
732730

731+
// monitor the merger only once all child pids are known to the shutdown callback
732+
launchThreadMonitoringEvents(pipe_mergerdriver_fd[0], "EVENT FINISHED : ", gFinishedEvents, finishCallback);
733+
734+
// wait on merger (which when exiting completes the workflow)
733735
int status, cpid;
734736
// wait just blocks and waits until any child returns; but we make sure to wait until merger is here
735737
bool errored = false;

0 commit comments

Comments
 (0)