Commit 10dcdc9c by Marco Clemencic Committed by Charles Leggett

### Reentrant Algorithm base class

parent 72db7704
 ... ... @@ -506,6 +506,8 @@ namespace Gaudi constexpr unsigned int outputLocationSize() const { return N_out; } protected: bool isReEntrant() const override { return true; } std::tuple...> m_inputs; std::tuple...> m_outputs; }; ... ... @@ -524,6 +526,8 @@ namespace Gaudi } protected: bool isReEntrant() const override { return true; } std::tuple<> m_inputs; }; ... ... @@ -568,6 +572,8 @@ namespace Gaudi constexpr unsigned int inputLocationSize() const { return N_in; } protected: bool isReEntrant() const override { return true; } std::tuple...> m_inputs; }; ... ... @@ -611,6 +617,8 @@ namespace Gaudi constexpr unsigned int outputLocationSize() const { return N_out; } protected: bool isReEntrant() const override { return true; } std::tuple...> m_outputs; }; ... ...
 ... ... @@ -43,8 +43,11 @@ // ============================================================================ // forward declarations // ============================================================================ class Algorithm; // GaudiKernel class AlgTool; // GaudiKernel namespace Gaudi { class Algorithm; // GaudiKernel } class AlgTool; // GaudiKernel class ISvcLocator; namespace Gaudi { ... ... @@ -654,7 +657,7 @@ public: public: /// Algorithm constructor - the SFINAE constraint below ensures that this is /// constructor is only defined if PBASE derives from Algorithm template ::value, U>> template ::value, U>> GaudiCommon( const std::string& name, ISvcLocator* pSvcLocator ) : base_class( name, pSvcLocator ) { initGaudiCommonConstructor(); ... ...
 ... ... @@ -2699,7 +2699,7 @@ public: // ========================================================================== /// Algorithm constructor - the SFINAE constraint below ensures that this is /// constructor is only defined if PBASE derives from GaudiAlgorithm template ::value, U>> template ::value, U>> GaudiHistos( const std::string& name, ISvcLocator* pSvcLocator ) : PBASE( name, pSvcLocator ) { } ... ...
 ... ... @@ -3,7 +3,9 @@ // Include files // from Gaudi #include "GaudiAlg/GaudiAlgorithm.h" #include "GaudiAlg/GaudiAlg.h" #include "GaudiAlg/GaudiCommon.h" #include // Forward declarations class ISequencerTimerTool; ... ... @@ -23,16 +25,15 @@ class ISequencerTimerTool; * @author Olivier Callot * @date 2004-05-13 */ class GAUDI_API GaudiSequencer : public GaudiAlgorithm class GAUDI_API GaudiSequencer : public GaudiCommon { public: /// Standard constructor using GaudiAlgorithm::GaudiAlgorithm; using GaudiCommon::GaudiCommon; StatusCode initialize() override; ///< Algorithm initialization StatusCode execute() override; ///< Algorithm execution bool isSequence() const override final { return true; } StatusCode initialize() override; StatusCode execute( const EventContext& ctx ) const override; StatusCode sysExecute( const EventContext& ctx ) override; /// Produce string represention of the control flow expression. std::ostream& toControlFlowExpression( std::ostream& os ) const override; ... ... @@ -42,19 +43,19 @@ private: { public: /// Standard constructor AlgorithmEntry( Algorithm* alg ) : m_algorithm( alg ) {} AlgorithmEntry( Gaudi::Algorithm* alg ) : m_algorithm( alg ) {} void setReverse( bool flag ) { m_reverse = flag; } Algorithm* algorithm() const { return m_algorithm; } bool reverse() const { return m_reverse; } Gaudi::Algorithm* algorithm() const { return m_algorithm; } bool reverse() const { return m_reverse; } void setTimer( int nb ) { m_timer = nb; } int timer() const { return m_timer; } private: Algorithm* m_algorithm = nullptr; ///< Algorithm pointer bool m_reverse = false; ///< Indicates that the flag has to be inverted int m_timer = 0; ///< Timer number for this algorithm Gaudi::Algorithm* m_algorithm = nullptr; ///< Algorithm pointer bool m_reverse = false; ///< Indicates that the flag has to be inverted int m_timer = 0; ///< Timer number for this algorithm }; /** Decode a vector of string. */ ... ... @@ -63,9 +64,10 @@ private: /** for asynchronous changes in the list of algorithms */ void membershipHandler(); /** copy/assignment not allowed **/ GaudiSequencer( const GaudiSequencer& a ) = delete; GaudiSequencer& operator=( const GaudiSequencer& a ) = delete; Gaudi::Property> m_vetoObjs{ this, "VetoObjects", {}, "skip execute if one or more of these TES objects exist"}; Gaudi::Property> m_requireObjs{ this, "RequireObjects", {}, "execute only if one or more of these TES objects exist"}; Gaudi::Property> m_names = { this, "Members", {}, &GaudiSequencer::membershipHandler, "list of algorithms"}; ... ...
 ... ... @@ -2,8 +2,10 @@ #define ALGORITHM_SEQUENCER_H // Include files #include "GaudiKernel/Algorithm.h" #include "GaudiKernel/Property.h" #include #include class MsgStream; ... ... @@ -12,21 +14,21 @@ class MsgStream; ** ** Description: A Sequencer is essentially a list of Algorithms and is responsible ** for their management. Note that Sequences may themselves contain other ** Sequences. The default execute( ) implementation loops over the ** members of the sequence, calling their execute( ) methods. However, this ** Sequences. The default execute() implementation loops over the ** members of the sequence, calling their execute() methods. However, this ** can be modified if a member is disabled, has already been executed, or a ** member indicates that it's filter fails. The the former two cases the ** execution of the member is bypassed. In the latter case, the loop is ** terminated and the Sequencer assumes the same filtered state as the ** last member. **/ class GAUDI_API Sequencer : public Algorithm class GAUDI_API Sequencer : public Gaudi::Sequence { public: /** ** Constructor(s) **/ using Algorithm::Algorithm; using Gaudi::Sequence::Sequence; /***************************** ** Public Function Members ** *****************************/ ... ... @@ -53,7 +55,7 @@ public: ** The actions to be performed by the sequencer on an event. This method ** is invoked once per event. **/ StatusCode execute() override; StatusCode execute( const EventContext& ctx ) const override; /** ** Sequencer finalization. ... ... @@ -65,29 +67,19 @@ public: **/ StatusCode finalize() override; /** ** Reset the Sequencer executed state for the current event. **/ void resetExecuted() override; /** ** additional interface methods **/ /** ** Identify as a Sequence **/ bool isSequence() const override final { return true; } /** ** Was the branch filter passed for the last event? **/ virtual bool branchFilterPassed() const; bool branchFilterPassed( const EventContext& ctx ) const; /** ** Set the branch filter passed flag for the last event **/ virtual StatusCode setBranchFilterPassed( bool state ); void setBranchFilterPassed( const EventContext& ctx, bool state ) const; /** ** Has the StopOverride mode been set? ... ... @@ -97,12 +89,12 @@ public: /** ** Append an algorithm to the sequencer. **/ StatusCode append( Algorithm* pAlgorithm ); StatusCode append( Gaudi::Algorithm* pAlgorithm ); /** ** Append an algorithm to the sequencer branch **/ StatusCode appendToBranch( Algorithm* pAlgorithm ); StatusCode appendToBranch( Gaudi::Algorithm* pAlgorithm ); /** ** Create a algorithm and append it to the sequencer. A call to this method ... ... @@ -115,7 +107,7 @@ public: **/ StatusCode createAndAppend( const std::string& type, // The concrete algorithm class of the algorithm const std::string& name, // The name to be given to the algorithm Algorithm*& pAlgorithm // Set to point to the newly created algorithm object Gaudi::Algorithm*& pAlgorithm // Set to point to the newly created algorithm object ); /** ... ... @@ -127,17 +119,18 @@ public: ** directly via the new operator is preferred since then the framework ** may take care of all of the necessary book-keeping. **/ StatusCode createAndAppendToBranch( const std::string& type, // The concrete algorithm class of the algorithm const std::string& name, // The name to be given to the algorithm Algorithm*& pAlgorithm // Set to point to the newly created algorithm object ); StatusCode createAndAppendToBranch( const std::string& type, // The concrete algorithm class of the algorithm const std::string& name, // The name to be given to the algorithm Gaudi::Algorithm*& pAlgorithm // Set to point to the newly created algorithm object ); /** ** Remove the specified algorithm from the sequencer **/ StatusCode remove( Algorithm* pAlgorithm ); StatusCode remove( Gaudi::Algorithm* pAlgorithm ); StatusCode remove( const std::string& name ); StatusCode removeFromBranch( Algorithm* pAlgorithm ); StatusCode removeFromBranch( Gaudi::Algorithm* pAlgorithm ); StatusCode removeFromBranch( const std::string& name ); /** ... ... @@ -146,8 +139,8 @@ public: ** a failure. The branch is located within the main sequence ** by the first element, which is the filter algorithm. **/ const std::vector& branchAlgorithms() const; std::vector& branchAlgorithms(); const std::vector& branchAlgorithms() const; std::vector& branchAlgorithms(); /// Decode Member Name list StatusCode decodeMemberNames(); ... ... @@ -159,7 +152,7 @@ protected: /** ** Append an algorithm to the sequencer. **/ StatusCode append( Algorithm* pAlgorithm, std::vector& theAlgs ); StatusCode append( Gaudi::Algorithm* pAlgorithm, std::vector& theAlgs ); /** ** Create a algorithm and append it to the sequencer. A call to this method ... ... @@ -170,33 +163,34 @@ protected: ** directly via the new operator is preferred since then the framework ** may take care of all of the necessary book-keeping. **/ StatusCode createAndAppend( const std::string& type, // The concrete algorithm class of the algorithm const std::string& name, // The name to be given to the algorithm Algorithm*& pAlgorithm, // Set to point to the newly created algorithm object std::vector& theAlgs ); StatusCode createAndAppend( const std::string& type, // The concrete algorithm class of the algorithm const std::string& name, // The name to be given to the algorithm Gaudi::Algorithm*& pAlgorithm, // Set to point to the newly created algorithm object std::vector& theAlgs ); /** ** Decode algorithm names, creating or appending algorithms as appropriate **/ StatusCode decodeNames( Gaudi::Property>& theNames, std::vector& theAlgs, StatusCode decodeNames( Gaudi::Property>& theNames, std::vector& theAlgs, std::vector& theLogic ); /** ** Execute the members in the specified list **/ StatusCode execute( const std::vector& theAlgs, std::vector& theLogic, Algorithm*& lastAlgorithm, unsigned int first = 0 ); StatusCode execute( const EventContext& ctx, const std::vector& theAlgs, const std::vector& theLogic, Gaudi::Algorithm*& lastAlgorithm, std::size_t first = 0 ) const; /** ** Execute member algorithm **/ StatusCode executeMember( Algorithm* theAlgorithm ); StatusCode executeMember( Gaudi::Algorithm* theAlgorithm, const EventContext& context ) const; /** ** Remove the specified algorithm from the sequencer **/ StatusCode remove( const std::string& algname, std::vector& theAlgs ); StatusCode remove( const std::string& algname, std::vector& theAlgs ); // NO COPY / ASSIGNMENT ALLOWED Sequencer( const Sequencer& a ) = delete; ... ... @@ -229,11 +223,12 @@ private: "branch member names"}; Gaudi::Property m_stopOverride{this, "StopOverride", false, "stop on filter failure override"}; std::vector m_isInverted; // Member logic inverted list std::vector m_branchAlgs; // Branch algorithms std::vector m_isBranchInverted; // Branch Member logic inverted list std::vector m_isInverted; // Member logic inverted list std::vector m_branchAlgs; // Branch algorithms std::vector m_isBranchInverted; // Branch Member logic inverted list bool m_branchFilterPassed = false; // Branch filter passed flag mutable std::mutex m_branchFilterMutex; mutable std::map m_branchFilterPassed; // Branch filter passed flag }; #endif // ALGORITHM_SEQUENCER_H
 #include "GaudiAlg/EventCounter.h" #include "GaudiAlg/GaudiAlgorithm.h" #include "GaudiAlg/GaudiSequencer.h" #include "GaudiAlg/Prescaler.h" #include "GaudiAlg/Sequencer.h" ... ...
 ... ... @@ -89,32 +89,34 @@ SmartIF& GaudiAlgorithm::evtColSvc() const * @return status code */ // ============================================================================ StatusCode GaudiAlgorithm::sysExecute( const EventContext& evtCtx ) StatusCode GaudiAlgorithm::sysExecute( const EventContext& ctx ) { IAlgContextSvc* ctx = nullptr; StatusCode sc{StatusCode::SUCCESS}; IAlgContextSvc* algCtx = nullptr; if ( registerContext() ) { ctx = contextSvc(); algCtx = contextSvc(); } // Lock the context Gaudi::Utils::AlgContext cnt( ctx, this ); ///< guard/sentry Gaudi::Utils::AlgContext cnt( this, algCtx, ctx ); ///< guard/sentry // Do not execute if one or more of the m_vetoObjs exist in TES auto it = std::find_if( std::begin( m_vetoObjs ), std::end( m_vetoObjs ), [&]( const std::string& loc ) { return this->exist( loc ); } ); if ( it != std::end( m_vetoObjs ) ) { const auto it = find_if( begin( m_vetoObjs ), end( m_vetoObjs ), [&]( const std::string& loc ) { return this->exist( loc ); } ); if ( it != end( m_vetoObjs ) ) { if ( msgLevel( MSG::DEBUG ) ) debug() << *it << " found, skipping event " << endmsg; return StatusCode::SUCCESS; return sc; } // Execute if m_requireObjs is empty // or if one or more of the m_requireObjs exist in TES bool doIt = m_requireObjs.empty() || std::any_of( std::begin( m_requireObjs ), std::end( m_requireObjs ), [&]( const std::string& loc ) { return this->exist( loc ); } ); m_requireObjs.empty() || any_of( begin( m_requireObjs ), end( m_requireObjs ), [&]( const std::string& loc ) { return this->exist( loc ); } ); // execute the generic method: if ( doIt ) return Algorithm::sysExecute( evtCtx ); return StatusCode::SUCCESS; if ( doIt ) sc = Algorithm::sysExecute( ctx ); return sc; } // ============================================================================ ... ...
 ... ... @@ -7,6 +7,10 @@ #include "GaudiAlg/ISequencerTimerTool.h" #include "GaudiKernel/IAlgManager.h" #include "GaudiKernel/IJobOptionsSvc.h" #include "GaudiKernel/ThreadLocalContext.h" #include "GaudiCommon.icpp" template class GaudiCommon; namespace { ... ... @@ -75,14 +79,14 @@ namespace //============================================================================= StatusCode GaudiSequencer::initialize() { GaudiAlgorithm::initialize(); // Note: not calling base class initialize because we want to reimplement the loop over sub algs if ( msgLevel( MSG::DEBUG ) ) debug() << "==> Initialise" << endmsg; StatusCode status = decodeNames(); auto status = decodeNames(); if ( !status.isSuccess() ) return status; m_timerTool = tool( "SequencerTimerTool" ); m_timerTool = tool( "SequencerTimerTool" ); if ( m_timerTool->globalTiming() ) m_measureTime = true; if ( m_measureTime ) { ... ... @@ -112,7 +116,7 @@ StatusCode GaudiSequencer::initialize() //============================================================================= // Main execution //============================================================================= StatusCode GaudiSequencer::execute() StatusCode GaudiSequencer::execute( const EventContext& ctx ) const { if ( m_measureTime ) m_timerTool->start( m_timer ); ... ... @@ -126,18 +130,18 @@ StatusCode GaudiSequencer::execute() // also see comment below .... for ( auto& entry : m_entries ) { Algorithm* myAlg = entry.algorithm(); Gaudi::Algorithm* myAlg = entry.algorithm(); if ( !myAlg->isEnabled() ) continue; if ( !myAlg->isExecuted() ) { if ( myAlg->execState( ctx ).state() != AlgExecState::State::Done ) { if ( m_measureTime ) m_timerTool->start( entry.timer() ); result = myAlg->sysExecute( getContext() ); result = myAlg->sysExecute( ctx ); if ( m_measureTime ) m_timerTool->stop( entry.timer() ); if ( !result.isSuccess() ) break; //== Abort and return bad status } //== Check the returned status if ( !m_ignoreFilter ) { bool passed = myAlg->filterPassed(); bool passed = myAlg->execState( ctx ).filterPassed(); if ( msgLevel( MSG::VERBOSE ) ) verbose() << "Algorithm " << myAlg->name() << " returned filter passed " << ( passed ? "true" : "false" ) << endmsg; ... ... @@ -166,8 +170,9 @@ StatusCode GaudiSequencer::execute() } } if ( msgLevel( MSG::VERBOSE ) ) verbose() << "SeqPass is " << ( seqPass ? "true" : "false" ) << endmsg; if ( !m_ignoreFilter && !m_entries.empty() ) setFilterPassed( m_invert ? !seqPass : seqPass ); setExecuted( true ); auto& state = execState( ctx ); if ( !m_ignoreFilter && !m_entries.empty() ) state.setFilterPassed( m_invert ? !seqPass : seqPass ); state.setState( AlgExecState::State::Done ); if ( m_measureTime ) m_timerTool->stop( m_timer ); ... ... @@ -201,11 +206,11 @@ StatusCode GaudiSequencer::decodeNames() // values... and are not set explicitly already. populate_JobOptionsSvc_t populate_guard{theName, jos, std::forward_as_tuple( "Context", context() ), std::forward_as_tuple( "RootInTES", rootInTES() )}; Algorithm* myAlg = nullptr; result = createSubAlgorithm( theType, theName, myAlg ); myIAlg = myAlg; // ensure that myIAlg.isValid() from here onwards! Gaudi::Algorithm* myAlg = nullptr; result = createSubAlgorithm( theType, theName, myAlg ); myIAlg = myAlg; // ensure that myIAlg.isValid() from here onwards! } else { Algorithm* myAlg = dynamic_cast( myIAlg.get() ); Gaudi::Algorithm* myAlg = dynamic_cast( myIAlg.get() ); if ( myAlg ) { subAlgorithms()->push_back( myAlg ); // when the algorithm is not created, the ref count is short by one, so we have to fix it. ... ... @@ -231,13 +236,13 @@ StatusCode GaudiSequencer::decodeNames() if ( result.isSuccess() ) { // TODO: (MCl) it is possible to avoid the dynamic_cast in most of the // cases by keeping the result of createSubAlgorithm. Algorithm* myAlg = dynamic_cast( myIAlg.get() ); Gaudi::Algorithm* myAlg = dynamic_cast( myIAlg.get() ); if ( myAlg ) { // Note: The reference counting is kept by the system of sub-algorithms m_entries.emplace_back( myAlg ); if ( msgLevel( MSG::DEBUG ) ) debug() << "Added algorithm " << theName << endmsg; } else { warning() << theName << " is not an Algorithm - failed dynamic_cast" << endmsg; warning() << theName << " is not a Gaudi::Algorithm - failed dynamic_cast" << endmsg; final = StatusCode::FAILURE; } } else { ... ... @@ -252,8 +257,8 @@ StatusCode GaudiSequencer::decodeNames() msg << "Member list: "; GaudiUtils::details::ostream_joiner( msg, m_entries, ", ", []( auto& os, const AlgorithmEntry& e ) -> decltype( auto ) { Algorithm* alg = e.algorithm(); std::string typ = System::typeinfoName( typeid( *alg ) ); Gaudi::Algorithm* alg = e.algorithm(); std::string typ = System::typeinfoName( typeid( *alg ) ); os << typ; if ( alg->name() != typ ) os << "/" << alg->name(); return os; ... ... @@ -316,4 +321,35 @@ std::ostream& GaudiSequencer::toControlFlowExpression( std::ostream& os ) const if ( m_entries.size() > 1 ) os << ")"; return os; } // ============================================================================ StatusCode GaudiSequencer::sysExecute( const EventContext& ctx ) { StatusCode sc{StatusCode::SUCCESS}; IAlgContextSvc* algCtx = nullptr; if ( registerContext() ) { algCtx = contextSvc(); } // Lock the context Gaudi::Utils::AlgContext cnt( this, algCtx, ctx ); ///< guard/sentry // Do not execute if one or more of the m_vetoObjs exist in TES const auto it = find_if( begin( m_vetoObjs ), end( m_vetoObjs ), [&]( const std::string& loc ) { return this->exist( evtSvc(), loc ); } ); if ( it != end( m_vetoObjs ) ) { if ( msgLevel( MSG::DEBUG ) ) debug() << *it << " found, skipping event " << endmsg; return sc; } // Execute if m_requireObjs is empty // or if one or more of the m_requireObjs exist in TES bool doIt = m_requireObjs.empty() || any_of( begin( m_requireObjs ), end( m_requireObjs ), [&]( const std::string& loc ) { return this->exist( evtSvc(), loc ); } ); // execute the generic method: if ( doIt ) sc = GaudiCommon::sysExecute( ctx ); return sc; } //=============================================================================
 ... ... @@ -2,7 +2,6 @@ // Implements: // 1) Common functionality of IInterface // 2) Default behavior for the IAlgorithm #include "GaudiAlg/Sequencer.h" #include "GaudiKernel/Chrono.h" ... ... @@ -10,56 +9,46 @@ #include "GaudiKernel/IAlgManager.h" #include "GaudiKernel/ISvcLocator.h" #include "GaudiKernel/Stat.h" #include "GaudiKernel/ThreadLocalContext.h" #define ON_DEBUG if ( msgLevel( MSG::DEBUG ) ) #define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) ) StatusCode Sequencer::initialize() { StatusCode result = StatusCode::SUCCESS; result = decodeMemberNames(); if ( result.isFailure() ) { auto is_good = decodeMemberNames(); if ( !is_good ) { error() << "Unable to configure one or more sequencer members " << endmsg; return result; return is_good; } result = decodeBranchMemberNames(); if ( result.isFailure() ) { is_good = decodeBranchMemberNames(); if ( !is_good ) { error() << "Unable to configure one or more branch members " << endmsg; return result; return is_good; } // Loop over all sub-algorithms for ( auto& alg : *subAlgorithms() ) { result = alg->sysInitialize(); if ( result.isFailure() ) { error() << "Unable to initialize Algorithm " << alg->name() << endmsg; return result; } } // We have to "decode" members before calling base class initialize is_good = Sequence::initialize(); if ( !is_good ) return is_good;