LDMX Software
eventbuilder::EventBuilder Class Reference

Public Member Functions

 EventBuilder (const std::string &name, framework::Process &proc)
 
 enableLogging ("EventBuilder")
 
void configure (framework::config::Parameters &ps) override
 Callback for the EventProcessor to configure itself from the given set of parameters.
 
void produce (framework::Event &event) override
 Process the event and put new data products into it.
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for a Producer is calling produce.
 
- Public Member Functions inherited from framework::EventProcessor
 DECLARE_FACTORY (EventProcessor, EventProcessor *, const std::string &, Process &)
 declare that we have a factory for this class
 
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()=default
 Class destructor.
 
virtual void beforeNewRun (ldmx::RunHeader &run_header)
 Callback for Producers to add parameters to the run header before conditions are initialized.
 
virtual void onNewRun (const ldmx::RunHeader &run_header)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a event input ROOT file is closed.
 
virtual void onProcessStart ()
 Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.
 
virtual void onProcessEnd ()
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
template<class T >
const T & getCondition (const std::string &condition_name)
 Access a conditions object for the current event.
 
TDirectory * getHistoDirectory ()
 Access/create a directory in the histogram file for this event processor to create histograms and analysis tuples.
 
void setStorageHint (framework::StorageControl::Hint hint)
 Mark the current event as having the given storage control hint from this module_.
 
void setStorageHint (framework::StorageControl::Hint hint, const std::string &purposeString)
 Mark the current event as having the given storage control hint from this module and the given purpose string.
 
int getLogFrequency () const
 Get the current logging frequency from the process.
 
int getRunNumber () const
 Get the run number from the process.
 
std::string getName () const
 Get the processor name.
 
void createHistograms (const std::vector< framework::config::Parameters > &histos)
 Internal function which is used to create histograms passed from the python configuration @parma histos vector of Parameters that configure histograms to create.
 

Private Member Functions

PhysicsEventData assemblePayload (const std::vector< DataFragment > &fragments)
 
void writeEventBinary (const PhysicsEventData &ev, const std::string &path="events.bin")
 

Private Attributes

bool m_verbose_parse_
 
unsigned int m_event_id_
 
FragmentBuffer m_event_buffer_
 
std::string m_input_file_
 
packing::utility::Reader m_reader_
 
std::string m_output_name_ {"BuilderOutput"}
 
long long m_coherence_window_ns_
 
int m_min_subsystems_ {2}
 
std::string m_binary_file_ {"events.bin"}
 binary event output, empty to disable
 
std::string m_performance_file_ {"event_performance.csv"}
 performance metrics CSV, empty to disable
 
std::chrono::steady_clock::time_point m_start_time_
 
std::chrono::steady_clock::time_point m_event_start_time_
 
uint64_t m_total_bytes_read_ {0}
 
uint64_t m_total_events_built_ {0}
 
unsigned long m_events_since_last_report_ {0}
 
std::chrono::steady_clock::time_point m_window_start_time_
 
uint64_t m_window_events_count_ {0}
 
uint64_t m_window_bytes_read_ {0}
 

Static Private Attributes

static constexpr unsigned int WINDOW_SIZE
 

Additional Inherited Members

- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 14 of file EventBuilder.h.

Constructor & Destructor Documentation

◆ EventBuilder()

eventbuilder::EventBuilder::EventBuilder ( const std::string & name,
framework::Process & proc )
inline

Definition at line 16 of file EventBuilder.h.

17 : framework::Producer(name, proc),
18 m_verbose_parse_(false),
19 m_event_id_(0) {}
Base class for a module which produces a data product.

Member Function Documentation

◆ assemblePayload()

PhysicsEventData EventBuilder::assemblePayload ( const std::vector< DataFragment > & fragments)
private

Definition at line 540 of file EventBuilder.cxx.

541 {
542 PhysicsEventData event_data;
543 if (fragments.empty()) return event_data;
544 event_data.event_id_ = m_event_id_;
545 event_data.timestamp_ = fragments.front().header_.timestamp_;
546 for (const auto& fragment : fragments) {
548 g.subsystem_id_ = fragment.header_.subsystem_id_;
549 g.timestamp_ns_ = fragment.header_.timestamp_;
550 g.data_ = fragment.payload_;
551 if (fragment.trailer_.checksum_ != 0)
552 g.checksum_ = fragment.trailer_.checksum_;
553 else
554 g.checksum_ = crc32(fragment.payload_);
555 event_data.blocks_.push_back(std::move(g));
556 event_data.systems_readout_.push_back(fragment.header_.subsystem_id_);
557 }
558 return event_data;
559}

