GCC Code Coverage Report


Directory: ./
File: src/dp/processingInfo.cc
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 0 180 0.0%
Functions: 0 21 0.0%
Branches: 0 40 0.0%

Line Branch Exec Source
1 #include "na64dp/processingInfo.hh"
2 #include "na64util/str-fmt.hh"
3 #include "na64util/log4cpp-extras.hh"
4 #include "na64dp/abstractHitHandler.hh"
5
6 #include <cassert>
7 #include <ctime>
8 #include <iomanip>
9 #include <sstream>
10
11 namespace na64dp {
12
13 //
14 // Basic registry
15
16 void
17 iEvStatProcInfo::register_handler( const AbstractHandler * hPtr
18 , const std::string & hName ) {
19 auto ir = emplace( hPtr, aux::HandlerStatisticsEntry( hName ) );
20 assert(ir.second);
21 ir.first->second.handlerPtr = hPtr;
22 ir.first->second.hitHandlerPtr = dynamic_cast<const HitHandlerStats *>(hPtr);
23 _ordered.push_back( &stats_for(hPtr) );
24 }
25
26 aux::HandlerStatisticsEntry &
27 iEvStatProcInfo::stats_for( const AbstractHandler * hPtr ) {
28 auto it = find(hPtr);
29 if( end() == it ) {
30 NA64DP_RUNTIME_ERROR( "Can not find registered handler by given pointer." );
31 }
32 return it->second;
33 }
34
35 void
36 iEvStatProcInfo::notify_event_read() {
37 if(!_started) { _started = clock(); }
38 ++_nEvsProcessed;
39 //return _nEvsToProcess > 0 ? _nEvsProcessed < _nEvsToProcess : true;
40 }
41
42 void
43 iEvStatProcInfo::notify_event_discriminated( const AbstractHandler * hPtr ) {
44 ++stats_for(hPtr).nDiscriminated;
45 }
46
47 void
48 iEvStatProcInfo::notify_handler_starts( const AbstractHandler * hPtr ) {
49 stats_for(hPtr)._started = clock();
50 }
51
52 void
53 iEvStatProcInfo::notify_handler_done( const AbstractHandler * hPtr ) {
54 auto & s = stats_for(hPtr);
55 s.elapsed += clock() - s._started;
56 }
57
58 size_t
59 iEvStatProcInfo::n_events_discriminated() const {
60 size_t n = 0;
61 for(auto const hsp : _ordered) {
62 n += hsp->nDiscriminated;
63 }
64 return n;
65 }
66
67 void
68 iEvStatProcInfo::finalize() {
69 assert(_ended == 0);
70 _ended = clock();
71 }
72
73 clock_t
74 iEvStatProcInfo::elapsed() const {
75 if(0 == _started) return 0.;
76 if(_ended) return _ended - _started;
77 return clock() - _started;
78 }
79
80 // Helper function producing output:
81 // - 604800 abs secs is "168h 0m 0.000s"
82 // 123456789|1234
83 // - 3 abs secs is "3.000s"
84 // - 75 abs secs is "1m 15.000s"
85 size_t
86 abs_sec_to_hr(clock_t nSecAbs, char * strBuf, size_t bufLen) {
87 unsigned int nHours, nMins;
88 double nSec_ = static_cast<double>(nSecAbs)/CLOCKS_PER_SEC;
89 nHours = static_cast<unsigned int>(nSec_/3600);
90 nSec_ -= 3600*nHours;
91 nMins = static_cast<unsigned int>(nSec_/60);
92 nSec_ -= 60*nMins;
93 if(0 != nHours) {
94 return snprintf(strBuf, bufLen, "%uh %um %02.2fs", nHours, nMins, nSec_);
95 } else if(0 != nMins) {
96 return snprintf(strBuf, bufLen, "%um %02.2fs", nMins, nSec_);
97 } else {
98 if(nSec_ >= 5e-2) {
99 return snprintf(strBuf, bufLen, "%02.2fs", nSec_);
100 } else if(nSec_ > 5e-4) {
101 return snprintf(strBuf, bufLen, "%.2fms", nSec_*1e3);
102 } else {
103 return snprintf(strBuf, bufLen, "%.2fus", nSec_*1e6);
104 }
105 }
106 }
107
108 #if 0
109 Overall summary:
110 Time elapsed ........... 1h 3m 45.3s (1.23 ev/s)
111 Events considered ...... 123478
112 Events discriminated ... 345 (23%)
113 Handlers summary:
114 #. LABEL ELAPSED DISCRIMINATED
115 1. Plot something ................ 0.3s ...... 0, 100.2%
116 2. Discriminate RC ....... 12h 5m 23.1s ... 2345, 36.3%
117 3. Subpipe: consider foo ......... 0.7s ..... 22, 34.5%
118 3.1 Discriminate one ............. 0.4s ... [11], [16.25%]
119 3.2 Discriminate two ............. 0.4s ... [11], [18.25%]
120 4. Plot another ............... 2m 1.5s ..... 21, 0.2% ; hits: 456712/0, 34.2%
121 #endif
122
123 // aux struct collecting strings per handler
124 struct StrItem {
125 std::string label, elapsed, nDiscriminated, percentage, hitsStats;
126 };
127
128 void
129 iEvStatProcInfo::print_summary(std::ostream & os) {
130 // TODO: sub-pipe is not supported so far...
131 const size_t nItems = _ordered.size();
132 size_t fieldWidth[] = {0, 0, 0, 0, 0}; // label, elpased, disc, perc, hitsStats
133 std::vector<StrItem> strItems;
134 strItems.reserve(nItems);
135
136 os << "Handlers summary:" << std::endl;
137 char strBf[64];
138 size_t nEventsSurvived = _nEvsProcessed
139 , nDiscriminatedOverall = 0;
140 size_t nItem = 0;
141 for(auto handlerStatsEntry : _ordered) {
142 ++nItem;
143 StrItem strItem;
144
145 // handler number + label
146 size_t labelLength = snprintf(strBf, sizeof(strBf)
147 , "%3lu. %s", nItem + 1, handlerStatsEntry->name.c_str() );
148 if(fieldWidth[0] < labelLength) fieldWidth[0] = labelLength;
149 strItem.label = strBf;
150 // elapsed time
151 size_t strTimeLength = abs_sec_to_hr(handlerStatsEntry->elapsed, strBf, sizeof(strBf));
152 if(fieldWidth[1] < strTimeLength) fieldWidth[1] = strTimeLength;
153 strItem.elapsed = strBf;
154 // number of discriminated events
155 size_t nDiscStrLength = snprintf(strBf, sizeof(strBf)
156 , "%lu", handlerStatsEntry->nDiscriminated);
157 if(fieldWidth[2] < nDiscStrLength) fieldWidth[2] = nDiscStrLength;
158 strItem.nDiscriminated = strBf;
159 // discriminated percentage
160 float perc = nEventsSurvived
161 ? 100*(static_cast<float>(handlerStatsEntry->nDiscriminated) / nEventsSurvived)
162 : std::numeric_limits<float>::quiet_NaN()
163 ;
164 // decrease number of survived events for further usage
165 if(nEventsSurvived)
166 nEventsSurvived -= handlerStatsEntry->nDiscriminated;
167 nDiscriminatedOverall += handlerStatsEntry->nDiscriminated;
168 size_t nPercStrLength = snprintf(strBf, sizeof(strBf), "%4.1f%%", perc);
169 if(fieldWidth[3] < nPercStrLength) fieldWidth[3] = nPercStrLength;
170 strItem.percentage = strBf;
171 // hits stats
172 if(!handlerStatsEntry->hitHandlerPtr) {
173 strItems.push_back(strItem);
174 continue;
175 }
176 // hits stats
177 size_t hitsStatsLen = snprintf(strBf, sizeof(strBf), "%zu/%zu"
178 , handlerStatsEntry->hitHandlerPtr->n_hits_discriminated()
179 , handlerStatsEntry->hitHandlerPtr->n_hits_considered()
180 );
181
182 if(0 != handlerStatsEntry->hitHandlerPtr->n_hits_discriminated()) {
183 float hitsPerc = 100
184 * static_cast<float>(handlerStatsEntry->hitHandlerPtr->n_hits_discriminated())
185 / handlerStatsEntry->hitHandlerPtr->n_hits_considered()
186 ;
187 hitsStatsLen += snprintf(strBf + hitsStatsLen, sizeof(strBf) - hitsStatsLen, ", %.1f%%", hitsPerc);
188 }
189 strItem.hitsStats = strBf;
190 if(fieldWidth[4] < hitsStatsLen) fieldWidth[4] = hitsStatsLen;
191
192 strItems.push_back(strItem);
193 }
194
195 os << std::setw(fieldWidth[0] + 4) << std::left << " #. LABEL"
196 << std::setw(fieldWidth[1] + 1) << std::right << "ELAPSED"
197 << std::setw(17) << std::right << "DISCRIMINATED"
198 << std::endl;
199 for(const auto & strItem : strItems) {
200 os << std::setw(fieldWidth[0]+4) << std::setfill('.') << std::left << strItem.label + " "
201 << std::setw(fieldWidth[1]+2) << std::setfill('.') << std::right << " " + strItem.elapsed + " "
202 << std::setw(fieldWidth[2]+4) << std::setfill('.') << std::right << " " + strItem.nDiscriminated
203 << /*std::setw(fieldWidth[3]) <<*/ std::setfill(' ') << std::left << ", " + strItem.percentage;
204 if(!strItem.hitsStats.empty())
205 os /* << std::setw(fieldWidth[4])*/ << " ; " + strItem.hitsStats;
206 os << std::endl;
207 }
208 abs_sec_to_hr(elapsed(), strBf, sizeof(strBf));
209 std::string elapsedTimeStr(strBf);
210 float evsPerSec = 0.;
211 if(_nEvsProcessed) {
212 evsPerSec = static_cast<float>(_nEvsProcessed)*CLOCKS_PER_SEC / elapsed();
213 }
214 if(evsPerSec < 5e-2) {
215 snprintf(strBf, sizeof(strBf), "%.2e", evsPerSec);
216 } else {
217 snprintf(strBf, sizeof(strBf), "%.2f", evsPerSec);
218 }
219 os << "Overall event processing summary:" << std::endl
220 << " Time elapsed overall ... " << elapsedTimeStr << " (" << strBf << " ev/s)" << std::endl
221 << " Events considered ...... " << _nEvsProcessed << std::endl
222 << " Events discriminated ... " << nDiscriminatedOverall << std::endl;
223 }
224
225 //
226 // Periodic dispatcher
227
228 void
229 EvProcInfoDispatcher::_dispatch_f() {
230 while( _keep ) {
231 std::this_thread::sleep_for(std::chrono::milliseconds(_rrMSec));
232 _m.lock();
233 _update_event_processing_info();
234 _m.unlock();
235 }
236 }
237
238 EvProcInfoDispatcher::EvProcInfoDispatcher( size_t nMaxEvs
239 , unsigned int refreshTime
240 ) : iEvStatProcInfo( nMaxEvs )
241 , _rrMSec(refreshTime)
242 , _dispatcherThread(nullptr)
243 , _keep(false)
244 , _processingStartTime(clock()) {
245 }
246 EvProcInfoDispatcher::~EvProcInfoDispatcher() {
247 if( _dispatcherThread ) {
248 _m.lock();
249 _keep = false;
250 _m.unlock();
251 _dispatcherThread->join();
252 delete _dispatcherThread;
253 _dispatcherThread = nullptr;
254 }
255 }
256
257 void
258 EvProcInfoDispatcher::notify_event_read() {
259 std::lock_guard<std::mutex> lock(_m);
260 iEvStatProcInfo::notify_event_read();
261 }
262
263 void
264 EvProcInfoDispatcher::notify_event_discriminated( const AbstractHandler * hPtr ) {
265 std::lock_guard<std::mutex> lock(_m);
266 iEvStatProcInfo::notify_event_discriminated(hPtr);
267 }
268
269 void
270 EvProcInfoDispatcher::notify_handler_starts( const AbstractHandler * hPtr ) {
271 std::lock_guard<std::mutex> lock(_m);
272 iEvStatProcInfo::notify_handler_starts(hPtr);
273 }
274
275 void
276 EvProcInfoDispatcher::notify_handler_done( const AbstractHandler * hPtr ) {
277 std::lock_guard<std::mutex> lock(_m);
278 iEvStatProcInfo::notify_handler_done(hPtr);
279 }
280
281 void
282 EvProcInfoDispatcher::start_event_processing() {
283 assert(!_dispatcherThread);
284 assert(!_keep);
285 _keep = true;
286 _dispatcherThread = new std::thread( &EvProcInfoDispatcher::_dispatch_f
287 , this );
288 }
289
290 void
291 EvProcInfoDispatcher::finalize() {
292 {
293 _m.lock();
294 _keep = false;
295 _m.unlock();
296 }
297 if(_dispatcherThread) {
298 _dispatcherThread->join();
299 delete _dispatcherThread;
300 _dispatcherThread = nullptr;
301 }
302 }
303
304 //
305 // TTY print-out
306
307 void
308 TTYStatusProcessingInfo::_update_event_processing_info() {
309 auto layoutPtr = na64dp::util::StdoutStreamAppender::self();
310 if(layoutPtr) {
311 float elapsed = ((float) clock() - started())/CLOCKS_PER_SEC
312 , rate = ((float) n_events_processed())/(elapsed ? elapsed : 1)
313 ;
314
315 std::ostringstream oss;
316 oss << " ";
317 if( n_events_to_process() ) {
318 oss << n_events_processed() << " / "
319 << n_events_to_process()
320 ;
321 if(rate && std::isfinite(rate)) {
322 char buf[64];
323 float reamainedSec
324 = (n_events_to_process() - n_events_processed())/rate;
325 util::seconds_to_hmsm(reamainedSec, buf, sizeof(buf));
326 oss << ", ~" << buf;
327 }
328 } else {
329 oss << n_events_processed();
330 }
331 oss << ", ";
332
333 layoutPtr->update_status_text(oss.str().c_str());
334 }
335 }
336
337 #if 0
338 void
339 PrintEventProcessingInfo::_update_event_processing_info() {
340 float elapsed = ((float) clock() - started())/CLOCKS_PER_SEC
341 , rate = ((float) n_events_processed())/(elapsed ? elapsed : 1)
342 ;
343
344 static char bf[1024];
345 // Note: following escape sequences are used (ANSI terminal):
346 // \033[s -- save current cursor position
347 // \033[u -- restore cursor position previously saved
348 // \033[K -- clear line, from current position to end
349 size_t nPrinted = snprintf( bf, sizeof(bf)
350 , "\033[K\033[1m%zu\033[0m events processed in"
351 " \033[1m%.2f\033[0m sec (\033[1m%.1f\033[0m event/sec)\n"
352 , n_events_processed(), elapsed, rate );
353 size_t nHandler = 1;
354 for( auto handlerPair : *this ) {
355 const AbstractHandler * handlerPtr = handlerPair.first;
356 const aux::HandlerStatisticsEntry & hse = handlerPair.second;
357 float perc = 100.*hse.nDiscriminated/((float) n_events_processed());
358 nPrinted += snprintf( bf + nPrinted, sizeof(bf) - nPrinted
359 , "\033[K %2zu : %p %5zu (%4.1f%%) : %s\n"
360 , nHandler, handlerPtr, hse.nDiscriminated
361 , perc, hse.name.c_str() );
362 if( nPrinted >= sizeof(bf) ) {
363 break;
364 }
365 ++nHandler;
366 }
367 fprintf(stdout, "\033[%zuA", nHandler);
368 fputs(bf, stdout);
369 fflush(stdout);
370 }
371 #endif
372
373 #if 0 // XXX, kept as a draft for future
374 void
375 EvProcInfoDispatcher::excerpt( std::vector<char> & buffer ) {
376 //std::lock_guard<std::mutex> lock(_m);
377 // TODO: this objects could be probably made reentrant
378 ::capnp::MallocMessageBuilder msg;
379 EventProcessingState::Builder state = msg.initRoot<EventProcessingState>();
380 ::capnp::List<HandlerStats>::Builder hStates = state.initHandlers( size() );
381
382 // Fill handlers infor
383 int i = 0;
384 std::map<unsigned short, const EventProcessingState *> sorted;
385 for( const aux::HandlerStatisticsEntry * hse : ordered_stats() ) {
386 HandlerStats::Builder hState = hStates[i];
387
388 hState.setEventsDiscriminated( hse->nDiscriminated );
389 hState.setElapsedTime( 1e3*float(hse->elapsed)/CLOCKS_PER_SEC );
390 hState.setName( hse->name );
391 ++i;
392 }
393 state.setElapsedTime( 1e3*float(clock() - started())/CLOCKS_PER_SEC );
394 state.setEventsPassed( n_events_processed() );
395 state.setNEventsExpected( n_events_to_process() );
396 // Fill banks info
397 auto banks = state.initBanks(); {
398 banks.setNSADCHits( _banks.bankSADC.capacity() );
399 banks.setNAPVHits( _banks.bankAPV.capacity() );
400 banks.setNSADCFittingEntries( _banks.bankSADCFitting.capacity() );
401 banks.setNAPVClusters( _banks.bankAPVClusters.capacity() );
402 banks.setNTrackPoints( _banks.bankTrackPoints.capacity() );
403 banks.setNTracks( _banks.bankTrackPoints.capacity() );
404 }
405
406 // serialize
407 kj::Array<capnp::word> dataArr = capnp::messageToFlatArray(msg);
408 kj::ArrayPtr<kj::byte> bytes = dataArr.asBytes();
409
410 buffer.resize( bytes.size() );
411 std::copy( bytes.begin(), bytes.end(), buffer.begin() );
412 }
413 #endif
414
415 } // namespace na64
416
417