GCC Code Coverage Report


Directory: ./
File: include/na64dp/processingInfo.hh
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 0 19 0.0%
Functions: 0 9 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /* This file is a part of NA64SW software.
2 * Copyright (C) 2015-2022 NA64 Collaboration, CERN
3 *
4 * NA64SW is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 # pragma once
18
19 /**\file
20 * \brief Data processing statistics monitor
21 *
22 * This header file defines interface to track event processing statistics for
23 * the pipeline. These entities get updated in the realtime and foresee
24 * periodic/realtime dispatch for online monitors, real-time logging, etc.
25 *
26 * Header also provides simple implementation of the console output writing
27 * number of events being processed -- `TTYStatusProcessingInfo`.
28 * */
29
30 #include "na64sw-config.h"
31 #include "na64util/mem/fwd.hh"
32
33 #include <yaml-cpp/yaml.h>
34
35 # include <map>
36 # include <vector>
37 # include <thread>
38 # include <mutex>
39
40 namespace na64dp {
41
42 class AbstractHandler;
43 class AbstractEventSource;
44 class Pipeline;
45 class HitHandlerStats;
46
47 // TODO: use high resolution clock with NA64SW_HANDLERS_PROFILING maxro
48
49 namespace aux {
50 /**\brief Statistical entry struct, follows basic statistics on the running
51 * handler at the pipeline.
52 *
53 * `iEvProcInfo` maintains set of such entries during processing to gather
54 * statistics on event and hits processed and discriminated. Also tracks
55 * time profile, that can be used for rough benchmarks and pipeline
56 * optimization. */
57 struct HandlerStatisticsEntry {
58 /// Name of the handler.
59 std::string name;
60 /// Counter corresponding to discriminated events on certain handler in
61 /// pipeline
62 size_t nDiscriminated;
63 // For hit handler -- number of hits being considered
64 //size_t nHitsConsidered;
65 // For hit handler -- number of hits being discriminated
66 //size_t nHitsDiscriminated;
67 /// Time elapsed on computation.
68 clock_t elapsed
69 , _started;
70
71 /// Used for reverse lookup in summary printout; always set
72 const AbstractHandler * handlerPtr;
73 /// Used to retrieve per-hit metrics, can be null for event level handlers
74 const HitHandlerStats * hitHandlerPtr;
75
76
77 HandlerStatisticsEntry(const std::string & nm)
78 : name(nm)
79 , nDiscriminated(0)
80 , elapsed(0)
81 , _started(0)
82 , handlerPtr(nullptr)
83 , hitHandlerPtr(nullptr)
84 {}
85 };
86
87 } // namespace ::na64dp::aux
88
89 namespace util {
90 namespace PoD {
91
92 #if 0
93 ///\brief Interface of data processing manager
94 ///
95 /// Interface defines a event processor steering contract:
96 ///
97 /// * On pipeline startup
98 ///
99 /// Default implementation of methods always provides positive control
100 /// response.
101 struct iProcManager {
102 enum ExecStatus {
103 shutdown,
104 processEvents,
105 };
106
107 /// Returns `true` if instance shall manage pipeline processing
108 virtual bool manages_processing() const { return false; }
109
110 /// Called after logging and calibrations initialized, before instantiating
111 /// source and processing pipeline
112 virtual ExecStatus startup( std::vector<std::string> & //inputs
113 , YAML::Node & //srcCfg
114 , YAML::Node & //runCfg
115 )
116 { return processEvents; }
117 /// Called after instantiating source, before instantiating pipeline
118 virtual ExecStatus source_constructed( na64dp::AbstractEventSource *
119 , const std::vector<std::string> &
120 , const YAML::Node & //srcCfg
121 , YAML::Node & //runCfg
122 )
123 { return processEvents; }
124 };
125 #endif
126
127 } // namespace ::na64dp::util::PoD
128 } // namespace ::na64dp::util
129
130 /**\brief Processing info base class
131 *
132 * Interface for processing info aggregation endpoint. */
133 struct iEvProcInfo {
134 /**\brief Called at the beginning of proc info lifecycle
135 *
136 * Used to initialize counters, structures, etc. */
137 virtual void start_event_processing() {}
138 /**\brief Creates new statistical entry for the handler
139 *
140 * Might be called at any time to indicate new handler created in the
141 * pipeline */
142 virtual void register_handler( const AbstractHandler *, const std::string & ) = 0;
143 /**\brief Called by pipeline at start of event processing */
144 virtual void notify_event_read() = 0;
145 /**\brief Called by pipeline when event was discriminated by certain handler */
146 virtual void notify_event_discriminated( const AbstractHandler * hPtr ) = 0;
147 /**\brief Called when event is provided to a certain handler for
148 * processing */
149 virtual void notify_handler_starts( const AbstractHandler * hPtr ) = 0;
150 /**\brief Called by pipeline when certain handler done processing current
151 * event. */
152 virtual void notify_handler_done( const AbstractHandler * hPtr ) = 0;
153 /** Called at the end of proc info lifecycle */
154 virtual void finalize() {}
155
156 virtual ~iEvProcInfo() {}
157 };
158
159
160 /** \brief Event processing info registry
161 *
162 * An interim utility abstract class, implements basic interface to track
163 * individual handlers statistics. Maintains index of
164 * `aux::HandlerStatisticsEntry` by handler pointer, provides basic interface
165 * for querying.
166 *
167 * \note descendants usually protect access to registry members with mutex, so
168 * by default most of the getters are qualified as `protected'. */
169 struct iEvStatProcInfo : public iEvProcInfo
170 //, public util::PoD::iProcManager,
171 , protected std::map< const AbstractHandler *
172 , aux::HandlerStatisticsEntry> {
173 private:
174 size_t _nEvsProcessed ///< number of processed events, overall
175 , _nEvsToProcess ///< number of discriminated events, overall
176 ;
177 clock_t _started; ///< processing started at
178 clock_t _ended; ///< processing ended at (can be 0)
179 /// ordered list of handlers stats
180 std::vector<const aux::HandlerStatisticsEntry *> _ordered;
181 protected:
182 /// Returns statistics entry for handler
183 aux::HandlerStatisticsEntry & stats_for( const AbstractHandler * );
184
185 iEvStatProcInfo( size_t nEvsToProcess ) : _nEvsProcessed(0)
186 , _nEvsToProcess(nEvsToProcess)
187 , _started(0), _ended(0)
188 {}
189
190 ///\brief Creates new handler entry in the registry
191 ///
192 /// Modifies map of handlers (creates new item) and ordered list.
193 ///
194 /// \todo sub-pipeline
195 void register_handler( const AbstractHandler *, const std::string & ) override;
196 ///\brief Increments overall events counter, starts overall clock if not started
197 void notify_event_read() override;
198 ///\brief Increments handler's discriminated events counter
199 void notify_event_discriminated( const AbstractHandler * hPtr ) override;
200 ///\brief Affects handler's clock (start)
201 void notify_handler_starts( const AbstractHandler * hPtr ) override;
202 ///\brief Increments handler's elapsed time clock
203 void notify_handler_done( const AbstractHandler * hPtr ) override;
204 public:
205 virtual ~iEvStatProcInfo() {}
206 /// Returns number of events being processed
207 size_t n_events_processed() const { return _nEvsProcessed; }
208 /// Returns number of events being discriminated within the pipeline
209 size_t n_events_discriminated() const;
210 /// Returns number of events expected to be read
211 size_t n_events_to_process() const { return _nEvsToProcess; }
212 /// Returns clock() value when processing started
213 clock_t started() const { return _started; }
214 /// Returns elapsed time (in ticks)
215 ///
216 /// Depending on whether `finalize()` was called returns time difference
217 /// between current or finalized time
218 clock_t elapsed() const;
219 /// Returns ordered list of processor stats
220 const std::vector<const aux::HandlerStatisticsEntry *> & ordered_stats() {
221 return _ordered; }
222
223 virtual void finalize() override;
224
225 ///\brief Prints event processing summary as an ASCII table
226 ///
227 /// ...
228 /// \todo
229 virtual void print_summary(std::ostream &);
230
231 friend class Pipeline;
232 };
233
234 /**\brief Wrapper for parallel dispatching of events processing info.
235 *
236 * Tracks the event processing speed, guarantees reasonable refresh rate while
237 * dispatching some runtime information: events being read and processed,
238 * average events processing rate, events discrimination statistics, etc.
239 *
240 * The rationale is to prevent significant slowdown appearing on frequent I/O
241 * operations (FIFO, TTY, network connections, etc) by yielding of a thread
242 * dedicated to these operations. Though, synchronization via mutex may still
243 * introduce noticeable impact. */
244 class EvProcInfoDispatcher : public iEvStatProcInfo {
245 private:
246 /// Refresh interval, msec
247 const unsigned int _rrMSec;
248 /// A thread for periodical print-out of the info
249 std::thread * _dispatcherThread;
250 /// True, when periodical print-out shall proceed
251 bool _keep;
252 /// Info synchronization mutex
253 std::mutex _m;
254 /// In-thread runner
255 void _dispatch_f();
256 protected:
257 /// A record storing the starting time of the processing procedure
258 clock_t _processingStartTime; // XXX?
259
260 ///\brief Shall actually dispatche/update the target
261 ///
262 /// During this function execution the statistics kept by the instance is
263 /// frozen and won't change.
264 virtual void _update_event_processing_info() = 0;
265 /// Initializes basic state.
266 EvProcInfoDispatcher( size_t nMaxEvs
267 , unsigned int mSecRefreshInterval
268 );
269 public:
270 virtual ~EvProcInfoDispatcher();
271 /// Issues a monitoring thread
272 void start_event_processing() override;
273 /// Stops monitoring thread
274 void finalize() override;
275
276 /// Guarded version: increases "passed events" counter
277 void notify_event_read() override;
278 /// Guarded version: increases "discriminated events" counters
279 void notify_event_discriminated( const AbstractHandler * hPtr ) override;
280 /// Guarded version: handler has been invoked
281 void notify_handler_starts( const AbstractHandler * hPtr ) override;
282 /// Guarded version: handler has finished
283 void notify_handler_done( const AbstractHandler * hPtr ) override;
284 };
285
286 /**\brief Prints handlers I/O stats as a simple unbuffered ASCII display.
287 *
288 * A simplest possible case of TTY display, that in case of
289 * interactive terminal provides basic print-out of number of events being
290 * processed till this moment. */
291 class TTYStatusProcessingInfo : public EvProcInfoDispatcher {
292 protected:
293 const std::string _format;
294 virtual void _update_event_processing_info() override;
295 public:
296 /// Accepts a C-file descriptor and refresh interval in msec.
297 TTYStatusProcessingInfo( const std::string & format
298 , size_t nMaxEvents=0
299 , int mSecRefreshInterval=200 )
300 : EvProcInfoDispatcher( nMaxEvents, mSecRefreshInterval )
301 , _format(format)
302 {}
303 };
304
305 } // namespace na64dp
306
307