◆ configure()

void EventBuilder::configure ( framework::config::Parameters & parameters)
overridevirtual

Callback for the EventProcessor to configure itself from the given set of parameters.

The parameters a processor has access to are the member variables of the python class in the sequence that has class_name equal to the EventProcessor class name.

For an example, look at MyProcessor.

Parameters
parametersParameters for configuration.

Reimplemented from framework::EventProcessor.

Definition at line 58 of file EventBuilder.cxx.

58 {
59 if (ps.exists("verbose_parse")) {
60 m_verbose_parse_ = ps.get<bool>("verbose_parse");
61 }
62 if (ps.exists("dat_file")) {
63 m_input_file_ = ps.get<std::string>("dat_file");
64 } else {
65 const char* env_input = std::getenv("EVENTBUILDER_INPUT");
66 if (env_input) m_input_file_ = env_input;
67 }
68 if (ps.exists("output_name"))
69 m_output_name_ = ps.get<std::string>("output_name");
70 if (ps.exists("coherence_window_ns")) {
71 m_coherence_window_ns_ = ps.get<double>("coherence_window_ns");
72 }
73 if (ps.exists("min_subsystems")) {
74 m_min_subsystems_ = ps.get<int>("min_subsystems");
75 }
76 if (ps.exists("binary_file")) {
77 m_binary_file_ = ps.get<std::string>("binary_file");
78 }
79 if (ps.exists("performance_file")) {
80 m_performance_file_ = ps.get<std::string>("performance_file");
81 }
82
83 ldmx_log(info) << "configure(): dat_file='" << m_input_file_
84 << "' output_name='" << m_output_name_
85 << "' verbose_parse=" << (m_verbose_parse_ ? "true" : "false")
86 << " coherence_window_ns=" << m_coherence_window_ns_
87 << " min_subsystems=" << m_min_subsystems_;
88
89 if (!m_input_file_.empty()) {
90 ldmx_log(info) << "configure(): opening file '" << m_input_file_ << "'";
91 m_reader_.open(m_input_file_);
92 if (!m_reader_) {
93 ldmx_log(error) << "failed to open input file: '" << m_input_file_ << "'";
94 } else {
95 ldmx_log(info) << "configure(): file opened successfully";
96 }
97 } else {
98 ldmx_log(error) << "no input file specified";
99 }
100
101 // Initialize performance tracking
102 m_start_time_ = std::chrono::steady_clock::now();
103 m_total_bytes_read_ = 0;
104 m_total_events_built_ = 0;
105 m_events_since_last_report_ = 0;
106
107 // Initialize windowed metrics for real-time DAQ monitoring
108 m_window_start_time_ = m_start_time_;
109 m_window_events_count_ = 0;
110 m_window_bytes_read_ = 0;
111}
std::string m_performance_file_
performance metrics CSV, empty to disable
std::string m_binary_file_
binary event output, empty to disable
void open(const std::string &file_name)
Open a file with this reader.
Definition Reader.h:36

References framework::config::Parameters::exists(), framework::config::Parameters::get(), m_binary_file_, m_performance_file_, and packing::utility::Reader::open().

◆ produce()

void EventBuilder::produce ( framework::Event & event)
overridevirtual

Process the event and put new data products into it.

Parameters
eventThe Event to process.

Implements framework::Producer.

Definition at line 113 of file EventBuilder.cxx.

