Commit 10dcdc9c authored by Marco Clemencic's avatar Marco Clemencic Committed by Charles Leggett
Browse files

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<details::InputHandle_t<Traits_, In>...> m_inputs;
std::tuple<details::OutputHandle_t<Traits_, Out>...> 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<details::InputHandle_t<Traits_, In>...> 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<details::OutputHandle_t<Traits_, Out>...> 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 <typename U = PBASE, typename = std::enable_if_t<std::is_base_of<Algorithm, PBASE>::value, U>>
template <typename U = PBASE, typename = std::enable_if_t<std::is_base_of<Gaudi::Algorithm, PBASE>::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 <typename U = PBASE, typename = std::enable_if_t<std::is_base_of<GaudiAlgorithm, PBASE>::value, U>>
template <typename U = PBASE, typename = std::enable_if_t<std::is_base_of<Gaudi::Algorithm, PBASE>::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 <Gaudi/Sequence.h>
// 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<Gaudi::Sequence>
{
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<std::vector<std::string>> m_vetoObjs{
this, "VetoObjects", {}, "skip execute if one or more of these TES objects exist"};
Gaudi::Property<std::vector<std::string>> m_requireObjs{
this, "RequireObjects", {}, "execute only if one or more of these TES objects exist"};
Gaudi::Property<std::vector<std::string>> 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 <Gaudi/Sequence.h>
#include <mutex>
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<Algorithm*>& branchAlgorithms() const;
std::vector<Algorithm*>& branchAlgorithms();
const std::vector<Gaudi::Algorithm*>& branchAlgorithms() const;
std::vector<Gaudi::Algorithm*>& branchAlgorithms();
/// Decode Member Name list
StatusCode decodeMemberNames();
......@@ -159,7 +152,7 @@ protected:
/**
** Append an algorithm to the sequencer.
**/
StatusCode append( Algorithm* pAlgorithm, std::vector<Algorithm*>& theAlgs );
StatusCode append( Gaudi::Algorithm* pAlgorithm, std::vector<Gaudi::Algorithm*>& 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<Algorithm*>& 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<Gaudi::Algorithm*>& theAlgs );
/**
** Decode algorithm names, creating or appending algorithms as appropriate
**/
StatusCode decodeNames( Gaudi::Property<std::vector<std::string>>& theNames, std::vector<Algorithm*>& theAlgs,
StatusCode decodeNames( Gaudi::Property<std::vector<std::string>>& theNames, std::vector<Gaudi::Algorithm*>& theAlgs,
std::vector<bool>& theLogic );
/**
** Execute the members in the specified list
**/
StatusCode execute( const std::vector<Algorithm*>& theAlgs, std::vector<bool>& theLogic, Algorithm*& lastAlgorithm,
unsigned int first = 0 );
StatusCode execute( const EventContext& ctx, const std::vector<Gaudi::Algorithm*>& theAlgs,
const std::vector<bool>& 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<Algorithm*>& theAlgs );
StatusCode remove( const std::string& algname, std::vector<Gaudi::Algorithm*>& theAlgs );
// NO COPY / ASSIGNMENT ALLOWED
Sequencer( const Sequencer& a ) = delete;
......@@ -229,11 +223,12 @@ private:
"branch member names"};
Gaudi::Property<bool> m_stopOverride{this, "StopOverride", false, "stop on filter failure override"};
std::vector<bool> m_isInverted; // Member logic inverted list
std::vector<Algorithm*> m_branchAlgs; // Branch algorithms
std::vector<bool> m_isBranchInverted; // Branch Member logic inverted list
std::vector<bool> m_isInverted; // Member logic inverted list
std::vector<Gaudi::Algorithm*> m_branchAlgs; // Branch algorithms
std::vector<bool> m_isBranchInverted; // Branch Member logic inverted list
bool m_branchFilterPassed = false; // Branch filter passed flag
mutable std::mutex m_branchFilterMutex;
mutable std::map<EventContext::ContextID_t, bool> 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<INTupleSvc>& 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<DataObject>( 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<DataObject>( 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<DataObject>( loc ); } );
m_requireObjs.empty() || any_of( begin( m_requireObjs ), end( m_requireObjs ),
[&]( const std::string& loc ) { return this->exist<DataObject>( 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<Gaudi::Sequence>;
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<ISequencerTimerTool>( "SequencerTimerTool" );
m_timerTool = tool<ISequencerTimerTool>( "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<Algorithm*>( myIAlg.get() );
Gaudi::Algorithm* myAlg = dynamic_cast<Gaudi::Algorithm*>( 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<Algorithm*>( myIAlg.get() );
Gaudi::Algorithm* myAlg = dynamic_cast<Gaudi::Algorithm*>( 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<DataObject>( 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<DataObject>( evtSvc(), loc ); } );
// execute the generic method:
if ( doIt ) sc = GaudiCommon<Gaudi::Sequence>::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;