9#include <boost/serialization/variant.hpp>
12#include "GaudiKernel/FileIncident.h"
16 m_env = std::make_unique<mpi3::environment>(mpi3::thread_level::multiple);
18 if (
m_env->thread_support() != mpi3::thread_level::multiple) {
19 ATH_MSG_ERROR(
"MPI_THREAD_MULTIPLE is required but unavailable");
20 return StatusCode::FAILURE;
25 char version_string[MPI_MAX_LIBRARY_VERSION_STRING];
26 int version_string_len;
27 MPI_Get_library_version(version_string, &version_string_len);
33 <<
" ranks! This is insufficient!");
34 return StatusCode::FAILURE;
41 if (std::getenv(
"RANK") != std::to_string(
m_rank)) {
42 const char* env_rank = std::getenv(
"RANK");
44 <<
") does not match $RANK = " << env_rank);
48 m_mpiLog->createStatement(
"PRAGMA foreign_keys = ON").run();
52 "CREATE TABLE ranks (rank INTEGER PRIMARY KEY, "
53 "node TEXT, start_time FLOAT, end_time FLOAT)")
57 "INSERT INTO ranks (rank, node, start_time) "
58 "VALUES(?1, ?2, julianday('now'))")
62 "CREATE TABLE files (fileId INTEGER PRIMARY KEY, fileName TEXT)")
66 "CREATE TABLE event_log (rank INTEGER, id INTEGER UNIQUE,"
67 "inputFileId INTEGER,"
68 "runNumber INTEGER, eventNumber INTEGER, complete INTEGER,"
69 "status INTEGER, request_time_ns INTEGER, start_time FLOAT,"
70 "end_time FLOAT, PRIMARY KEY (runNumber, eventNumber, id), "
71 "FOREIGN KEY (rank) REFERENCES ranks(rank),"
72 "FOREIGN KEY (inputFileId) REFERENCES files(fileId))")
75 "INSERT INTO event_log(id, rank, inputFileId, runNumber, eventNumber, "
77 "start_time, request_time_ns) "
78 "VALUES(?1, ?4, ?6, ?2, ?3, 0, julianday('now'), ?5)");
80 "UPDATE event_log SET complete = 1, status = ?4, end_time = "
81 "julianday('now') WHERE runNumber = ?2 "
82 "AND eventNumber = ?3 AND id = ?1");
84 "INSERT INTO files (fileId, fileName) VALUES(?1, ?2)");
88 if (!incsvc.retrieve().isSuccess()) {
90 return (StatusCode::FAILURE);
92 incsvc->addListener(
this, IncidentType::BeginInputFile, 100);
93 incsvc->addListener(
this, IncidentType::BeginProcessing, 100);
95 return StatusCode::SUCCESS;
101 "UPDATE ranks SET end_time = julianday('now') WHERE rank = ?1")
103 return StatusCode::SUCCESS;
109 if (inc.type() == IncidentType::BeginProcessing) {
110 const std::size_t slot = Gaudi::Hive::currentContext().slot();
115 if (inc.type() == IncidentType::BeginInputFile) {
116 const FileIncident* fileInc =
dynamic_cast<const FileIncident*
>(&inc);
117 if (fileInc ==
nullptr) {
118 ATH_MSG_ERROR(
"BeginInputFile does not have a file name attached");
122 const std::string fileName = fileInc->fileName();
153 if (
m_rank != 0 && message.messageType == ClusterMessageType::RequestEvent &&
154 m_world.iprobe().has_value()) {
159 mpi3::communicator& comm =
161 if (message.messageType == ClusterMessageType::Data &&
164 "Event data should be sent with EventData communicator. "
170 const auto& [
header, body] = message.wire_msg();
171 comm.send_n(
header.begin(),
header.size(), destRank, 0);
172 if (body.has_value()) {
173 comm.send_n(body->begin(), body->size(), destRank,
header[2]);
174 if (message.messageType == ClusterMessageType::Data) {
177 char* ptr =
reinterpret_cast<char*
>((std::uint64_t(bdy[0]) << 32) +
178 std::uint64_t(bdy[1]));
179 std::size_t len = (std::uint64_t(bdy[2]) << 32) + std::uint64_t(bdy[3]);
183 constexpr int tag_offset = 16384;
184 comm.send_n(ptr, len, destRank,
header[2] + tag_offset);
191 constexpr int tag_offset = 16384;
192 constexpr std::uint64_t thirtytwo_ones = 0xFFFFFFFF;
195 mpi3::communicator& comm =
199 comm.receive_n(
head.begin(),
head.size());
201 if (
head[0] ==
int(ClusterMessageType::FinalWorkerStatus) ||
202 head[0] ==
int(ClusterMessageType::WorkerError) ||
203 head[0] ==
int(ClusterMessageType::Data)) {
205 comm.receive_n(body->begin(), body->size(),
head[1],
head[2]);
206 if (
head[0] ==
int(ClusterMessageType::Data)) {
209 std::size_t len = (std::uint64_t(bdy[2]) << 32) + std::uint64_t(bdy[3]);
210 std::size_t align = (std::uint64_t(bdy[4]) << 32) + std::uint64_t(bdy[5]);
211 std::size_t alloc_size = len;
212 if (!std::has_single_bit(align)) {
214 align = std::bit_ceil(align);
216 if (len % align != 0) {
221 alloc_size = (len + align - 1) & ~(align - 1);
224 char* ptr =
static_cast<char*
>(std::aligned_alloc(align, alloc_size));
225 comm.receive_n(ptr, len,
head[1],
head[2] + tag_offset);
228 bdy[0] = int(std::uint64_t(ptr) >> 32);
229 bdy[1] = int(std::uint64_t(ptr) & thirtytwo_ones);
239 std::int64_t event_number,
240 std::int64_t request_time_ns,
247 std::int64_t event_number,
248 std::int64_t status) {
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
C++ native wrapper for the C xxhash API.
std::int64_t m_lastInputFileHash
virtual ClusterMessage waitReceiveMessage(ClusterComm communicator=ClusterComm::Default) override final
Block until we receive an MPI message.
virtual void barrier() override final
Insert a barrier No rank will continue until all ranks reach this point.
virtual void log_addEvent(int eventIdx, std::int64_t run_number, std::int64_t event_number, std::int64_t request_time_ns, std::size_t slot) override final
Add (begin) an event in the log.
SQLite::Statement m_mpiLog_addFile
std::unique_ptr< mpi3::environment > m_env
SQLite::Statement m_mpiLog_addEvent
virtual void handle(const Incident &inc) override
IIncidentListener handle.
virtual void abort() override final
Abort the MPI run.
virtual int rank() const override final
Return our rank.
mpi3::communicator m_world
virtual StatusCode initialize() override final
Initialize.
mpi3::communicator m_datacom
virtual StatusCode finalize() override final
Finalize.
virtual void log_completeEvent(int eventIdx, std::int64_t run_number, std::int64_t event_number, std::int64_t status) override final
Complete an event in the log.
SQLite::Statement m_mpiLog_completeEvent
virtual void sendMessage(int destRank, ClusterMessage message, ClusterComm communicator=ClusterComm::Default) override final
Send an MPI message.
ServiceHandle< ISQLiteDBSvc > m_mpiLog
virtual int numRanks() const override final
Return number of ranks.
std::map< std::size_t, std::int64_t > m_inputFileSlotMap
std::string head(std::string s, const std::string &pattern)
head of a string
std::uint64_t hash64(const void *data, std::size_t size)
Passthrough to XXH3_64bits.
A class describing a message sent between nodes in a cluster.
std::tuple< WireMsgHdr, std::optional< WireMsgBody > > WireMsg
std::array< std::uint32_t, 10 > WireMsgBody