113 {
114 static int produce_call_count = 0;
115 produce_call_count++;
116 ldmx_log(debug) << "produce() called, count=" << produce_call_count;
117 ldmx_log(debug) << "verbose_parse=" << (m_verbose_parse_ ? "true" : "false");
118 if (m_verbose_parse_ || produce_call_count <= 3) {
119 ldmx_log(info) << "produce() call #" << produce_call_count;
120 }
121
122 // Start timing for this event
123 m_event_start_time_ = std::chrono::steady_clock::now();
124
125 // Track errors encountered during event assembly
126 uint32_t current_event_errors = 0;
127
128 while (m_reader_ && !m_reader_.eof()) {
129 // Try to read a RogueFrameHeader
130 packing::RogueFrameHeader frame_header;
131 frame_header.read(m_reader_);
132
133 // Store location of end-of-frame for potential recovery
134 const long long frame_end =
135 static_cast<long long>(m_reader_.tell()) + frame_header.size();
136
137 // Check if this is a data frame (channel 0) and not YAML
138 if (frame_header.channel() != 0 || frame_header.probablyYaml()) {
139 // Skip this frame
140 if (m_verbose_parse_)
141 ldmx_log(debug) << "skipping non-data frame (channel="
142 << frame_header.channel() << ")";
143 m_reader_.seek(frame_end);
144 continue;
145 }
146
147 // We have a valid data frame - try to parse it
148 DataFragment fragment{{}, {}, {.checksum_ = 0}};
149 bool parsed_ok = false;
150
151 // Try RoR format first
152 packing::LDMXRoRHeader ror_header;
153 int pos_before_ror = m_reader_.tell();
154
155 // Attempt to read as RoR header
156 try {
157 ror_header.read(m_reader_);
158 // Successfully parsed RoR header
159 fragment.header_.subsystem_id_ =
160 static_cast<uint64_t>(ror_header.subsystem());
161 fragment.header_.contributor_id_ =
162 static_cast<uint64_t>(ror_header.contributor());
163 fragment.header_.timestamp_ = ror_header.timestamp();
164
165 if (m_verbose_parse_) {
166 ldmx_log(debug) << "parsed RoR header subsys="
167 << (int)ror_header.subsystem()
168 << " contrib=" << (int)ror_header.contributor()
169 << " ts=" << ror_header.timestamp();
170 }
171
172 // Read remaining frame payload after RoR header
173 std::vector<uint8_t> payload_data;
174 long long payload_size = frame_end - m_reader_.tell();
175 if (payload_size > 0) {
176 payload_data.resize(payload_size);
177 m_reader_.read(reinterpret_cast<char*>(payload_data.data()),
178 payload_size);
179 }
180 fragment.payload_ = std::move(payload_data);
181 parsed_ok = true;
182 } catch (...) {
183 // RoR parse failed, try packing subsystem format
184 if (m_verbose_parse_)
185 ldmx_log(debug)
186 << "RoR header parse failed, trying packing subsystem format";
187 current_event_errors |= ldmx::EventSummary::ERROR_PARSE_FAILURE;
188 m_reader_.seek(pos_before_ror);
189 }
190
191 if (!parsed_ok) {
192 // Try packing subsystem format
194 try {
195 pkt.read(m_reader_);
196 fragment.header_.subsystem_id_ = static_cast<uint64_t>(pkt.id());
197 fragment.header_.contributor_id_ =
198 0; // Not available in packing subsystem format
199 fragment.header_.timestamp_ = static_cast<uint64_t>(pkt.header()[1]) *
200 1000000000ULL; // event number to ns
201
202 // Convert packet data to payload bytes
203 const auto& data = pkt.data();
204 fragment.payload_.resize(data.size() * 4);
205 std::memcpy(fragment.payload_.data(),
206 reinterpret_cast<const char*>(data.data()),
207 data.size() * 4);
208
209 if (m_verbose_parse_) {
210 ldmx_log(debug) << "parsed packing subsystem pkt subsys=" << pkt.id()
211 << " data_size=" << data.size();
212 }
213 parsed_ok = true;
214 } catch (...) {
215 // Both parse attempts failed, skip this frame
216 if (m_verbose_parse_)
217 ldmx_log(debug) << "failed to parse as either format, skipping frame";
218 current_event_errors |= ldmx::EventSummary::ERROR_PARSE_FAILURE;
219 m_reader_.seek(frame_end);
220 continue;
221 }
222 }
223
224 if (!parsed_ok) {
225 m_reader_.seek(frame_end);
226 continue;
227 }
228
229 if (m_verbose_parse_)
230 ldmx_log(debug) << "adding fragment subsys="
231 << fragment.header_.subsystem_id_
232 << " ts=" << fragment.header_.timestamp_
233 << " bytes=" << fragment.payload_.size();
234
235 // Check if this fragment is outside the coherence window of the current
236 // event batch If so, it means we should finalize the previous event before
237 // adding this one
238 long long fragment_ts = fragment.header_.timestamp_;
239 long long buffer_ref_time = m_event_buffer_.getReferenceTime();
240
241 if (buffer_ref_time > 0 &&
242 (fragment_ts < buffer_ref_time - m_coherence_window_ns_ ||
243 fragment_ts > buffer_ref_time + m_coherence_window_ns_)) {
244 // This fragment is outside the current window - try to build the previous
245 // event
246 std::vector<DataFragment> assembled_event_fragments;
247 if (m_event_buffer_.tryBuildEvent(m_coherence_window_ns_,
248 m_min_subsystems_,
249 assembled_event_fragments) &&
250 !assembled_event_fragments.empty()) {
251 // Output the complete event and return
252 ++m_event_id_;
253 // Add each subsystem's raw data as vector<uint8_t> directly
254 uint64_t event_timestamp = 0;
255 for (const auto& frag : assembled_event_fragments) {
256 std::string subsys_name = packing::LDMXRoRHeader::getSubsystemName(
257 static_cast<uint8_t>(frag.header_.subsystem_id_),
258 static_cast<uint8_t>(frag.header_.contributor_id_));
259 std::vector<uint8_t> payload_bytes(frag.payload_.begin(),
260 frag.payload_.end());
261 event.add(subsys_name, payload_bytes);
262 if (event_timestamp == 0) {
263 event_timestamp = frag.header_.timestamp_;
264 }
265 }
266 event.getEventHeader().setIntParameter(
267 "RoR Timestamp", static_cast<long long>(event_timestamp));
268 event.getEventHeader().setRealData();
269 // Still create PhysicsEventData for binary output file
270 PhysicsEventData final_event =
271 assemblePayload(assembled_event_fragments);
272 writeEventBinary(final_event, m_binary_file_);
273 ldmx_log(info) << "assembled event id=" << m_event_id_
274 << " timestamp=" << final_event.timestamp_
275 << " fragments=" << assembled_event_fragments.size()
276 << " systems=" << final_event.systems_readout_.size();
277
278 ldmx::EventSummary summary;
279 summary.setEventNumber(m_event_id_);
280 summary.setTimestampNs(static_cast<uint64_t>(final_event.timestamp_));
281 std::set<uint64_t> unique_sys, unique_sources;
282 uint64_t total_payload = 0;
283 for (const auto& f : assembled_event_fragments) {
284 unique_sys.insert(f.header_.subsystem_id_);
285 // a subsystem may have several contributors, a duplicate is the same
286 // pair twice
287 unique_sources.insert(f.header_.subsystem_id_ << 8 |
288 f.header_.contributor_id_);
289 total_payload += f.payload_.size();
290 }
291 // Check for duplicate subsystems
292 if (unique_sources.size() != assembled_event_fragments.size()) {
293 current_event_errors |= ldmx::EventSummary::ERROR_DUPLICATE_SUBSYSTEM;
294 }
295 summary.setNSystems(static_cast<uint32_t>(unique_sys.size()));
296 summary.setSystemIds(
297 std::vector<uint64_t>(unique_sys.begin(), unique_sys.end()));
298 summary.setPayloadSize(total_payload);
299 summary.setErrorFlags(current_event_errors);
300 event.add("EventSummary", summary);
301
302 // Update performance metrics
303 m_total_bytes_read_ += total_payload;
304 m_total_events_built_++;
305 m_events_since_last_report_++;
306 std::chrono::steady_clock::time_point now =
307 std::chrono::steady_clock::now();
308 std::chrono::milliseconds event_build_time_ms =
309 std::chrono::duration_cast<std::chrono::milliseconds>(
310 now - m_event_start_time_);
311 std::chrono::seconds total_elapsed_s =
312 std::chrono::duration_cast<std::chrono::seconds>(now -
313 m_start_time_);
314
315 double events_per_sec =
316 (total_elapsed_s.count() > 0)
317 ? static_cast<double>(m_total_events_built_) /
318 total_elapsed_s.count()
319 : 0.0;
320 double mb_per_sec = (total_elapsed_s.count() > 0)
321 ? static_cast<double>(m_total_bytes_read_) /
322 (1024.0 * 1024.0) /
323 total_elapsed_s.count()
324 : 0.0;
325
326 // Update windowed metrics
327 m_window_events_count_++;
328 m_window_bytes_read_ += total_payload;
329 std::chrono::seconds window_elapsed_s =
330 std::chrono::duration_cast<std::chrono::seconds>(
331 now - m_window_start_time_);
332
333 // Reset window if we've processed WINDOW_SIZE events
334 double window_events_per_sec = 0.0;
335 double window_mb_per_sec = 0.0;
336 if (m_window_events_count_ >= WINDOW_SIZE) {
337 double window_time_sec =
338 std::max(1.0, static_cast<double>(window_elapsed_s.count()));
339 window_events_per_sec =
340 static_cast<double>(m_window_events_count_) / window_time_sec;
341 window_mb_per_sec = static_cast<double>(m_window_bytes_read_) /
342 (1024.0 * 1024.0) / window_time_sec;
343
344 // Reset window
345 m_window_start_time_ = now;
346 m_window_events_count_ = 0;
347 m_window_bytes_read_ = 0;
348 }
349
350 // Write performance metrics to CSV
351 long long event_build_time_ms_val = event_build_time_ms.count();
352 writePerformanceMetric(m_performance_file_, m_event_id_,
353 static_cast<double>(event_build_time_ms_val),
354 events_per_sec, mb_per_sec,
355 window_events_per_sec, window_mb_per_sec,
356 m_total_events_built_, m_total_bytes_read_);
357
358 if (m_verbose_parse_ || m_events_since_last_report_ % 100 == 0) {
359 ldmx_log(info) << "Performance: "
360 << "total_events=" << m_total_events_built_ << ", "
361 << "events_per_sec=" << std::fixed
362 << std::setprecision(2) << events_per_sec << ", "
363 << "mb_per_sec=" << std::fixed << std::setprecision(3)
364 << mb_per_sec;
365 }
366
367 current_event_errors = 0; // Reset for next event
368 // The fragment that tripped the window-close belongs to the NEXT
369 // event, not the one we just emitted. Buffer it here (the buffer is
370 // empty post-build, so this also resets the reference time) instead
371 // of dropping it -- otherwise every event after the first loses its
372 // triggering subsystem.
373 m_event_buffer_.addFragment(std::move(fragment));
374 return; // Return the event to framework
375 }
376 }
377
378 // Add fragment to buffer (may start a new event batch if buffer was empty)
379 m_event_buffer_.addFragment(std::move(fragment));
380
381 if (m_verbose_parse_)
382 ldmx_log(debug) << "frame added to buffer, searching for more frames...";
383 }
384
385 // Reached EOF - flush any remaining events in the buffer
386 if (m_verbose_parse_)
387 ldmx_log(debug) << "reached EOF, flushing remaining events";
388
389 std::vector<DataFragment> assembled_event_fragments;
390 while (m_event_buffer_.tryBuildEvent(
391 m_coherence_window_ns_, m_min_subsystems_, assembled_event_fragments)) {
392 if (assembled_event_fragments.empty()) break;
393
394 // Mark truncated events (those flushed at EOF)
395 current_event_errors |= ldmx::EventSummary::ERROR_TRUNCATED_EVENT;
396
397 ++m_event_id_;
398 // Add each subsystem's raw data as vector<uint8_t> directly
399 uint64_t event_timestamp = 0;
400 for (const auto& frag : assembled_event_fragments) {
401 std::string subsys_name = packing::LDMXRoRHeader::getSubsystemName(
402 static_cast<uint8_t>(frag.header_.subsystem_id_),
403 static_cast<uint8_t>(frag.header_.contributor_id_));
404 std::vector<uint8_t> payload_bytes(frag.payload_.begin(),
405 frag.payload_.end());
406 event.add(subsys_name, payload_bytes);
407 if (event_timestamp == 0) {
408 event_timestamp = frag.header_.timestamp_;
409 }
410 }
411 event.getEventHeader().setIntParameter(
412 "RoR Timestamp", static_cast<long long>(event_timestamp));
413 event.getEventHeader().setRealData();
414 // Still create PhysicsEventData for binary output file
415 PhysicsEventData final_event = assemblePayload(assembled_event_fragments);
416 writeEventBinary(final_event, m_binary_file_);
417 ldmx_log(info) << "assembled event id=" << m_event_id_
418 << " timestamp=" << final_event.timestamp_
419 << " fragments=" << assembled_event_fragments.size()
420 << " systems=" << final_event.systems_readout_.size();
421
422 ldmx::EventSummary summary;
423 summary.setEventNumber(m_event_id_);
424 summary.setTimestampNs(static_cast<uint64_t>(final_event.timestamp_));
425 std::set<uint64_t> unique_sys, unique_sources;
426 uint64_t total_payload = 0;
427 for (const auto& f : assembled_event_fragments) {
428 unique_sys.insert(f.header_.subsystem_id_);
429 // a subsystem may have several contributors, a duplicate is the same pair
430 // twice
431 unique_sources.insert(f.header_.subsystem_id_ << 8 |
432 f.header_.contributor_id_);
433 total_payload += f.payload_.size();
434 }
435 // Check for duplicate subsystems
436 if (unique_sources.size() != assembled_event_fragments.size()) {
437 current_event_errors |= ldmx::EventSummary::ERROR_DUPLICATE_SUBSYSTEM;
438 }
439 summary.setNSystems(static_cast<uint32_t>(unique_sys.size()));
440 summary.setSystemIds(
441 std::vector<uint64_t>(unique_sys.begin(), unique_sys.end()));
442 summary.setPayloadSize(total_payload);
443 summary.setErrorFlags(current_event_errors);
444 event.add("EventSummary", summary);
445
446 // Update performance metrics
447 m_total_bytes_read_ += total_payload;
448 m_total_events_built_++;
449 m_events_since_last_report_++;
450 std::chrono::steady_clock::time_point now =
451 std::chrono::steady_clock::now();
452 std::chrono::milliseconds event_build_time_ms =
453 std::chrono::duration_cast<std::chrono::milliseconds>(
454 now - m_event_start_time_);
455 std::chrono::seconds total_elapsed_s =
456 std::chrono::duration_cast<std::chrono::seconds>(now - m_start_time_);
457
458 double events_per_sec = (total_elapsed_s.count() > 0)
459 ? static_cast<double>(m_total_events_built_) /
460 total_elapsed_s.count()
461 : 0.0;
462 double mb_per_sec = (total_elapsed_s.count() > 0)
463 ? static_cast<double>(m_total_bytes_read_) /
464 (1024.0 * 1024.0) / total_elapsed_s.count()
465 : 0.0;
466
467 // Update windowed metrics
468 m_window_events_count_++;
469 m_window_bytes_read_ += total_payload;
470 std::chrono::seconds window_elapsed_s =
471 std::chrono::duration_cast<std::chrono::seconds>(now -
472 m_window_start_time_);
473
474 // Calculate window metrics (for final event, may not have full window)
475 double window_events_per_sec = 0.0;
476 double window_mb_per_sec = 0.0;
477 if (m_window_events_count_ >= WINDOW_SIZE || window_elapsed_s.count() > 0) {
478 double window_time_sec =
479 std::max(1.0, static_cast<double>(window_elapsed_s.count()));
480 window_events_per_sec =
481 static_cast<double>(m_window_events_count_) / window_time_sec;
482 window_mb_per_sec = static_cast<double>(m_window_bytes_read_) /
483 (1024.0 * 1024.0) / window_time_sec;
484 }
485
486 // Write performance metrics to CSV
487 long long event_build_time_ms_val = event_build_time_ms.count();
488 writePerformanceMetric(m_performance_file_, m_event_id_,
489 static_cast<double>(event_build_time_ms_val),
490 events_per_sec, mb_per_sec, window_events_per_sec,
491 window_mb_per_sec, m_total_events_built_,
492 m_total_bytes_read_);
493
494 if (m_verbose_parse_ || m_events_since_last_report_ % 100 == 0) {
495 ldmx_log(info) << "Performance: "
496 << "total_events=" << m_total_events_built_ << ", "
497 << "events_per_sec=" << std::fixed << std::setprecision(2)
498 << events_per_sec << ", "
499 << "mb_per_sec=" << std::fixed << std::setprecision(3)
500 << mb_per_sec;
501 }
502
503 current_event_errors = 0; // Reset for next event
504
505 assembled_event_fragments.clear();
506 return;
507 }
508
509 // No more events - print final summary statistics
510 std::chrono::steady_clock::time_point final_time =
511 std::chrono::steady_clock::now();
512 std::chrono::seconds total_time_s =
513 std::chrono::duration_cast<std::chrono::seconds>(final_time -
514 m_start_time_);
515 double final_events_per_sec =
516 (total_time_s.count() > 0)
517 ? static_cast<double>(m_total_events_built_) / total_time_s.count()
518 : 0.0;
519 double final_mb_per_sec = (total_time_s.count() > 0)
520 ? static_cast<double>(m_total_bytes_read_) /
521 (1024.0 * 1024.0) / total_time_s.count()
522 : 0.0;
523
524 ldmx_log(info) << "\n===== FINAL STATISTICS =====";
525 ldmx_log(info) << "Total events built: " << m_total_events_built_;
526 ldmx_log(info) << "Total bytes read: "
527 << m_total_bytes_read_ / (1024.0 * 1024.0) << " MB";
528 ldmx_log(info) << "Total time: " << total_time_s.count() << " seconds";
529 ldmx_log(info) << "Average throughput: "
530 << "events_per_sec=" << std::fixed << std::setprecision(2)
531 << final_events_per_sec << ", "
532 << "mb_per_sec=" << std::fixed << std::setprecision(3)
533 << final_mb_per_sec;
534 ldmx_log(info) << "=============================\n";
535 ldmx_log(info) << "Event building complete";
536
537 abortEvent();
538}
void abortEvent()
Abort the event immediately.
Provides summary information about an assembled event, including error flags for data quality assessm...
void setSystemIds(const std::vector< uint64_t > &ids)
Set the system IDs.
void setNSystems(uint32_t ns)
Set the number of systems in this event.
void setPayloadSize(uint64_t size)
Set the total payload size.
void setTimestampNs(uint64_t ts)
Set the timestamp in nanoseconds.
void setEventNumber(uint64_t num)
Set the event number.
void setErrorFlags(uint32_t flags)
Set the error flags.
@ ERROR_PARSE_FAILURE
Frame parsing error.
@ ERROR_DUPLICATE_SUBSYSTEM
Duplicate subsystem in single event.
@ ERROR_TRUNCATED_EVENT
Event was truncated (EOF reached)
the header that the LDMX DAQ Firmware block includes in the output data stream at the beginning of ea...
static std::tuple< int, int > subsystem(const std::string &name)
Get the (subsystem, contributor) pair for the input subsystem name.
uint8_t contributor() const
ID number for contributor within subsystem (configured into firmware)
static std::string getSubsystemName(uint8_t subsystem_id, uint8_t contributor_id)
Get the subsystem name from subsystem and contributor IDs.
uint64_t timestamp() const
get timestamp of this RoR
utility::Reader & read(utility::Reader &r)
read the next LDMX RoR header into memory
the header that the Rogue StreamWriter puts includes at the beginning of each frame.
unsigned int size() const
get the size of the frame not including this header
bool probablyYaml() const
check if this frame is probably a yaml dump
int channel() const
get the channel this data was written to
utility::Reader & read(utility::Reader &r)
read the next rogue frame header into memory
std::vector< uint32_t > & data()
Get data.
utility::Reader & read(utility::Reader &r)
read the subsystem packet from the input reader
std::vector< uint32_t > header() const
get the header words
std::streampos tell()
Tell us where the reader is.
Definition Reader.h:88
bool eof()
check if file is done
Definition Reader.h:217
void seek(std::streampos off, std::ios_base::seekdir dir=std::ios::beg)
Go ("seek") a specific position in the file.
Definition Reader.h:62
Reader & read(WordType *w, std::size_t count)
Read the next 'count' words into the input handle.
Definition Reader.h:114

