// $Id: GaudiCommon.icpp,v 1.22 2008/10/10 15:18:56 marcocle Exp $ // ============================================================================ // CVS tag $Name: $ version $Revision: 1.22 $ // ============================================================================ // ============================================================================ // include files // ============================================================================ // STL & STD // ============================================================================ #include #include // ============================================================================ /* @file GaudiCommon.cpp * * Implementation file for class : GaudiCommon * * @author Chris Jones Christopher.Rob.Jones@cern.ch * @author Vanya BELYAEV Ivan.Belyaev@itep.ru * @author Rob Lambert Rob.Lambert@cern.ch * @date 2009-08-04 */ // GaudiKernel // ============================================================================ #include "GaudiKernel/IDataProviderSvc.h" #include "GaudiKernel/IToolSvc.h" #include "GaudiKernel/IProperty.h" #include "GaudiKernel/Property.h" #include "GaudiKernel/ISvcLocator.h" #include "GaudiKernel/MsgStream.h" #include "GaudiKernel/ObjectVector.h" #include "GaudiKernel/SmartDataPtr.h" #include "GaudiKernel/SmartRef.h" #include "GaudiKernel/Stat.h" #include "GaudiKernel/System.h" #include "GaudiKernel/IJobOptionsSvc.h" #include "GaudiKernel/StatEntity.h" #include "GaudiKernel/Algorithm.h" #include "GaudiKernel/AlgTool.h" // ============================================================================ // GaudiAlg // ============================================================================ #include "GaudiAlg/Print.h" #include "GaudiAlg/GaudiCommon.h" #include "GaudiAlg/GaudiAlgorithm.h" #include "GaudiAlg/GaudiTool.h" // ============================================================================ // GaudiUtils // ============================================================================ #include "GaudiUtils/RegEx.h" // ============================================================================ // Boost // ============================================================================ #include "boost/format.hpp" #include "boost/lexical_cast.hpp" // ============================================================================ // Disable warning on windows #ifdef _WIN32 #pragma warning ( disable:4661 ) // incomplete explicit templates #endif // ============================================================================ // ============================================================================ // constructor initialisation // ============================================================================ template void GaudiCommon::initGaudiCommonConstructor( const IInterface * parent ) { // initialise data members m_msgLevel = MSG::NIL; m_msgStream = 0; m_updMgrSvc = 0; m_fastContainersSvc = 0; m_typePrint = true; m_propsPrint = false; m_statPrint = true; m_errorsPrint = true; m_context = "" ; m_rootInTES = "" ; m_globalTimeOffset = 0.0 ; //data members for the CounterSummarySvc m_counterSummarySvc=NULL; m_counterList=std::vector(1,".*"); m_statEntityList=std::vector(0); // printout of counters: // the header row for counters printout m_header = " | Counter | # | sum | mean/eff^* | rms/err^* | min | max |" ; // format for regular statistical printout rows m_format1 = " | %|-48.48s|%|50t||%|10d| |%|11.7g| |%|#11.5g| |%|#11.5g| |%|#12.5g| |%|#12.5g| |" ; // format for "efficiency" statistical printout rows m_format2 = " |*%|-48.48s|%|50t||%|10d| |%|11.5g| |(%|#9.6g| +- %|-#9.6g|)%%| ------- | ------- |" ; // flag to use the special "efficiency" format m_useEffFormat = true ; ///< flag to use the special "efficiency" format // job options // print error counters at finalization ? this->declareProperty ( "ErrorsPrint" , m_errorsPrint , "Print the statistics of errors/warnings/exceptions") -> declareUpdateHandler ( &GaudiCommon::printErrorHandler, this ) ; // print properties at initialization? this->declareProperty ( "PropertiesPrint" , m_propsPrint , "Print the properties of the component ") -> declareUpdateHandler ( &GaudiCommon::printPropsHandler, this ) ; // print statistical counters at finalization ? this->declareProperty ( "StatPrint" , m_statPrint , "Print the table of counters" ) -> declareUpdateHandler ( &GaudiCommon::printStatHandler, this ) ; // insert the actual C++ type of the algorithm or tool in the messages? this->declareProperty ( "TypePrint" , m_typePrint , "Add the actal C++ component type into the messages" ) ; // context this->declareProperty ( "Context" , m_context ) ; // root in TES this->declareProperty ( "RootInTES" , m_rootInTES ) ; // root on TES ( temporary ) this->declareProperty ( "RootOnTES" , m_rootOnTES ) ; // global time offset this->declareProperty ( "GlobalTimeOffset", m_globalTimeOffset ) ; // the header row for counters printout this->declareProperty ( "StatTableHeader" , m_header , "The header row for the output Stat-table" ) ; // format for regular statistical printout rows this->declareProperty ( "RegularRowFormat" , m_format1 , "The format for the regular row in the output Stat-table" ) ; // format for "efficiency" statistical printout rows this->declareProperty ( "EfficiencyRowFormat" , m_format2 , "The format for the regular row in the output Stat-table" ) ; // flag to use the special "efficiency" format this->declareProperty ( "UseEfficiencyRowFormat" , m_useEffFormat , "Use the special format for printout of efficiency counters" ) ; //declare the list of simple counters to write. this->declareProperty( "CounterList", m_counterList=std::vector(1,".*"), "RegEx list, of simple integer counters for CounterSummary."); //declare the list of stat entities to write. this->declareProperty( "StatEntityList", m_statEntityList=std::vector(0), "RegEx list, of StatEntity counters for CounterSummary."); // add handler for message level changes this->outputLevelProperty().declareUpdateHandler( &GaudiCommon::msgLevelHandler, this ); // setup context from parent if available if ( parent ) { if ( const GaudiAlgorithm* gAlg = dynamic_cast(parent) ) { m_context = gAlg->context(); m_rootInTES = gAlg->rootInTES(); m_globalTimeOffset = gAlg->globalTimeOffset(); } else if ( const GaudiTool* gTool = dynamic_cast (parent) ) { m_context = gTool->context(); m_rootInTES = gTool->rootInTES(); m_globalTimeOffset = gTool->globalTimeOffset(); } } // Get the job option service IJobOptionsSvc* jos = svc( "JobOptionsSvc" ); // Get the "Context" option if in the file... const std::vector* myList = jos->getProperties( this->name() ); if ( 0 != myList ) { // Iterate over the list to set the options for ( std::vector::const_iterator iter = myList->begin(); iter != myList->end(); ++iter ) { const StringProperty* sp = dynamic_cast(*iter); if ( 0 != sp ) { if ( "Context" == (*iter)->name() ) { m_context = sp->value(); } else if ( "RootInTES" == (*iter)->name() ) { m_rootInTES = sp->value(); } else if ( "GlobalTimeOffset" == (*iter)->name() ) { m_globalTimeOffset = atof( sp->value().c_str() ); } } } } // release tool release( jos ).ignore(); } //============================================================================= //============================================================================= // Initialise the common functionality //============================================================================= template < class PBASE > StatusCode GaudiCommon:: #ifdef __ICC i_gcInitialize #else initialize #endif () { // initialize base class const StatusCode sc = PBASE::initialize(); if ( sc.isFailure() ) { return Error ( "Failed to initialise base class PBASE", sc ) ; } // some debug printout if ( msgLevel(MSG::DEBUG) ) { debug() << "Initialize base class GaudiCommon<" << System::typeinfoName(typeid(PBASE)) << ">" << endmsg; if ( !context().empty() ) debug() << "Created with context = '" << context() << "'" << endmsg; } // some temporary checks to see if people are using RootOnTES and warn if so // TO BE REMOVED ASAP ... if ( m_rootInTES.empty() && !m_rootOnTES.empty() ) { m_rootInTES = m_rootOnTES; Warning( "RootOnTES option is OBSOLETE -> Use RootInTES instead. RootInTES has been updated to " + m_rootInTES, StatusCode::SUCCESS ).ignore(); } else if ( !m_rootInTES.empty() && !m_rootOnTES.empty() ) { Warning( "Options RootOnTES AND RootInTES are defined ! Use RootInTES. RootOnTES is ignored", StatusCode::SUCCESS ).ignore(); } // Check rootInTES ends with a / if ( !m_rootInTES.empty() && m_rootInTES.substr(m_rootInTES.size()-1) != "/" ) m_rootInTES += "/"; //Set up the CounterSummarySvc May need to be changed this->svcLoc()->service("CounterSummarySvc",m_counterSummarySvc,false).ignore() ; if (msgLevel(MSG::DEBUG)) { if (m_counterSummarySvc==NULL ) debug() << "could not locate CounterSummarySvc, no counter summary will be made" << endmsg; else debug() << "found CounterSummarySvc OK" << endmsg; } // properties will be printed if asked for or in "MSG::DEBUG" mode if ( propsPrint() ) { printProps(MSG::ALWAYS); } else if ( msgLevel(MSG::DEBUG) ) { printProps(MSG::DEBUG); } return sc; } //============================================================================= //============================================================================= // Finalize the common functionality //============================================================================= template < class PBASE > StatusCode GaudiCommon:: #ifdef __ICC i_gcFinalize #else finalize #endif () { StatusCode sc = StatusCode::SUCCESS; // print the general information about statistical counters if ( msgLevel(MSG::DEBUG) || (statPrint() && !counters().empty()) ) { // print general statistical counters printStat ( statPrint() ? MSG::ALWAYS : MSG::DEBUG ) ; } //add all counters to the CounterSummarySvc if(m_counterSummarySvc && this->svcLoc()->existsService("CounterSummarySvc")) { if ( msgLevel(MSG::DEBUG) ) debug() << "adding counters to CounterSummarySvc" << endmsg; for(Statistics::const_iterator i=this->counters().begin(); i!=this->counters().end(); i++) { if(Gaudi::Utils::RegEx::matchOr(i->first,m_statEntityList)) m_counterSummarySvc->addCounter(this->name(),i->first,i->second, Gaudi::CounterSummary::SaveStatEntity); else if(Gaudi::Utils::RegEx::matchOr(i->first,m_counterList)) m_counterSummarySvc->addCounter(this->name(),i->first,i->second); } } // release all located tools and services if ( msgLevel(MSG::DEBUG) ) { debug() << "Tools to release :"; for ( AlgTools::const_iterator i = m_tools.begin(); i != m_tools.end(); ++i ) { debug() << " " << (*i)->name(); } debug() << endmsg; } while ( !m_tools.empty() ) { sc = sc && releaseTool( m_tools.back() ) ; } // release all located services if ( msgLevel(MSG::DEBUG) ) { debug() << "Services to release :"; for ( Services::const_iterator i = m_services.begin(); i != m_services.end(); ++i ) { debug() << " " << (*i).first; } debug() << endmsg; } while ( !m_services.empty() ) { sc = sc && releaseSvc( m_services.begin()->second ) ; } //release the CounterSummarySvc manually if(m_counterSummarySvc) { m_counterSummarySvc->release(); m_counterSummarySvc=NULL; } // format printout if ( !m_errors.empty() || !m_warnings.empty() || !m_exceptions.empty() ) { always() << "Exceptions/Errors/Warnings/Infos Statistics : " << m_exceptions .size () << "/" << m_errors .size () << "/" << m_warnings .size () << "/" << m_infos .size () << endmsg ; if ( errorsPrint() ) { printErrors () ; } } // delete the MsgStream resetMsgStream(); // clear *ALL* counters explicitly m_counters .clear() ; m_exceptions .clear() ; m_infos .clear() ; m_warnings .clear() ; m_errors .clear() ; m_counterList.clear() ; m_statEntityList.clear() ; // finalize base class return sc && PBASE::finalize(); } //============================================================================= //============================================================================= // Methods related to tools and services //============================================================================= // ============================================================================ // manual forced (and 'safe') release of the active tool or service // ============================================================================ template < class PBASE > StatusCode GaudiCommon::release ( const IInterface* interface ) const { if ( 0 == interface ) { return Error ( "release(IInterface):: IInterface* points to NULL!" ) ; } // dispatch between tools and services const IAlgTool* algTool = dynamic_cast( interface ) ; // perform the actual release return 0 != algTool ? releaseTool( algTool ) : releaseSvc( interface ) ; } // ============================================================================ // ============================================================================ // manual forced (and 'save') release of the tool // ============================================================================ template < class PBASE > StatusCode GaudiCommon::releaseTool ( const IAlgTool* algTool ) const { if( 0 == algTool ) { return Error ( "releaseTool(IAlgTool):: IAlgTool* points to NULL!" ) ; } if( this->toolSvc() == 0 ) { return Error ( "releaseTool(IAlgTool):: IToolSvc* points to NULL!" ) ; } // find a tool in the list of active tools AlgTools::reverse_iterator it = std::find( m_tools.rbegin() , m_tools.rend() , algTool ) ; if( m_tools.rend() == it ) { return Warning("releaseTool(IAlgTool):: IAlgTool* is not active" ) ; } // get the tool IAlgTool* t = *it ; // cache name const std::string name = t->name(); if ( msgLevel(MSG::DEBUG) ) { debug() << "Releasing tool '" << name << "'" << endmsg; } // remove the tool from the lists m_tools.erase( --it.base() ) ; // release tool if ( msgLevel(MSG::DEBUG) ) { this->debug() << "The tool '" << t->name() << "' of type '" << System::typeinfoName(typeid(*t)) << "' is released" << endmsg; } const StatusCode sc = this->toolSvc()->releaseTool( t ) ; if ( sc.isFailure() ) { return Warning ( "releaseTool(IAlgTool):: error from IToolSvc whilst releasing "+name , sc ) ; } // return final status code return sc ; } // ============================================================================ // ============================================================================ // manual forced (and 'safe') release of the service // ============================================================================ template < class PBASE > StatusCode GaudiCommon::releaseSvc ( const IInterface* Svc ) const { if( 0 == Svc ) { return Error ( "releaseSvc(IInterface):: IInterface* points to NULL!" ) ; } SmartIF svc(const_cast(Svc)); if (svc.isValid()) { Services::iterator it = m_services.find(svc->name()); if (it == m_services.end()) { return Warning( "releaseSvc(IInterface):: IInterface* is not active" ); } if ( msgLevel(MSG::DEBUG) ) { debug() << "Releasing service '" << it->first << "'" << endmsg; } m_services.erase(it); return StatusCode::SUCCESS; } return Warning( "releaseSvc(IInterface):: IInterface* is not a service" ); } // ============================================================================ // ============================================================================ // Add the given tool to the list of active tools // ============================================================================ template < class PBASE > void GaudiCommon::addToToolList( IAlgTool * tool ) const { if( 0 != tool ) { if ( this->msgLevel ( MSG::DEBUG ) ) { this->debug() << "The tool of type '" << System::typeinfoName(typeid(*tool)) << "' has been added with the name '" << tool->name() << "'" << endmsg ; } m_tools.push_back( tool ) ; } } // ============================================================================ // ============================================================================ // Add the given service to the list of active services // ============================================================================ template < class PBASE > void GaudiCommon::addToServiceList( const SmartIF& svc ) const { if (svc.isValid()) { m_services[svc->name()] = svc; } } // ============================================================================ //============================================================================= // Methods related to messaging //============================================================================= // ============================================================================ // Print the error message and return status code // ============================================================================ template < class PBASE > StatusCode GaudiCommon::Error( const std::string& msg , const StatusCode st , const size_t mx ) const { // increase local counter of errors const size_t num = ++m_errors[msg] ; // If suppressed, just return if ( num > mx ) { return st ; } else if ( num == mx ) // issue one-time suppression message { return Print ( "The ERROR message is suppressed : '" + msg + "'" , st , MSG::ERROR ) ; } // return message return Print ( msg , st , MSG::ERROR ) ; } // ============================================================================ // ============================================================================ // Print the warning message and return status code // ============================================================================ template < class PBASE > StatusCode GaudiCommon::Warning ( const std::string& msg , const StatusCode st , const size_t mx ) const { // increase local counter of warnings const size_t num = ++m_warnings[msg] ; // If suppressed, just return if ( num > mx ) { return st ; } else if ( num == mx ) // issue one-time suppression message { return Print ( "The WARNING message is suppressed : '" + msg + "'" , st , MSG::WARNING ) ; } // return message return Print ( msg , st , MSG::WARNING ) ; } // ============================================================================ // ============================================================================ // Print the info message and return status code // ============================================================================ template < class PBASE > StatusCode GaudiCommon::Info ( const std::string& msg , const StatusCode st , const size_t mx ) const { // increase local counter of warnings const size_t num = ++m_infos[msg] ; // If suppressed, just return if ( num > mx ) { return st ; } else if ( num == mx ) // issue one-time suppression message { return Print ( "The INFO message is suppressed : '" + msg + "'" , st , MSG::INFO ) ; } // return message return Print ( msg , st , MSG::INFO ) ; } // ============================================================================ // ============================================================================ // Print the message and return status code // ============================================================================ template < class PBASE > StatusCode GaudiCommon::Print( const std::string& msg , const StatusCode st , const MSG::Level lvl ) const { // perform printout ? if ( !msgLevel( lvl ) ) { return st ; } // RETURN // use the predefined stream MsgStream& str = msgStream( lvl ) ; if ( typePrint() ) { str << System::typeinfoName(typeid(*this)) << ":: " ; } // print the message str << msg ; // test status code if ( st.isSuccess() ) { } else if ( StatusCode::FAILURE != st.getCode() ) { str << " StatusCode=" << st.getCode() ; } else { str << " StatusCode=FAILURE" ; } // perform print operation str << endmsg ; // return return st; } // ============================================================================ // ============================================================================ // Create and (re)-throw the exception // ============================================================================ template < class PBASE > void GaudiCommon::Exception( const std::string & msg , const GaudiException & exc , const StatusCode sc ) const { // increase local counter of exceptions ++m_exceptions[ msg ]; Print ( "Exception (re)throw: " + msg , sc , MSG::FATAL ); throw GaudiException( this->name() + ":: " + msg , this->name() , sc, exc); } // ============================================================================ // ============================================================================ // Create and (re)-throw the exception // ============================================================================ template < class PBASE > void GaudiCommon::Exception( const std::string & msg , const std::exception & exc , const StatusCode sc ) const { // increase local counter of exceptions ++m_exceptions[ msg ]; Print ( "Exception (re)throw: " + msg , sc , MSG::FATAL ); throw GaudiException( this->name() + ":: " + msg+"("+exc.what()+")", "", sc ); } // ============================================================================ // ============================================================================ // Create and throw the exception // ============================================================================ template < class PBASE > void GaudiCommon::Exception( const std::string & msg , const StatusCode sc ) const { // increase local counter of exceptions ++m_exceptions[ msg ]; Print ( "Exception throw: " + msg , sc , MSG::FATAL ); throw GaudiException( this->name() + ":: " + msg , "", sc ); } // ============================================================================ // ============================================================================ // perform the actual printout of counters // ============================================================================ template < class PBASE > long GaudiCommon::printStat( const MSG::Level level ) const { // print statistics if ( counters().empty() ) { return 0 ; } MsgStream& msg = msgStream ( level ) ; // msg << "Number of counters : " << counters().size() ; // if ( !counters().empty() ) { msg << std::endl << m_header ; } // for ( Statistics::const_iterator entry = counters().begin() ; counters().end() != entry ; ++entry ) { msg << std::endl << Gaudi::Utils::formatAsTableRow ( entry -> first , entry -> second , m_useEffFormat , m_format1 , m_format2 ); } // msg << endmsg ; // return counters().size() ; } // ============================================================================ // ============================================================================ // perform the actual printout of error counters // ============================================================================ template < class PBASE > long GaudiCommon::printErrors ( const MSG::Level level ) const { // format for printout boost::format ftm ( " %s = %|.8s| %|23t| Message = '%s'" ); { // print exceptions for ( Counter::const_iterator excp = m_exceptions.begin() ; excp != m_exceptions.end() ; ++excp ) { msgStream(level) << ( ftm % "#EXCEPTIONS" % excp->second % excp->first ) << endmsg; } } { // print errors for ( Counter::const_iterator error = m_errors.begin() ; error != m_errors.end() ; ++error ) { msgStream(level) << ( ftm % "#ERRORS " % error->second % error->first ) << endmsg; } } { // print warnings for ( Counter::const_iterator warning = m_warnings.begin() ; warning != m_warnings.end() ; ++warning ) { msgStream(level) << ( ftm % "#WARNINGS " % warning->second % warning->first ) << endmsg; } } { // print warnings for ( Counter::const_iterator info = m_infos.begin() ; info != m_infos.end() ; ++info ) { msgStream(level) << ( ftm % "#INFOS " % info->second % info->first ) << endmsg; } } // return total number of errors+warnings+exceptions return m_exceptions .size () + m_errors .size () + m_warnings .size () + m_infos .size () ; } // ============================================================================ // ============================================================================ /** perform the printout of properties * @return number of error counters */ // ============================================================================ template < class PBASE > long GaudiCommon::printProps ( const MSG::Level level ) const { // print ALL properties MsgStream& msg = msgStream ( level ); typedef std::vector Properties; const Properties& properties = this->getProperties() ; msg << "List of ALL properties of " << System::typeinfoName( typeid( *this ) ) << "/" << this->name() << " #properties = " << properties.size() << endmsg ; for ( Properties::const_reverse_iterator property = properties.rbegin() ; properties.rend() != property ; ++property ) { msg << "Property ['Name': Value] = " << ( **property) << endmsg ; } return properties.size() ; } // ============================================================================ // ============================================================================ // Handle method for changes in the Messaging levels // ============================================================================ template < class PBASE > void GaudiCommon::msgLevelHandler ( Property & theProp ) { // Force a new MsgStream object, to pick up the new settings resetMsgStream(); // adjust internal message level m_msgLevel = this->outputLevel() < (int) MSG::NIL ? MSG::NIL : this->outputLevel() >= (int) MSG::NUM_LEVELS ? MSG::ALWAYS : MSG::Level( this->outputLevel() ) ; // Keep MessageSvc up to date if needed if ( this->msgSvc()->outputLevel(this->name()) != this->outputLevel() ) { this->msgSvc()->setOutputLevel( this->name(), this->outputLevel() ); } // printout message if ( msgLevel(MSG::DEBUG) ) { debug() << "Property update for " << theProp.name() << " : new value = " << this->outputLevel() << endmsg; } } // ============================================================================ // ============================================================================ // Methods for dealing with the TES and TDS // ============================================================================ // ============================================================================ // put results into Gaudi Event Transient Store // ============================================================================ template < class PBASE > DataObject* GaudiCommon::put ( IDataProviderSvc* svc , DataObject* object , const std::string& location , const bool useRootInTES ) const { // check arguments Assert ( 0 != svc , "put():: Invalid 'service'!" ) ; Assert ( 0 != object , "put():: Invalid 'Object'!" ) ; Assert ( !location.empty() , "put():: Invalid 'address' = '' " ) ; // final data location const std::string & fullLocation = fullTESLocation( location, useRootInTES ); // register the object! const StatusCode status = '/' == fullLocation[0] ? svc -> registerObject( fullLocation , object ) : svc -> registerObject( "/Event/" + fullLocation , object ) ; // check the result! if ( status.isFailure() ) { Exception ( "put():: could not register '" + System::typeinfoName( typeid( *object ) ) + "' at address '" + fullLocation + "'" , status ) ; } if ( msgLevel( MSG::DEBUG ) ) { Print( "The object of type '" + System::typeinfoName( typeid( *object ) ) + "' is registered in TS at address '" + fullLocation + "'" , status , MSG::DEBUG ) ; } return object; } // ============================================================================ // ============================================================================ // Handle method for changes in the 'ErrorsPrint' // ============================================================================ template < class PBASE > void GaudiCommon::printErrorHandler ( Property& /* theProp */ ) { // no action if not yet initialized if ( this -> FSMState() < Gaudi::StateMachine::INITIALIZED ) { return ; } if ( this -> errorsPrint() ) { this -> printErrors () ; } } // ============================================================================ // Handle method for changes in the 'PropertiesPrint' // ============================================================================ template < class PBASE > void GaudiCommon::printPropsHandler ( Property& /* theProp */ ) { // no action if not yet initialized if ( this -> FSMState() < Gaudi::StateMachine::INITIALIZED ) { return ; } if ( this -> propsPrint() ) { this -> printProps ( MSG::ALWAYS ) ; } } // ============================================================================ // Handle method for changes in the 'StatPrint' // ============================================================================ template < class PBASE > void GaudiCommon::printStatHandler ( Property& /* theProp */ ) { // no action if not yet initialized if ( this -> FSMState() < Gaudi::StateMachine::INITIALIZED ) { return ; } if ( this -> statPrint() ) { this -> printStat ( MSG::ALWAYS ) ; } } // ============================================================================ // ============================================================================ // The END // ============================================================================