Gaudi Framework, version v25r0

Home   Generated: Mon Feb 17 2014
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ChronoStatSvc.cpp
Go to the documentation of this file.
1 #ifdef _WIN32
2 #pragma warning( disable : 4786 )
3 #endif
4 // ============================================================================
5 // STD & STL
6 // ============================================================================
7 #include <iostream>
8 #include <iomanip>
9 #include <string>
10 #include <algorithm>
11 #include <functional>
12 #include <fstream>
13 #include <iomanip>
14 // ============================================================================
15 // GaudiKernel
16 // ============================================================================
17 #include "GaudiKernel/Kernel.h"
18 #include "GaudiKernel/StatusCode.h"
20 #include "GaudiKernel/MsgStream.h"
22 #include "GaudiKernel/StatEntity.h"
23 #include "GaudiKernel/Stat.h"
25 // ============================================================================
27 // ============================================================================
28 #include "ChronoStatSvc.h"
29 // ============================================================================
32 // ============================================================================
34 // ============================================================================
41 // ============================================================================
42 // ============================================================================
43 // comparison functor
44 // ============================================================================
46  : public std::binary_function<
47  const std::pair<ChronoEntity*,const IChronoStatSvc::ChronoTag*> ,
48  const std::pair<ChronoEntity*,const IChronoStatSvc::ChronoTag*> , bool >
49 {
50 public:
51  inline bool operator()
53  const IChronoStatSvc::ChronoTag*>& p1 ,
54  const std::pair< ChronoEntity*,
55  const IChronoStatSvc::ChronoTag*>& p2 ) const
56  {
57  const ChronoEntity* e1 = p1.first;
58  const ChronoEntity* e2 = p2.first;
59  return ( ( 0 == e1 || 0 == e2 ) ? true : (*e1)<(*e2) ) ;
60  }
61 };
62 // ============================================================================
63 // comparison functor
64 // ============================================================================
66  : public std::binary_function<
67  const std::pair<const StatEntity*,const IChronoStatSvc::StatTag*> ,
68  const std::pair<const StatEntity*,const IChronoStatSvc::StatTag*> , bool >
69 {
70 public:
72  inline bool operator()
73  ( const std::pair<const StatEntity*,
74  const IChronoStatSvc::StatTag*>& p1,
75  const std::pair<const StatEntity*,
76  const IChronoStatSvc::StatTag*>& p2 ) const
77  {
78  const StatEntity* se1 = p1.first;
79  const StatEntity* se2 = p2.first;
80  return ( 0 == se1 || 0 == se2 ) ? true : (*se1)<(*se2) ;
81  }
82 };
83 // ============================================================================
84 // Constructor
85 // ============================================================================
87 ( const std::string& name, ISvcLocator* svcloc )
88  : base_class( name , svcloc )
89  , m_chronoEntities ()
90  , m_chronoPrintLevel ( MSG::INFO )
91  , m_statEntities ()
92  , m_statPrintLevel ( MSG::INFO )
93  //
94  // the header row
95  , m_header ( " Counter | # | sum | mean/eff^* | rms/err^* | min | max |")
96  // format for regular statistical printout rows
97  , m_format1 ( " %|-15.15s|%|17t||%|10d| |%|11.7g| |%|#11.5g| |%|#11.5g| |%|#12.5g| |%|#12.5g| |" )
98  // format for "efficiency" statistical printout rows
99  , m_format2 ( "*%|-15.15s|%|17t||%|10d| |%|11.5g| |(%|#9.7g| +- %|-#9.7g|)%%| ------- | ------- |" )
100  // flag to use the special "efficiency" format
101  , m_useEffFormat ( true )
102 {
104  declareProperty ( "ChronoPrintOutTable" ,
105  m_chronoTableFlag = true );
107  declareProperty ( "ChronoDestinationCout" ,
108  m_chronoCoutFlag = false );
110  declareProperty ( "ChronoPrintLevel" ,
111  m_intChronoPrintLevel = MSG::INFO );
114  declareProperty ( "ChronoTableToBeOrdered" ,
115  m_chronoOrderFlag = true );
117  declareProperty ( "PrintUserTime" ,
118  m_printUserTime = true );
120  declareProperty ( "PrintSystemTime" ,
121  m_printSystemTime = false );
123  declareProperty ( "PrintEllapsedTime" ,
124  m_printEllapsedTime = false );
127  declareProperty ( "StatPrintOutTable" ,
128  m_statTableFlag = true );
130  declareProperty ( "StatDestinationCout" ,
131  m_statCoutFlag = false );
133  declareProperty ( "StatPrintLevel" ,
134  m_intStatPrintLevel = MSG::INFO );
137  declareProperty ( "StatTableToBeOrdered" ,
138  m_statOrderFlag = true );
139 
140  // specify the number of events to be skipped by the memory auditor
141  // in order to better spot memory leak
142  declareProperty ( "NumberOfSkippedEventsForMemStat" ,
143  m_numberOfSkippedEventsForMemStat = -1 ) ;
144 
145  declareProperty( "AsciiStatsOutputFile",
146  m_statsOutFileName = "",
147  "Name of the output file storing the stats. If empty, no"
148  " statistics will be saved (default)" );
149 
150  declareProperty
151  ( "StatTableHeader" , m_header ,
152  "The header row for the output Stat-table" ) ;
153  declareProperty
154  ( "RegularRowFormat" , m_format1 ,
155  "The format for the regular row in the output Stat-table" ) ;
156  declareProperty
157  ( "EfficiencyRowFormat" , m_format2 ,
158  "The format for the regular row in the output Stat-table" ) ;
159  declareProperty
160  ( "UseEfficiencyRowFormat" , m_useEffFormat ,
161  "Use the special format for printout of efficiency counters" ) ;
162 
163  declareProperty
164  ( "PerEventFile", m_perEventFile="",
165  "File name for per-event deltas" );
166 
167 }
168 // ============================================================================
169 // Destructor.
170 // ============================================================================
172 {
173  // clear the container of chrono entities
175  // clear the container of stat entities
177 }
178 // ============================================================================
179 // Implementation of IService::initialize()
180 // ============================================================================
182 {
184  if ( sc.isFailure() ) return sc;
186  MsgStream log( msgSvc() , this->name() );
187 
188  // Set my own properties
189  sc = setProperties();
190 
191  if (sc.isFailure()) {
192  log << MSG::ERROR << "setting my properties" << endmsg;
193  return StatusCode::FAILURE;
194  }
195 
196  // only add an EndEvent listener if per-event output requested
197  if (m_perEventFile != "") {
198  m_ofd.open(m_perEventFile.c_str());
199  if (!m_ofd.is_open()) {
200  log << MSG::ERROR << "unable to open per-event output file \""
201  << m_perEventFile << "\"" << endmsg;
202  return StatusCode::FAILURE;
203  } else {
204  SmartIF<IIncidentSvc> ii(serviceLocator()->service("IncidentSvc"));
205  if (! ii) {
206  log << MSG::ERROR << "Unable to find IncidentSvc" << endmsg;
207  return StatusCode::FAILURE;
208  }
209  ii->addListener(this, IncidentType::EndEvent);
210  }
211  }
212 
213  log << MSG::INFO << " Number of skipped events for MemStat"
215 
229  if( m_chronoTableFlag &&
230  !m_printUserTime &&
232  !m_printEllapsedTime ) { m_printUserTime = true ; }
234  if( m_printUserTime ||
239  chronoStart( name() ) ;
241  return StatusCode::SUCCESS;
242 }
243 // ============================================================================
244 // Implementation of IService::finalize()
245 // ============================================================================
247 {
248  std::string local = name()+".finalize()";
250  MsgStream main_log( msgSvc() , local );
253  chronoStop( name() ) ;
254 
255  if (m_ofd.is_open()) {
256  MsgStream log(msgSvc(), name());
257  log << MSG::DEBUG << "writing per-event timing data to '" << m_perEventFile << "'" << endmsg;
258  std::string alg;
260  for (itr=m_perEvtTime.begin(); itr != m_perEvtTime.end(); ++itr) {
261  alg = itr->first;
262  alg.erase(alg.length()-8,8);
263  m_ofd << alg << " ";
265  for (itt=itr->second.begin(); itt!=itr->second.end(); ++itt) {
266  m_ofd << " " << (long int)(*itt);
267  }
268  m_ofd << std::endl;
269  }
270 
271  m_ofd.close();
272  }
273 
276  if ( m_chronoTableFlag &&
277  !m_chronoEntities.empty() &&
279  {
281  MsgStream log( msgSvc() , "*****Chrono*****" );
282  const std::string stars( ( m_chronoCoutFlag ) ? 126 : 100 , '*' );
283  if( m_chronoCoutFlag )
284  {
285  std::cout << stars << std::endl;
286  std::cout << local << " The Final CPU consumption (Chrono) Table "
287  << ( m_chronoOrderFlag ? "(ordered)" : "(not ordered)" ) << std::endl;
288  std::cout << stars << std::endl;
289  }
290  else
291  {
293  << stars << endmsg;
295  << " The Final CPU consumption ( Chrono ) Table "
296  << ( m_chronoOrderFlag ? "(ordered)" : "(not ordered)" ) << endmsg;
297  log << (MSG::Level) m_chronoPrintLevel << stars << endmsg;
298  }
300  { // prepare container for printing
302  typedef std::vector<MPair> MCont;
303  MCont tmpCont;
305  m_chronoEntities.end() != it ; ++it )
306  { tmpCont.push_back( MPair( &(it->second) , &(it->first) ) ) ; }
307  // sort it
308  if( m_chronoOrderFlag )
309  { std::sort( tmpCont.begin() ,
310  tmpCont.end() ,
312  // print User Time statistics
313  if( m_printUserTime )
314  {
315  for( MCont::iterator iter = tmpCont.begin() ; tmpCont.end() != iter ; ++iter )
316  {
317  //
318  ChronoEntity* entity = iter->first ; if( 0 == entity ) { continue ; }
319  const ChronoTag* tag = iter->second ; if( 0 == tag ) { continue ; }
320 
321  entity->stop();
322 
323  if ( m_chronoCoutFlag )
324  { std::cout << *tag << "\t" << entity->outputUserTime () << std::endl ; }
325  else
326  {
327  MsgStream(msgSvc(), *tag)
328  << m_chronoPrintLevel << entity->outputUserTime () << endmsg ;
329  }
330  //
331  }
332  }
334  if( m_printSystemTime )
335  {
339  { std::cout << stars << std::endl; }
340  else if ( m_printUserTime && !m_chronoCoutFlag )
341  { log << (MSG::Level) m_chronoPrintLevel << stars << endmsg; }
343  for( MCont::iterator iter = tmpCont.begin() ; tmpCont.end() != iter ; ++iter )
344  {
346  ChronoEntity* entity = iter->first ; if( 0 == entity ) { continue ; }
347  const ChronoTag* tag = iter->second ; if( 0 == tag ) { continue ; }
348 
349  entity->stop();
350 
351  if ( m_chronoCoutFlag )
352  { std::cout << *tag << "\t" << entity->outputSystemTime() << std::endl ; }
353  else
354  {
355  MsgStream(msgSvc(), *tag)
356  << m_chronoPrintLevel << entity->outputSystemTime() << endmsg ;
357  }
358  //
359  }
360  }
362  if( m_printEllapsedTime )
363  {
367  { std::cout << stars << std::endl; }
368  else if ( ( m_printUserTime || m_printSystemTime ) && !m_chronoCoutFlag )
369  { log << (MSG::Level) m_chronoPrintLevel << stars << endmsg; }
371  for( MCont::iterator iter = tmpCont.begin() ; tmpCont.end() != iter ; ++iter )
372  {
374  ChronoEntity* entity = iter->first ; if( 0 == entity ) { continue ; }
375  const ChronoTag* tag = iter->second ; if( 0 == tag ) { continue ; }
376 
377  entity->stop();
378 
379  if ( m_chronoCoutFlag )
380  { std::cout << *tag << "\t" << entity->outputElapsedTime() << std::endl ; }
381  else
382  {
383  MsgStream(msgSvc(), *tag)
384  << m_chronoPrintLevel << entity->outputElapsedTime() << endmsg ;
385  }
386  //
387  }
388  }
390  tmpCont.clear();
391  }
393  if( m_chronoCoutFlag ) { std::cout << stars << std::endl; }
394  else { log << m_chronoPrintLevel << stars << endmsg; }
395  }
396 
398 
400  if ( m_statTableFlag ) { printStats () ; }
401 
402  if ( !m_statsOutFileName.value().empty() ) {
403  saveStats();
404  }
405 
406  main_log << MSG::INFO << " Service finalized successfully " << endmsg;
407 
408  return Service::finalize();
409 }
410 // ============================================================================
411 // Implementation of IChronoStatSvc::chronoStart
412 // ============================================================================
413 ChronoEntity*
415 ( const ChronoTag& chronoTag )
416 {
417  ChronoEntity& entity = m_chronoEntities [ chronoTag ] ;
418  entity.start() ;
419  return &entity ;
420 }
421 // ============================================================================
422 // Implementation of IChronoStatSvc::chronoStop
423 // ============================================================================
424 const ChronoEntity*
426 ( const IChronoStatSvc::ChronoTag& chronoTag )
427 {
428  ChronoEntity& entity = m_chronoEntities [ chronoTag ] ;
429  entity.stop() ;
430  return &entity ;
431 }
432 // ============================================================================
433 // Implementation of IChronoStatSvc::chronoDelta
434 // ============================================================================
437 ( const IChronoStatSvc::ChronoTag& chronoTag,
439 {
440  return m_chronoEntities[ chronoTag ].delta( theType );
441 }
442 // ============================================================================
443 // Implementation of IChronoStatSvc::chronoPrint
444 // ============================================================================
446 ( const IChronoStatSvc::ChronoTag& chronoTag )
447 {
448  MsgStream log ( msgSvc() , chronoTag );
449  if( m_printUserTime ) {
450  log << (MSG::Level) m_chronoPrintLevel
451  << m_chronoEntities[ chronoTag ].outputUserTime ()
452  << endmsg;
453  }
454  if( m_printSystemTime ) {
455  log << (MSG::Level) m_chronoPrintLevel
456  << m_chronoEntities[ chronoTag ].outputSystemTime()
457  << endmsg;
458  }
459 }
460 // ============================================================================
461 // Implementation of IChronoSvc::chronoStatus
462 // ============================================================================
465 ( const IChronoStatSvc::ChronoTag& chronoTag )
466 { return m_chronoEntities[ chronoTag ].status(); }
467 // ============================================================================
468 // Implementation of IChronoStatSvc::stat
469 // ============================================================================
471 ( const IChronoStatSvc::StatTag & statTag ,
472  const IChronoStatSvc::StatFlag & statFlag )
473 {
474  StatMap::iterator theIter=m_statEntities.find(statTag);
475 
476  StatEntity * theStat=0 ;
477  // if new entity, specify the number of events to be skipped
478  if (theIter==m_statEntities.end()){
479  // new stat entity
480  StatEntity& theSe = m_statEntities[ statTag ];
481  theStat=& theSe;
482  theStat->setnEntriesBeforeReset(m_numberOfSkippedEventsForMemStat);
483  }
484  else
485  {
486  //existing stat entity
487  theStat=&((*theIter).second);
488  }
489 
490  theStat->addFlag ( statFlag ) ;
491 }
492 // ============================================================================
493 // Implementation of IChronoStatSvc::statPrint
494 // ============================================================================
496 ( const IChronoStatSvc::StatTag& statTag )
497 {
498  MsgStream log ( msgSvc() , statTag ) ;
499  log << (MSG::Level) m_statPrintLevel << m_statEntities[ statTag ] << endmsg;
500 }
501 // ============================================================================
502 /* extract the chrono entity for the given tag (name)
503  * @see IChronoStatSvc
504  * @param t chrono tag(name)
505  * @return pointer to chrono entity
506  */
507 // ============================================================================
508 const ChronoEntity* ChronoStatSvc::chrono
509 ( const IChronoStatSvc::ChronoTag& t ) const
510 {
511  ChronoMap::const_iterator it = m_chronoEntities.find ( t ) ;
512  if ( m_chronoEntities.end() != it ) { return &(it->second) ; }
513  return 0 ;
514 }
515 // ============================================================================
516 /* extract the stat entity for the given tag (name)
517  * @see IChronoStatSvc
518  * @param t stat tag(name)
519  * @return pointer to stat entity
520  */
521 // ============================================================================
523 ( const IChronoStatSvc::StatTag& t ) const
524 {
525  StatMap::const_iterator it = m_statEntities.find ( t ) ;
526  if ( m_statEntities.end() != it ) { return &(it->second) ; }
527  return 0 ;
528 }
529 // ============================================================================
530 // dump all the statistics into an ASCII file
531 // ============================================================================
533 {
534  std::ofstream out( m_statsOutFileName.value().c_str(),
536  if ( !out.good() ) {
537  MsgStream msg( msgSvc() , name() );
538  msg << MSG::INFO
539  << "Could not open the output file for writing chrono statistics ["
540  << m_statsOutFileName.value() << "]"
541  << endmsg;
542  return;
543  } else {
544  // format it our way
545  out << std::scientific << std::setprecision(8) ;
546  }
547 
548  // ChronoEntity
550  typedef std::vector<MPair> MCont;
551  MCont chronos;
552 
554  m_chronoEntities.end() != it ; ++it ) {
555  chronos.push_back( MPair( &(it->second) , &(it->first) ) ) ;
556  }
557 
558  // sort it
559  std::sort( chronos.begin() ,
560  chronos.end() ,
562 
563  // print User Time statistics
564  for( MCont::iterator iter = chronos.begin() ;
565  chronos.end() != iter;
566  ++iter ) {
567  //
568  const ChronoEntity* entity = iter->first;
569  if( 0 == entity ) { continue ; }
570 
571  const ChronoTag* tag = iter->second ;
572  if( 0 == tag ) { continue ; }
573 
574  // create an entry in the .INI-like table
575  out << "\n[" << *tag << "]\n";
576 
577  // user
578  out << "cpu_user_total = " << entity->uTotalTime() << "\n";
579  out << "cpu_user_min = " << entity->uMinimalTime() << "\n";
580  out << "cpu_user_mean = " << entity->uMeanTime() << "\n";
581  out << "cpu_user_RMS = " << entity->uRMSTime() << "\n";
582  out << "cpu_user_max = " << entity->uMaximalTime() << "\n";
583  out << "cpu_user_nbr = " << entity->nOfMeasurements() << "\n";
584 
585  // system
586  out << "\n"; // just for clarity
587  out << "cpu_system_total = " << entity->kTotalTime() << "\n";
588  out << "cpu_system_min = " << entity->kMinimalTime() << "\n";
589  out << "cpu_system_mean = " << entity->kMeanTime() << "\n";
590  out << "cpu_system_RMS = " << entity->kRMSTime() << "\n";
591  out << "cpu_system_max = " << entity->kMaximalTime() << "\n";
592  out << "cpu_system_nbr = " << entity->nOfMeasurements() << "\n";
593 
594  // real
595  out << "\n"; // just for clarity
596  out << "cpu_real_total = " << entity->eTotalTime() << "\n";
597  out << "cpu_real_min = " << entity->eMinimalTime() << "\n";
598  out << "cpu_real_mean = " << entity->eMeanTime() << "\n";
599  out << "cpu_real_RMS = " << entity->eRMSTime() << "\n";
600  out << "cpu_real_max = " << entity->eMaximalTime() << "\n";
601  out << "cpu_real_nbr = " << entity->nOfMeasurements() << "\n";
602 
603  }
604 
605  out << std::endl;
606 }
607 // ============================================================================
608 // print the "Stat" part of the ChronoStatSvc
609 // ============================================================================
611 {
613  if ( m_statEntities.empty() ) { return ; }
614 
615  MsgStream log ( msgSvc() , "******Stat******" ) ;
617  const std::string stars( ( m_statCoutFlag ) ? 126 : 100 , '*' ) ;
619  if ( m_statCoutFlag )
620  {
621  std::cout << stars << std::endl;
622  std::cout << " The Final stat Table "
623  << ( m_statOrderFlag ? "(ordered)" : "(not ordered)" ) << std::endl;
624  std::cout << stars << std::endl;
625  }
626  else
627  {
628  log << m_statPrintLevel << stars << endmsg;
629  log << m_statPrintLevel << " The Final stat Table "
630  << ( m_statOrderFlag ? "(ordered)" : "(not ordered)" ) << endmsg;
631  log << m_statPrintLevel << stars << endmsg;
632  }
633 
634  {
635  // prepare container for printing
637  typedef std::vector<SPair> SCont;
638  SCont tmpCont;
640  it != m_statEntities.end(); it++ )
641  { tmpCont.push_back( SPair( &(it->second) , &(it->first) ) ) ; }
642  // sort it
643  if ( m_statOrderFlag )
644  { std::sort( tmpCont.begin() ,
645  tmpCont.end() ,
647 
648 
649  {
650  // print the table header
651  if ( m_statCoutFlag ) { std::cout << m_header << std::endl ; }
652  else { log << m_statPrintLevel << m_header << endmsg ; }
653  }
654  // loop over counters and print them:
655  for ( SCont::iterator iter = tmpCont.begin() ; tmpCont.end() != iter ; ++iter )
656  {
658  const StatEntity* entity = iter->first ;
659  if ( 0 == entity ) { continue ; }
660  const StatTag* tag = iter->second ;
661  if ( 0 == tag ) { continue ; }
662 
663  if ( m_statCoutFlag )
664  {
665  std::cout
667  ( *tag , *entity , m_useEffFormat , m_format1 , m_format2 )
668  << std::endl;
669  }
670  else
671  {
672  log
675  ( *tag , *entity , m_useEffFormat , m_format1 , m_format2 )
676  << endmsg ;
677  }
678  }
679  tmpCont.clear();
680  }
682  if ( m_statCoutFlag ) { std::cout << stars << std::endl; }
683  else { log << m_statPrintLevel << stars << endmsg; }
684 }
685 
686 // ============================================================================
687 
688 void ChronoStatSvc::handle(const Incident& /* inc */) {
689 
690  if (! m_ofd.is_open()) return;
691 
694  for (itr=m_chronoEntities.begin(); itr != m_chronoEntities.end(); ++itr) {
695  if (itr->first.find(":Execute") == std::string::npos) continue;
696 
697  itm = m_perEvtTime.find(itr->first);
698  if (itm == m_perEvtTime.end()) {
699  // for when we move past gcc46....
700  // m_perEvtTime[itr->first] =
701  // std::vector<IChronoSvc::ChronoTime> {
702  // itr->second.delta(IChronoSvc::ELAPSED) };
703 
705  m_perEvtTime[itr->first].push_back(itr->second.delta(IChronoSvc::ELAPSED));
706  } else {
707  itm->second.push_back( itr->second.delta(IChronoSvc::ELAPSED) );
708  }
709  }
710 
711 }
712 
713 
714 // ============================================================================
715 // The END
716 // ============================================================================

Generated at Mon Feb 17 2014 14:37:39 for Gaudi Framework, version v25r0 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004