References framework::EventProcessor::abortEvent(), packing::RogueFrameHeader::channel(), packing::LDMXRoRHeader::contributor(), packing::rawdatafile::SubsystemPacket::data(), packing::utility::Reader::eof(), ldmx::EventSummary::ERROR_DUPLICATE_SUBSYSTEM, ldmx::EventSummary::ERROR_PARSE_FAILURE, ldmx::EventSummary::ERROR_TRUNCATED_EVENT, packing::LDMXRoRHeader::getSubsystemName(), packing::rawdatafile::SubsystemPacket::header(), m_binary_file_, m_performance_file_, packing::RogueFrameHeader::probablyYaml(), packing::LDMXRoRHeader::read(), packing::rawdatafile::SubsystemPacket::read(), packing::RogueFrameHeader::read(), packing::utility::Reader::read(), packing::utility::Reader::seek(), ldmx::EventSummary::setErrorFlags(), ldmx::EventSummary::setEventNumber(), ldmx::EventSummary::setNSystems(), ldmx::EventSummary::setPayloadSize(), ldmx::EventSummary::setSystemIds(), ldmx::EventSummary::setTimestampNs(), packing::RogueFrameHeader::size(), packing::LDMXRoRHeader::subsystem(), packing::utility::Reader::tell(), and packing::LDMXRoRHeader::timestamp().

