ATLAS Offline Software
Loading...
Searching...
No Matches
PileUpMTAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// PileUpMT includes
6#include "PileUpMTAlg.h"
7
8#include <CxxUtils/XXH.h>
9#include <unistd.h>
10
11#include <boost/core/demangle.hpp>
12#include <ranges>
13
14#include <chrono>
15#include <format>
16
18#include "EventInfo/EventInfo.h"
19#include <tuple>
20
22#include "CLHEP/Random/RandPoisson.h"
23#include "CLHEP/Random/RandomEngine.h"
31
33namespace rv = std::views;
34
35inline std::string CLIDToString(const CLID& clid) {
36 return boost::core::demangle(CLIDRegistry::CLIDToTypeinfo(clid)->name());
37}
38
39PileUpMTAlg::PileUpMTAlg(const std::string& name, ISvcLocator* pSvcLocator)
40 : AthAlgorithm(name, pSvcLocator) {}
41
43
45 std::unique_ptr<const xAOD::EventInfo>& ei_,
46 std::unique_ptr<xAOD::EventAuxInfo>& ei_aux_,
47 bool pileup) const {
48 std::string key = pileup ? "EventInfo" : "HSEventInfo";
49 auto newEi = std::make_unique<xAOD::EventInfo>();
50 auto eiAux = std::make_unique<xAOD::EventAuxInfo>();
51 newEi->setStore(eiAux.get());
52 SG::ReadHandle<xAOD::EventInfo> ei_h(key, sg.name());
53 const xAOD::EventInfo* ei = ei_h.get();
54 if (ei != nullptr) {
55 *newEi = *ei;
56 } else {
57 ATH_MSG_ERROR("Couldn't find xAOD::EventInfo. " << sg.name());
58 ATH_MSG_ERROR(sg.dump());
59 return StatusCode::FAILURE;
60 }
61 // Use attribute list if EventInfo doesn't have event numbers set
62 if (newEi->eventNumber() == 0) {
63 const auto* attr_list_p = sg.tryConstRetrieve<AthenaAttributeList>("Input");
64 if (attr_list_p != nullptr) {
65 if (attr_list_p->size() <= 6) {
66 ATH_MSG_WARNING("Read Input attribute list but size <= 6");
67 } else {
68 const AthenaAttributeList& attr_list = *attr_list_p;
69 const auto runNum = attr_list["RunNumber"].data<unsigned>();
70 const auto evtNum = attr_list["EventNumber"].data<unsigned long long>();
71 const auto lbNum = attr_list["LumiBlockN"].data<unsigned>();
72 newEi->setRunNumber(runNum);
73 newEi->setLumiBlock(lbNum);
74 newEi->setEventNumber(evtNum);
75 }
76 } else {
78 "Could not read Input attribute list and EventInfo has no event "
79 "number");
80 }
81 }
82 newEi->setEvtStore(&sg);
83 ei_ = std::move(newEi);
84 ei_aux_ = std::move(eiAux);
85 return StatusCode::SUCCESS;
86}
87
89 const std::vector<std::uint32_t>& bcid,
93 int bc, const EventContext& ctx, unsigned long subevt_id,
94 std::vector<std::uint64_t>& trace) {
95 // Keep the code to add and process a subevent in one place
96 const unsigned int bc_idx = bc - m_earliestDeltaBC;
97 StoreGateSvc* sg = mbSvc->getMinbias(ctx, subevt_id);
98 std::unique_ptr<const xAOD::EventInfo> ei;
99 std::unique_ptr<xAOD::EventAuxInfo> eiAux;
100 ATH_CHECK(get_ei(*sg, ei, eiAux, true));
101 xAOD::EventInfo mb_to_modify(*ei);
102 if (m_writeTrace) {
103 trace.push_back(mb_to_modify.eventNumber());
104 }
105 mb_to_modify.setBCID(bcid[bc_idx]);
106 try {
107 addSubEvent(overlaidEvt.ptr(), &mb_to_modify, bc * m_BCSpacing, puType,
108 puCont.ptr(), m_evtInfoContKey.key(), sg);
109 } catch (const std::exception& e) {
110 ATH_MSG_ERROR("Caught exception adding subevent: " << e.what());
111 return StatusCode::FAILURE;
112 }
113 return StatusCode::SUCCESS;
114}
115
117 using namespace std::chrono;
118 ATH_MSG_DEBUG("Initializing " << name() << "...");
119 if (m_writeTrace) {
120 std::string filename = std::format("pileup_trace_skipping-{}_{:%Y-%m-%dT%H%M}.txt",
121 m_skippedHSEvents.value(),
122 system_clock::now());
123 if (!m_pileupTrace.init(filename)) {
124 ATH_MSG_ERROR("Cannot append to file " << filename);
125 return StatusCode::FAILURE;
126 }
127 }
128 ATH_CHECK(m_skipEventIdxSvc.retrieve());
129 ATH_CHECK(m_rngSvc.retrieve());
130 if (m_fracLowPt != 0) {
131 ATH_CHECK(m_lowptMBSvc.retrieve());
132 }
133 if (m_fracHighPt != 0) {
134 ATH_CHECK(m_highptMBSvc.retrieve());
135 }
136 if (m_numCavern != 0) {
137 ATH_CHECK(m_cavernMBSvc.retrieve());
138 }
139 if (m_numBeamGas != 0) {
140 ATH_CHECK(m_beamgasMBSvc.retrieve());
141 }
142 if (m_numBeamHalo != 0) {
143 ATH_CHECK(m_beamhaloMBSvc.retrieve());
144 }
145 ATH_CHECK(m_beamInt.retrieve());
146 ATH_CHECK(m_beamLumi.retrieve());
147 ATH_CHECK(m_puTools.retrieve());
148
149 m_evtInfoContKey = "PileUpEventInfo";
150 ATH_CHECK(m_evtInfoKey.initialize());
151 ATH_CHECK(m_evtInfoContKey.initialize());
152 ATH_CHECK(m_beamSpotKey.initialize());
153
154 // Trace skipped events
155 if (m_writeTrace) {
157 ISkipEventIdxSvc::EvtIter end) -> StatusCode {
158 std::string trace_buf{};
159 auto trace = std::back_inserter(trace_buf);
160 for (; it != end; ++it) {
161 std::format_to(trace, "SKIPPING Run: {} LB: {} EVT: {} HS ID: {}\n",
162 it->runNum, it->lbNum, it->evtNum, it->evtIdx);
163 }
164 m_pileupTrace.print(trace_buf);
165 return StatusCode::SUCCESS;
166 };
167 if (!m_skiptrace_written) {
168 ATH_CHECK(m_skipEventIdxSvc->registerCallback(handler));
169 m_skiptrace_written = true;
170 }
171 }
172 return StatusCode::SUCCESS;
173}
174
176 ATH_MSG_DEBUG("Finalizing " << name() << "...");
177 //
178 // Things that happen once at the end of the event loop go here
179 //
180
181 return StatusCode::SUCCESS;
182}
183
184StatusCode PileUpMTAlg::execute(const EventContext& ctx) {
185 using PUType = xAOD::EventInfo::PileUpType;
186 std::string trace_buf{}; // Hold trace of events.
187 auto trace = std::back_inserter(trace_buf);
188 ATH_MSG_DEBUG("Executing " << name() << "...");
189 const auto& evtID = ctx.eventID();
190
191 ATH_CHECK(evtStore().retrieve());
192 setFilterPassed(false, ctx); // optional: start with algorithm not passed
193
194 // Code based on PileUpEventLoopMgr and PileUpToolsAlg (trying to extract the
195 // core merging code) Read hard scatter
196 std::unique_ptr<const xAOD::EventInfo> hsEvt = nullptr;
197 std::unique_ptr<xAOD::EventAuxInfo> hsEvtAux = nullptr;
198 ATH_CHECK(get_ei(*evtStore(), hsEvt, hsEvtAux));
199
200 // Setup overlaid event
202 ATH_CHECK(overlaidEvt.record(std::make_unique<xAOD::EventInfo>(),
203 std::make_unique<xAOD::EventAuxInfo>()));
204 *overlaidEvt = *hsEvt; // copy in hard scatter
205 overlaidEvt->setEvtStore(evtStore().get());
206 overlaidEvt->clearSubEvents();
207
208 // This was the problem. Need to fix overlaidEvt using context run and lb
209 // number
210 overlaidEvt->setRunNumber(evtID.run_number());
211 overlaidEvt->setLumiBlock(evtID.lumi_block());
212 overlaidEvt->setEventNumber(evtID.event_number());
213 overlaidEvt->setBCID(evtID.bunch_crossing_id());
214 overlaidEvt->setTimeStamp(evtID.time_stamp());
215 overlaidEvt->setTimeStampNSOffset(evtID.time_stamp_ns_offset());
216 // Set beam spot info
218 if (!beamSpotHandle.isValid()) {
219 ATH_MSG_ERROR("Beam spot information not valid");
220 return StatusCode::FAILURE;
221 }
222
223 overlaidEvt->setBeamPos(beamSpotHandle->beamPos()[Amg::x],
224 beamSpotHandle->beamPos()[Amg::y],
225 beamSpotHandle->beamPos()[Amg::z]);
226 overlaidEvt->setBeamPosSigma(beamSpotHandle->beamSigma(0),
227 beamSpotHandle->beamSigma(1),
228 beamSpotHandle->beamSigma(2));
229 overlaidEvt->setBeamPosSigmaXY(beamSpotHandle->beamSigmaXY());
230 overlaidEvt->setBeamTiltXZ(beamSpotHandle->beamTilt(0));
231 overlaidEvt->setBeamTiltYZ(beamSpotHandle->beamTilt(1));
232 overlaidEvt->setBeamStatus(beamSpotHandle->beamStatus());
233
234 // Pileup container
236 ATH_CHECK(puCont.record(std::make_unique<xAOD::EventInfoContainer>(),
237 std::make_unique<xAOD::EventInfoAuxContainer>()));
238
239 // Get crossing number
240 m_beamInt->selectT0(ctx);
241 overlaidEvt->setBCID(m_beamInt->getCurrentT0BunchCrossing());
242
243 // Set simulation bit
244 overlaidEvt->setEventTypeBitmask(hsEvt->eventTypeBitmask() |
246
247 // Set properties
248 bool sf_updated = false;
249 float lumi_sf = m_beamLumi->scaleFactor(evtID.run_number(),
250 evtID.lumi_block(), sf_updated);
251 float cur_avg_mu = lumi_sf * m_avgMu;
252 overlaidEvt->setAverageInteractionsPerCrossing(cur_avg_mu);
253 overlaidEvt->setActualInteractionsPerCrossing(m_beamInt->normFactor(0) *
254 cur_avg_mu);
255
256 // Trace
257 if (m_writeTrace) {
258 std::format_to(trace,
259 "Idx: {} Run: {} LB: {} EVT: {} "
260 "HS ID: {}\n",
261 ctx.evt(), evtID.run_number(), evtID.lumi_block(),
262 evtID.event_number(), m_lowptMBSvc->get_hs_id(ctx));
263 auto bunch_pattern = (rv::iota(m_earliestDeltaBC.value(), m_latestDeltaBC.value() + 1)
264 | rv::transform([this](int bc) { return int(m_beamInt->normFactor(bc));})
265 | rv::chunk_by(std::equal_to{})
266 | rv::transform([](auto&& chunk) { return std::format("{}{}", std::ranges::distance(chunk), *chunk.begin() == 0 ? 'E' : 'F');}))
267 | std::ranges::to<std::vector<std::string>>();
268 // Manual join using std::ostringstream as std::format does not support ranges
269 std::string joined_pattern;
270 for (size_t i = 0; i < bunch_pattern.size(); ++i) {
271 joined_pattern += bunch_pattern[i];
272 if (i + 1 < bunch_pattern.size()) {
273 joined_pattern += " ";
274 }
275 }
276
277 std::format_to(trace,
278 "mu = {}, central BCID = {}, bunch pattern = [{}]\n",
279 cur_avg_mu, m_beamInt->getCurrentT0BunchCrossing(),
280 joined_pattern);
281 }
282 // Copy subevents
283 if (!hsEvt->subEvents().empty()) {
284 for (const SubEvent& se : hsEvt->subEvents()) {
285 addSubEvent(overlaidEvt.ptr(), se, puCont.ptr(), m_evtInfoContKey.key(),
286 evtStore().get());
287 }
288 } else {
289 // if no subevents, add original event
290 addSubEvent(overlaidEvt.ptr(), hsEvt.get(), 0, xAOD::EventInfo::Signal,
291 puCont.ptr(), m_evtInfoContKey.key(), evtStore().get());
292 }
293
294 // Initialize MinbiasSvcs
295 if (m_fracLowPt != 0) {
296 ATH_CHECK(m_lowptMBSvc->beginHardScatter(ctx));
297 }
298 if (m_fracHighPt != 0) {
299 ATH_CHECK(m_highptMBSvc->beginHardScatter(ctx));
300 }
301 if (m_numCavern != 0) {
302 ATH_CHECK(m_cavernMBSvc->beginHardScatter(ctx));
303 }
304 if (m_numBeamHalo != 0) {
305 ATH_CHECK(m_beamhaloMBSvc->beginHardScatter(ctx));
306 }
307 if (m_numBeamGas != 0) {
308 ATH_CHECK(m_beamgasMBSvc->beginHardScatter(ctx));
309 }
310
311 std::uint32_t central_bcid = overlaidEvt->bcid();
312 std::vector<std::uint32_t> bcid{};
313 bcid.reserve(m_latestDeltaBC - m_earliestDeltaBC + 1);
314
315 for (int bc = m_earliestDeltaBC; bc <= m_latestDeltaBC; ++bc) {
316 bcid.push_back(get_BCID(bc, central_bcid));
317 }
318
319 // Setup tools
320 for (auto&& tool : m_puTools) {
321 // Reset filter -- Don't know if this is necessary
322 tool->resetFilter();
323 }
324
325 // Now add the events
326 std::uint64_t low_pt_count = 0;
327 std::uint64_t high_pt_count = 0;
328 std::uint64_t cavern_count = 0;
329 std::uint64_t beam_halo_count = 0;
330 std::uint64_t beam_gas_count = 0;
331 auto now = std::chrono::high_resolution_clock::now();
332 for (int bc = m_earliestDeltaBC; bc <= m_latestDeltaBC; ++bc) {
333 if (m_beamInt->normFactor(bc) == 0.) {
334 // skip empty bunch crossings
335 continue;
336 }
337 std::vector<std::uint64_t> subevts_vec{};
338 if (m_fracLowPt != 0) {
339 if (m_writeTrace) {
340 std::format_to(trace, "\tBC {:03} : LOW PT {} ", bc,
341 m_lowptMBSvc->getNumForBunch(ctx, bc));
342 }
343 for (std::size_t i = 0; i < m_lowptMBSvc->getNumForBunch(ctx, bc); ++i) {
344 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_lowptMBSvc,
345 PUType::MinimumBias, bc, ctx, low_pt_count,
346 subevts_vec));
347 ++low_pt_count;
348 }
349 }
350 if (m_fracHighPt != 0) {
351 if (m_writeTrace) {
352 std::format_to(trace, "HIGH PT {} | ",
353 m_highptMBSvc->getNumForBunch(ctx, bc));
354 }
355 for (std::size_t i = 0; i < m_highptMBSvc->getNumForBunch(ctx, bc); ++i) {
356 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_highptMBSvc,
357 PUType::HighPtMinimumBias, bc, ctx, high_pt_count,
358 subevts_vec));
359 ++high_pt_count;
360 }
361 }
362 if (m_numCavern != 0) {
363 if (m_writeTrace) {
364 std::format_to(trace, "CAVERN {} | ",
365 m_cavernMBSvc->getNumForBunch(ctx, bc));
366 }
367 for (std::size_t i = 0; i < m_cavernMBSvc->getNumForBunch(ctx, bc); ++i) {
368 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_cavernMBSvc,
369 PUType::Cavern, bc, ctx, cavern_count,
370 subevts_vec));
371 ++cavern_count;
372 }
373 }
374 if (m_numBeamHalo != 0) {
375 if (m_writeTrace) {
376 std::format_to(trace, "BEAM HALO {} | ",
377 m_beamhaloMBSvc->getNumForBunch(ctx, bc));
378 }
379 for (std::size_t i = 0; i < m_beamhaloMBSvc->getNumForBunch(ctx, bc);
380 ++i) {
381 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_beamhaloMBSvc,
382 PUType::HaloGas, bc, ctx, beam_halo_count,
383 subevts_vec));
384 ++beam_halo_count;
385 }
386 }
387 if (m_numBeamGas != 0) {
388 if (m_writeTrace) {
389 std::format_to(trace, "BEAM GAS {} | ",
390 m_beamgasMBSvc->getNumForBunch(ctx, bc));
391 }
392 for (std::size_t i = 0; i < m_beamgasMBSvc->getNumForBunch(ctx, bc);
393 ++i) {
394 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_beamgasMBSvc,
395 PUType::HaloGas, bc, ctx, beam_gas_count,
396 subevts_vec));
397 ++beam_gas_count;
398 }
399 }
400 if (m_writeTrace) {
401 std::format_to(trace, "TOTAL {} | HASH {:08X}\n", subevts_vec.size(),
402 xxh3::hash64(subevts_vec));
403 }
404 }
405 if (m_writeTrace) {
406 std::format_to(trace, "\n");
407 m_pileupTrace.print(trace_buf);
408 }
409
410 for (auto&& tool : m_puTools) {
411 try {
412 ATH_CHECK(tool->processAllSubEvents(ctx));
413 } catch (const std::exception& e) {
414 ATH_MSG_ERROR("Caught exception running " << tool.name() << ": "
415 << e.what());
416 return StatusCode::FAILURE;
417 }
418 // Propagate filter result
419 if (!tool->filterPassed()) {
420 setFilterPassed(false, ctx);
421 }
422 }
423 ATH_MSG_DEBUG(std::format("***** Took {:%OMm %OSs} to process all subevents",
424 std::chrono::high_resolution_clock::now() - now));
425 //
426 // Save hash (direct copy from PileUpEventLoopMgr)
427 PileUpHashHelper pileUpHashHelper;
428 pileUpHashHelper.addToHashSource(overlaidEvt.cptr());
429 ATH_MSG_VERBOSE("Pile-up hash source:" << pileUpHashHelper.hashSource());
430
431 // Calculate and set hash
432 uuid_t pileUpHash;
433 pileUpHashHelper.calculateHash(pileUpHash);
434 overlaidEvt->setPileUpMixtureID(
436 ATH_MSG_DEBUG("PileUpMixtureID = " << overlaidEvt->pileUpMixtureID());
437
438 setFilterPassed(true, ctx); // if got here, assume that means algorithm passed
439 if (m_fracLowPt != 0) {
440 ATH_CHECK(m_lowptMBSvc->endHardScatter(ctx));
441 }
442 if (m_fracHighPt != 0) {
443 ATH_CHECK(m_highptMBSvc->endHardScatter(ctx));
444 }
445 if (m_numCavern != 0) {
446 ATH_CHECK(m_cavernMBSvc->endHardScatter(ctx));
447 }
448 if (m_numBeamHalo != 0) {
449 ATH_CHECK(m_beamhaloMBSvc->endHardScatter(ctx));
450 }
451 if (m_numBeamGas != 0) {
452 ATH_CHECK(m_beamgasMBSvc->endHardScatter(ctx));
453 }
454 return StatusCode::SUCCESS;
455}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
uint32_t CLID
The Class ID type.
An AttributeList represents a logical row of attributes in a metadata table.
A helper class to compute a hash of pile-up events.
xAOD::EventInfo::SubEvent SubEvent
std::string CLIDToString(const CLID &clid)
xAOD::EventInfo * addSubEvent(xAOD::EventInfo *targetEv, const xAOD::EventInfo::SubEvent &subev, xAOD::EventInfoContainer *eiContainer, const std::string &eiContKey, StoreGateSvc *subev_store=nullptr)
C++ native wrapper for the C xxhash API.
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
virtual void setFilterPassed(bool state, const EventContext &ctx) const
ServiceHandle< StoreGateSvc > & evtStore()
An AttributeList represents a logical row of attributes in a metadata table.
static const std::type_info * CLIDToTypeinfo(CLID clid)
Translate between CLID and type_info.
std::vector< EvtId >::const_iterator EvtIter
std::string hashSource() const
Get the current hash base.
void addToHashSource(const std::string &string)
Add a plain string to the stream.
void calculateHash(uuid_t &hash) const
Calculate the hash.
static xAOD::EventInfo::PileUpMixtureID uuidToPileUpMixtureId(const uuid_t &hash)
Convert uuid_t to xAOD::EventInfo::PileUpMixtureID.
Gaudi::Property< int > m_earliestDeltaBC
virtual StatusCode initialize() override
uncomment and implement methods as required
Gaudi::Property< int > m_latestDeltaBC
Gaudi::Property< bool > m_writeTrace
Gaudi::Property< float > m_avgMu
PileUpMTAlg(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< float > m_numCavern
unsigned int get_BCID(int bc, unsigned int central_BCID) const
virtual ~PileUpMTAlg()
Gaudi::Property< float > m_fracLowPt
ServiceHandle< IBeamLuminosity > m_beamLumi
ToolHandleArray< IPileUpTool > m_puTools
SG::WriteHandleKey< xAOD::EventInfoContainer > m_evtInfoContKey
ServiceHandle< IAthRNGSvc > m_rngSvc
SG::ReadCondHandleKey< InDet::BeamSpotData > m_beamSpotKey
StatusCode get_ei(StoreGateSvc &sg, std::unique_ptr< const xAOD::EventInfo > &ei, std::unique_ptr< xAOD::EventAuxInfo > &eiAux, bool pileup=false) const
ServiceHandle< IMinbiasSvc > m_beamgasMBSvc
ServiceHandle< IMinbiasSvc > m_highptMBSvc
ServiceHandle< IMinbiasSvc > m_cavernMBSvc
Gaudi::Property< float > m_fracHighPt
SG::WriteHandleKey< xAOD::EventInfo > m_evtInfoKey
ServiceHandle< IBeamIntensity > m_beamInt
ServiceHandle< ISkipEventIdxSvc > m_skipEventIdxSvc
Gaudi::Property< int > m_skippedHSEvents
ServiceHandle< IMinbiasSvc > m_lowptMBSvc
Other useful methods provided by base class are: evtStore() : ServiceHandle to main event data storeg...
Gaudi::Property< float > m_numBeamGas
virtual StatusCode execute(const EventContext &ctx) override
Execute method.
Gaudi::Property< float > m_numBeamHalo
virtual StatusCode finalize() override
StatusCode add_subevt(const std::vector< std::uint32_t > &bcid, SG::WriteHandle< xAOD::EventInfo > &overlaidEvt, SG::WriteHandle< xAOD::EventInfoContainer > &puCont, ServiceHandle< IMinbiasSvc > &mbSvc, xAOD::EventInfo::PileUpType puType, int bc, const EventContext &ctx, unsigned long subevt_id, std::vector< std::uint64_t > &trace)
ServiceHandle< IMinbiasSvc > m_beamhaloMBSvc
Gaudi::Property< int > m_BCSpacing
const_pointer_type get() const
Dereference the pointer, but don't cache anything.
const_pointer_type cptr() const
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
The Athena Transient Store API.
std::string dump() const
dump objects in store.
const T * tryConstRetrieve() const
Class describing the properties of one pileup sub-event.
void setBCID(uint32_t value)
Set the bunch crossing ID of the event.
PileUpType
Enumerator describing the types of pileup events.
@ Signal
The signal event.
@ IS_SIMULATION
true: simulation, false: data
uint64_t eventNumber() const
The current event's event number.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
EventInfo_v1 EventInfo
Definition of the latest event info version.
std::uint64_t hash64(const void *data, std::size_t size)
Passthrough to XXH3_64bits.
Definition XXH.cxx:9
void handler(int sig)
signal handler
Definition rmain.cxx:99