◆ writeEventBinary()

void EventBuilder::writeEventBinary ( const PhysicsEventData & ev,
const std::string & path = "events.bin" )
private

Definition at line 561 of file EventBuilder.cxx.

562 {
563 static std::mutex g_out_mutex;
564 std::lock_guard<std::mutex> lg(g_out_mutex);
565 if (path.empty()) return;
566 std::ofstream ofs(path, std::ios::binary | std::ios::app);
567 if (!ofs) return;
568 uint64_t event_id_u = static_cast<uint64_t>(ev.event_id_);
569 uint64_t ts = static_cast<uint64_t>(ev.timestamp_);
570 uint32_t nblocks = static_cast<uint32_t>(ev.blocks_.size());
571 ofs.write(reinterpret_cast<const char*>(&event_id_u), sizeof(event_id_u));
572 ofs.write(reinterpret_cast<const char*>(&ts), sizeof(ts));
573 ofs.write(reinterpret_cast<const char*>(&nblocks), sizeof(nblocks));
574 for (const auto& b : ev.blocks_) {
575 uint64_t sid = b.subsystem_id_;
576 uint64_t bts = b.timestamp_ns_;
577 uint32_t psz = static_cast<uint32_t>(b.data_.size());
578 uint32_t csum = b.checksum_;
579 ofs.write(reinterpret_cast<const char*>(&sid), sizeof(sid));
580 ofs.write(reinterpret_cast<const char*>(&bts), sizeof(bts));
581 ofs.write(reinterpret_cast<const char*>(&psz), sizeof(psz));
582 ofs.write(reinterpret_cast<const char*>(&csum), sizeof(csum));
583 if (psz)
584 ofs.write(reinterpret_cast<const char*>(b.data_.data()),
585 static_cast<std::streamsize>(psz));
586 }
587 ofs.flush();
588}

Member Data Documentation

◆ m_binary_file_

std::string eventbuilder::EventBuilder::m_binary_file_ {"events.bin"}
private

binary event output, empty to disable

Definition at line 47 of file EventBuilder.h.

47{"events.bin"};

Referenced by configure(), and produce().

◆ m_coherence_window_ns_

long long eventbuilder::EventBuilder::m_coherence_window_ns_
private
Initial value:
{
5000000}

Definition at line 41 of file EventBuilder.h.

41 {
42 5000000}; // 5 ms window for collecting fragments

◆ m_event_buffer_

FragmentBuffer eventbuilder::EventBuilder::m_event_buffer_
private

Definition at line 37 of file EventBuilder.h.

◆ m_event_id_

unsigned int eventbuilder::EventBuilder::m_event_id_
private

Definition at line 36 of file EventBuilder.h.

◆ m_event_start_time_

std::chrono::steady_clock::time_point eventbuilder::EventBuilder::m_event_start_time_
private

Definition at line 53 of file EventBuilder.h.

◆ m_events_since_last_report_

unsigned long eventbuilder::EventBuilder::m_events_since_last_report_ {0}
private

Definition at line 56 of file EventBuilder.h.

56{0};

◆ m_input_file_

std::string eventbuilder::EventBuilder::m_input_file_
private

Definition at line 38 of file EventBuilder.h.

◆ m_min_subsystems_

int eventbuilder::EventBuilder::m_min_subsystems_ {2}
private

Definition at line 45 of file EventBuilder.h.

45{2};

◆ m_output_name_

std::string eventbuilder::EventBuilder::m_output_name_ {"BuilderOutput"}
private

Definition at line 40 of file EventBuilder.h.

40{"BuilderOutput"};

◆ m_performance_file_

std::string eventbuilder::EventBuilder::m_performance_file_ {"event_performance.csv"}
private

performance metrics CSV, empty to disable

Definition at line 49 of file EventBuilder.h.

49{"event_performance.csv"};

Referenced by configure(), and produce().

◆ m_reader_

packing::utility::Reader eventbuilder::EventBuilder::m_reader_
private

Definition at line 39 of file EventBuilder.h.

◆ m_start_time_

std::chrono::steady_clock::time_point eventbuilder::EventBuilder::m_start_time_
private

Definition at line 52 of file EventBuilder.h.

◆ m_total_bytes_read_

uint64_t eventbuilder::EventBuilder::m_total_bytes_read_ {0}
private

Definition at line 54 of file EventBuilder.h.

54{0};

◆ m_total_events_built_

uint64_t eventbuilder::EventBuilder::m_total_events_built_ {0}
private

Definition at line 55 of file EventBuilder.h.

55{0};

◆ m_verbose_parse_

bool eventbuilder::EventBuilder::m_verbose_parse_
private

Definition at line 35 of file EventBuilder.h.

◆ m_window_bytes_read_

uint64_t eventbuilder::EventBuilder::m_window_bytes_read_ {0}
private

Definition at line 63 of file EventBuilder.h.

63{0};

◆ m_window_events_count_

uint64_t eventbuilder::EventBuilder::m_window_events_count_ {0}
private

Definition at line 62 of file EventBuilder.h.

62{0};

◆ m_window_start_time_

std::chrono::steady_clock::time_point eventbuilder::EventBuilder::m_window_start_time_
private

Definition at line 61 of file EventBuilder.h.

◆ WINDOW_SIZE

unsigned int eventbuilder::EventBuilder::WINDOW_SIZE
staticconstexprprivate
Initial value:
=
100

Definition at line 59 of file EventBuilder.h.


The documentation for this class was generated from the following files: