The Gaudi Framework  master (50869dff)
Loading...
Searching...
No Matches
AvalancheSchedulerSvc Class Reference

#include </builds/gaudi/Gaudi/GaudiHive/src/AvalancheSchedulerSvc.h>

Inheritance diagram for AvalancheSchedulerSvc:
Collaboration diagram for AvalancheSchedulerSvc:

Classes

struct  TaskSpec
 Struct to hold entries in the alg queues. More...
struct  AlgQueueSort
 Comparison operator to sort the queues. More...

Public Member Functions

StatusCode initialize () override
 Initialise.
StatusCode finalize () override
 Finalise.
StatusCode pushNewEvent (EventContext *eventContext) override
 Make an event available to the scheduler.
StatusCode pushNewEvents (std::vector< EventContext * > &eventContexts) override
StatusCode popFinishedEvent (EventContext *&eventContext) override
 Blocks until an event is available.
StatusCode tryPopFinishedEvent (EventContext *&eventContext) override
 Try to fetch an event from the scheduler.
unsigned int freeSlots () override
 Get free slots number.
void dumpState () override
 Dump scheduler state for all slots.
virtual StatusCode scheduleEventView (const EventContext *sourceContext, const std::string &nodeName, std::unique_ptr< EventContext > viewContext) override
 Method to inform the scheduler about event views.
virtual void recordOccupancy (int samplePeriod, std::function< void(OccupancySnapshot)> callback) override
 Sample occupancy at fixed interval (ms) Negative value to deactivate, 0 to snapshot every change Each sample, apply the callback function to the result.
bool next (TaskSpec &ts, bool asynchronous)
Public Member Functions inherited from extends< Service, IScheduler >
void const * i_cast (const InterfaceID &tid) const override
 Implementation of IInterface::i_cast.
StatusCode queryInterface (const InterfaceID &ti, void **pp) override
 Implementation of IInterface::queryInterface.
std::vector< std::string > getInterfaceNames () const override
 Implementation of IInterface::getInterfaceNames.
Public Member Functions inherited from Service
const std::string & name () const override
 Retrieve name of the service.
StatusCode configure () override
StatusCode initialize () override
StatusCode start () override
StatusCode stop () override
StatusCode finalize () override
StatusCode terminate () override
Gaudi::StateMachine::State FSMState () const override
Gaudi::StateMachine::State targetFSMState () const override
StatusCode reinitialize () override
StatusCode restart () override
StatusCode sysInitialize () override
 Initialize Service.
StatusCode sysStart () override
 Initialize Service.
StatusCode sysStop () override
 Initialize Service.
StatusCode sysFinalize () override
 Finalize Service.
StatusCode sysReinitialize () override
 Re-initialize the Service.
StatusCode sysRestart () override
 Re-initialize the Service.
 Service (std::string name, ISvcLocator *svcloc)
 Standard Constructor.
SmartIF< ISvcLocator > & serviceLocator () const override
 Retrieve pointer to service locator.
template<typename IFace = IService>
SmartIF< IFace > service (const std::string &name, bool createIf=true) const
template<class T>
Gaudi::Details::PropertyBasedeclareProperty (const std::string &name, ToolHandle< T > &hndl, const std::string &doc="none")
template<class T>
StatusCode declareTool (ToolHandle< T > &handle, bool createIf=true)
template<class T>
StatusCode declareTool (ToolHandle< T > &handle, const std::string &toolTypeAndName, bool createIf=true)
 Declare used tool.
template<class T>
Gaudi::Details::PropertyBasedeclareProperty (const std::string &name, ToolHandleArray< T > &hndlArr, const std::string &doc="none")
template<class T>
void addToolsArray (ToolHandleArray< T > &hndlArr)
const std::vector< IAlgTool * > & tools () const
SmartIF< IAuditorSvc > & auditorSvc () const
 The standard auditor service.May not be invoked before sysInitialize() has been invoked.
Public Member Functions inherited from PropertyHolder< CommonMessaging< implements< IService, IProperty, IStateful > > >
StatusCode setProperty (const Gaudi::Details::PropertyBase &p)
 Set the property from a property.
StatusCode setProperty (const std::string &name, const char *v)
 Special case for string literals.
StatusCode setProperty (const std::string &name, const std::string &v)
 Special case for std::string.
StatusCode setProperty (const std::string &name, const TYPE &value)
 set the property form the value
 PropertyHolder ()=default
Gaudi::Details::PropertyBasedeclareProperty (Gaudi::Details::PropertyBase &prop)
 Declare a property.
Gaudi::Details::PropertyBasedeclareRemoteProperty (const std::string &name, IProperty *rsvc, const std::string &rname="")
 Declare a remote property.
StatusCode setPropertyRepr (const std::string &n, const std::string &r) override
 set the property from name and value string representation
StatusCode getProperty (Gaudi::Details::PropertyBase *p) const override
 get the property
const std::vector< Gaudi::Details::PropertyBase * > & getProperties () const override
 get all properties
bool hasProperty (std::string_view name) const override
 Return true if we have a property with the given name.
Gaudi::Details::PropertyBaseproperty (std::string_view name) const
 \fixme property and bindPropertiesTo should be protected
void bindPropertiesTo (Gaudi::Interfaces::IOptionsSvc &optsSvc)
PropertyHolderoperator= (const PropertyHolder &)=delete
Public Member Functions inherited from CommonMessagingBase
virtual ~CommonMessagingBase ()=default
 Virtual destructor.
const SmartIF< IMessageSvc > & msgSvc () const
 The standard message service.
MsgStreammsgStream () const
 Return an uninitialized MsgStream.
MsgStreammsgStream (const MSG::Level level) const
 Predefined configurable message stream for the efficient printouts.
MsgStreamalways () const
 shortcut for the method msgStream(MSG::ALWAYS)
MsgStreamfatal () const
 shortcut for the method msgStream(MSG::FATAL)
MsgStreamerr () const
 shortcut for the method msgStream(MSG::ERROR)
MsgStreamerror () const
 shortcut for the method msgStream(MSG::ERROR)
MsgStreamwarning () const
 shortcut for the method msgStream(MSG::WARNING)
MsgStreaminfo () const
 shortcut for the method msgStream(MSG::INFO)
MsgStreamdebug () const
 shortcut for the method msgStream(MSG::DEBUG)
MsgStreamverbose () const
 shortcut for the method msgStream(MSG::VERBOSE)
MsgStreammsg () const
 shortcut for the method msgStream(MSG::INFO)
MSG::Level msgLevel () const
 get the cached level (originally extracted from the embedded MsgStream)
bool msgLevel (MSG::Level lvl) const
 get the output level from the embedded MsgStream

Private Types

enum  ActivationState { INACTIVE = 0 , ACTIVE = 1 , FAILURE = 2 }
using AState = AlgsExecutionStates::State
using action = std::function<StatusCode()>

Private Member Functions

StatusCode dumpDataDepsGraphFile (const std::map< std::string, DataObjIDColl > &inDeps, const std::map< std::string, DataObjIDColl > &outDeps) const
void activate ()
 Activate scheduler.
StatusCode deactivate ()
 Deactivate scheduler.
unsigned int algname2index (const std::string &algoname)
 Convert a name to an integer.
const std::string & index2algname (unsigned int index)
 Convert an integer to a name.
StatusCode iterate ()
 Loop on all slots to schedule DATAREADY algorithms and sign off ready events.
StatusCode revise (unsigned int iAlgo, EventContext *contextPtr, AState state, bool iterate=false)
StatusCode schedule (TaskSpec &&)
StatusCode signoff (const TaskSpec &)
 The call to this method is triggered only from within the AlgTask.
bool isStalled (const EventSlot &) const
 Check if scheduling in a particular slot is in a stall.
void eventFailed (EventContext *eventContext)
 Method to execute if an event failed.
void dumpSchedulerState (int iSlot)
 Dump the state of the scheduler.

Private Attributes

std::chrono::duration< int64_t, std::milli > m_snapshotInterval = std::chrono::duration<int64_t, std::milli>::min()
std::chrono::system_clock::time_point m_lastSnapshot = std::chrono::system_clock::now()
std::function< void(OccupancySnapshot)> m_snapshotCallback
Gaudi::Property< int > m_threadPoolSize
Gaudi::Property< int > m_maxParallelismExtra
Gaudi::Property< std::string > m_whiteboardSvcName { this, "WhiteboardSvc", "EventDataSvc", "The whiteboard name" }
Gaudi::Property< bool > m_simulateExecution
Gaudi::Property< std::string > m_optimizationMode
Gaudi::Property< bool > m_dumpIntraEventDynamics
Gaudi::Property< int > m_numOffloadThreads
Gaudi::Property< bool > m_checkDeps
Gaudi::Property< bool > m_checkOutput
Gaudi::Property< std::vector< std::string > > m_checkOutputIgnoreList
Gaudi::Property< std::string > m_useDataLoader
Gaudi::Property< bool > m_enableCondSvc { this, "EnableConditions", false, "Enable ConditionsSvc" }
Gaudi::Property< bool > m_showDataDeps
Gaudi::Property< bool > m_showDataFlow
Gaudi::Property< bool > m_showControlFlow
Gaudi::Property< bool > m_verboseSubSlots { this, "VerboseSubSlots", false, "Dump algorithm states for all sub-slots" }
Gaudi::Property< std::string > m_dataDepsGraphFile
Gaudi::Property< std::string > m_dataDepsGraphAlgoPattern
Gaudi::Property< std::string > m_dataDepsGraphObjectPattern
std::atomic< ActivationStatem_isActive { INACTIVE }
 Flag to track if the scheduler is active or not.
std::thread m_thread
 The thread in which the activate function runs.
std::unordered_map< std::string, unsigned int > m_algname_index_map
 Map to bookkeep the information necessary to the name2index conversion.
std::vector< std::string > m_algname_vect
 Vector to bookkeep the information necessary to the index2name conversion.
SmartIF< IPrecedenceSvcm_precSvc
 A shortcut to the Precedence Service.
SmartIF< IHiveWhiteBoardm_whiteboard
 A shortcut to the whiteboard.
std::vector< EventSlotm_eventSlots
 Vector of events slots.
std::atomic_int m_freeSlots { 0 }
 Atomic to account for asyncronous updates by the scheduler wrt the rest.
tbb::concurrent_bounded_queue< EventContext * > m_finishedEvents
 Queue of finished events.
SmartIF< IAlgExecStateSvcm_algExecStateSvc
 Algorithm execution state manager.
SmartIF< ICondSvcm_condSvc
 A shortcut to service for Conditions handling.
unsigned int m_algosInFlight = 0
 Number of algorithms presently in flight.
SmartIF< IAlgResourcePoolm_algResourcePool
 Cache for the algorithm resource pool.
tbb::concurrent_bounded_queue< actionm_actionsQueue
 Queue where closures are stored and picked for execution.
tbb::concurrent_priority_queue< TaskSpec, AlgQueueSortm_scheduledQueue
 Queues for scheduled algorithms.
tbb::concurrent_priority_queue< TaskSpec, AlgQueueSortm_scheduledAsynchronousQueue
std::queue< TaskSpecm_retryQueue
std::atomic< bool > m_needsUpdate { true }
SmartIF< IThreadPoolSvcm_threadPoolSvc
tbb::task_arena * m_arena { nullptr }
std::unique_ptr< FiberManagerm_fiberManager { nullptr }
size_t m_maxEventsInFlight { 0 }

Friends

class AlgTask

Additional Inherited Members

Public Types inherited from extends< Service, IScheduler >
using base_class
 Typedef to this class.
using extend_interfaces_base
 Typedef to the base of this class.
Public Types inherited from Service
using Factory = Gaudi::PluginService::Factory<IService*( const std::string&, ISvcLocator* )>
Public Types inherited from PropertyHolder< CommonMessaging< implements< IService, IProperty, IStateful > > >
using PropertyHolderImpl
 Typedef used to refer to this class from derived classes, as in.
Public Types inherited from CommonMessaging< implements< IService, IProperty, IStateful > >
using base_class
Public Types inherited from extend_interfaces< Interfaces... >
using ext_iids
 take union of the ext_iids of all Interfaces...
Protected Member Functions inherited from Service
std::vector< IAlgTool * > & tools ()
 ~Service () override
int outputLevel () const
 get the Service's output level
Protected Member Functions inherited from CommonMessaging< implements< IService, IProperty, IStateful > >
MSG::Level setUpMessaging () const override final
 Set up local caches.
MSG::Level resetMessaging ()
 Reinitialize internal states.
void updateMsgStreamOutputLevel (int level)
 Update the output level of the cached MsgStream.
Protected Attributes inherited from Service
Gaudi::StateMachine::State m_state = Gaudi::StateMachine::OFFLINE
 Service state.
Gaudi::StateMachine::State m_targetState = Gaudi::StateMachine::OFFLINE
 Service state.
Gaudi::Property< int > m_outputLevel { this, "OutputLevel", MSG::NIL, "output level" }
 flag indicating whether ToolHandle tools have been added to m_tools
Gaudi::Property< bool > m_auditorInitialize { this, "AuditInitialize", false, "trigger auditor on initialize()" }
Gaudi::Property< bool > m_auditorStart { this, "AuditStart", false, "trigger auditor on start()" }
Gaudi::Property< bool > m_auditorStop { this, "AuditStop", false, "trigger auditor on stop()" }
Gaudi::Property< bool > m_auditorFinalize { this, "AuditFinalize", false, "trigger auditor on finalize()" }
Gaudi::Property< bool > m_auditorReinitialize { this, "AuditReinitialize", false, "trigger auditor on reinitialize()" }
Gaudi::Property< bool > m_auditorRestart { this, "AuditRestart", false, "trigger auditor on restart()" }
Gaudi::Property< bool > m_autoRetrieveTools
Gaudi::Property< bool > m_checkToolDeps
SmartIF< IAuditorSvcm_pAuditorSvc
 Auditor Service.

Detailed Description

Introduction

The scheduler is named after its ability to generically maximize the average intra-event task occupancy by inducing avalanche-like concurrency disclosure waves in conditions of arbitrary intra-event task precedence constraints (see section 3.2 of http://cern.ch/go/7Jn7).

Task precedence management

The scheduler is driven by graph-based task precedence management. When compared to approach used in the ForwardSchedulerSvc, the following advantages can be emphasized:

(1) Faster decision making (thus lower concurrency disclosure downtime); (2) Capacity for proactive task scheduling decision making.

Point (2) allowed to implement a number of generic, non-intrusive intra-event throughput maximization scheduling strategies.

Scheduling principles

o Task scheduling prerequisites

A task is scheduled ASA all following conditions are met:

  • if a control flow (CF) graph traversal reaches the task;
  • when all data flow (DF) dependencies of the task are satisfied;
  • when the DF-ready task pool parsing mechanism (*) considers it, and:
    • a free (or re-entrant) algorithm instance to run within the task is available;
    • there is a free computational resource to run the task.

o (*) Avalanche induction strategies

The scheduler is able to maximize the intra-event throughput by applying several search strategies within the pool, prioritizing tasks according to the following types of precedence rules graph asymmetries:

(A) Local task-to-data asymmetry; (B) Local task-to-task asymmetry; (C) Global task-to-task asymmetry.

o Other mechanisms of throughput maximization

The scheduler supports cooperative scheduling with fibers, allowing a task to suspend its execution while waiting for an off-CPU operation to complete. The worker thread is then free to execute other work and resumes the suspended task once the operation completes.

The mechanism can be applied to the following types of tasks:

  • I/O-bound tasks;
  • tasks with computation offloading (accelerators, GPGPUs, clouds);
  • synchronization-bound tasks.

Credits

Historically, the AvalancheSchedulerSvc branched off the ForwardSchedulerSvc and in many ways built its success on ideas and code of the latter.

Author
Illya Shapoval
Version
1.0

Definition at line 114 of file AvalancheSchedulerSvc.h.

Member Typedef Documentation

◆ action

using AvalancheSchedulerSvc::action = std::function<StatusCode()>
private

Definition at line 161 of file AvalancheSchedulerSvc.h.

◆ AState

Member Enumeration Documentation

◆ ActivationState

Enumerator
INACTIVE 
ACTIVE 
FAILURE 

Definition at line 163 of file AvalancheSchedulerSvc.h.

Member Function Documentation

◆ activate()

void AvalancheSchedulerSvc::activate ( )
private

Activate scheduler.

Activate the scheduler.

From this moment on the queue of actions is checked. The checking will stop when the m_isActive flag is false and the queue is not empty. This will guarantee that all actions are executed and a stall is not created. The TBB pool must be initialised in the thread from where the tasks are launched (http://threadingbuildingblocks.org/docs/doxygen/a00342.html) The scheduler is initialised here since this method runs in a separate thread and spawns the tasks (through the execution of the lambdas)

Definition at line 461 of file AvalancheSchedulerSvc.cpp.

461 {
462
463 ON_DEBUG debug() << "AvalancheSchedulerSvc::activate()" << endmsg;
464
465 if ( m_threadPoolSvc->initPool( m_threadPoolSize, m_maxParallelismExtra ).isFailure() ) {
466 error() << "problems initializing ThreadPoolSvc" << endmsg;
468 return;
469 }
470
471 // Wait for actions pushed into the queue by finishing tasks.
472 action thisAction;
473 StatusCode sc( StatusCode::SUCCESS );
474
476
477 // Continue to wait if the scheduler is running or there is something to do
478 ON_DEBUG debug() << "Start checking the actionsQueue" << endmsg;
479 while ( m_isActive == ACTIVE || m_actionsQueue.size() != 0 ) {
480 m_actionsQueue.pop( thisAction );
481 sc = thisAction();
482 ON_VERBOSE {
483 if ( sc.isFailure() )
484 verbose() << "Action did not succeed (which is not bad per se)." << endmsg;
485 else
486 verbose() << "Action succeeded." << endmsg;
487 }
488 else sc.ignore();
489
490 // If all queued actions have been processed, update the slot states
491 if ( m_needsUpdate.load() && m_actionsQueue.empty() ) {
492 sc = iterate();
493 ON_VERBOSE {
494 if ( sc.isFailure() )
495 verbose() << "Iteration did not succeed (which is not bad per se)." << endmsg;
496 else
497 verbose() << "Iteration succeeded." << endmsg;
498 }
499 else sc.ignore();
500 }
501 }
502
503 ON_DEBUG debug() << "Terminating thread-pool resources" << endmsg;
504 if ( m_threadPoolSvc->terminatePool().isFailure() ) {
505 error() << "Problems terminating thread pool" << endmsg;
507 }
508}
#define ON_VERBOSE
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define ON_DEBUG
SmartIF< IThreadPoolSvc > m_threadPoolSvc
Gaudi::Property< int > m_threadPoolSize
tbb::concurrent_bounded_queue< action > m_actionsQueue
Queue where closures are stored and picked for execution.
std::atomic< bool > m_needsUpdate
Gaudi::Property< int > m_maxParallelismExtra
std::function< StatusCode()> action
std::atomic< ActivationState > m_isActive
Flag to track if the scheduler is active or not.
StatusCode iterate()
Loop on all slots to schedule DATAREADY algorithms and sign off ready events.
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
constexpr static const auto SUCCESS
Definition StatusCode.h:99

◆ algname2index()

unsigned int AvalancheSchedulerSvc::algname2index ( const std::string & algoname)
inlineprivate

Convert a name to an integer.

Definition at line 247 of file AvalancheSchedulerSvc.h.

247{ return m_algname_index_map[algoname]; }
std::unordered_map< std::string, unsigned int > m_algname_index_map
Map to bookkeep the information necessary to the name2index conversion.

◆ deactivate()

StatusCode AvalancheSchedulerSvc::deactivate ( )
private

Deactivate scheduler.

Deactivates the scheduler.

Two actions are pushed into the queue: 1) Drain the scheduler until all events are finished. 2) Flip the status flag m_isActive to false This second action is the last one to be executed by the scheduler.

Definition at line 518 of file AvalancheSchedulerSvc.cpp.

518 {
519
520 if ( m_isActive == ACTIVE ) {
521
522 // Set the number of slots available to an error code
523 m_freeSlots.store( 0 );
524
525 // Empty queue
526 action thisAction;
527 while ( m_actionsQueue.try_pop( thisAction ) ) {};
528
529 // This would be the last action
530 m_actionsQueue.push( [this]() -> StatusCode {
531 ON_VERBOSE verbose() << "Deactivating scheduler" << endmsg;
533 return StatusCode::SUCCESS;
534 } );
535 }
536
537 return StatusCode::SUCCESS;
538}
std::atomic_int m_freeSlots
Atomic to account for asyncronous updates by the scheduler wrt the rest.

◆ dumpDataDepsGraphFile()

StatusCode AvalancheSchedulerSvc::dumpDataDepsGraphFile ( const std::map< std::string, DataObjIDColl > & inDeps,
const std::map< std::string, DataObjIDColl > & outDeps ) const
private

Definition at line 1173 of file AvalancheSchedulerSvc.cpp.

1174 {
1175 // Both maps should have the same algorithm entries
1176 assert( inDeps.size() == outDeps.size() );
1177
1178 Gaudi::Hive::Graph g{ m_dataDepsGraphFile.value() };
1179 info() << "Dumping data dependencies graph to file: " << g.fileName() << endmsg;
1180
1181 // define algs and objects
1182 std::set<std::size_t> definedObjects;
1183
1184 // Regex for selection of algs and objects
1185 std::regex algNameRegex( m_dataDepsGraphAlgoPattern.value() );
1186 std::regex objNameRegex( m_dataDepsGraphObjectPattern.value() );
1187
1188 // inDeps and outDeps should have the same entries
1189 std::size_t algoIndex = 0ul;
1190 for ( const auto& [algName, ideps] : inDeps ) {
1191 if ( not std::regex_search( algName, algNameRegex ) ) continue;
1192 std::string algIndex = "Alg_" + std::to_string( algoIndex );
1193 g.addNode( algIndex, algName );
1194
1195 // inputs
1196 for ( const auto& dep : ideps ) {
1197 if ( not std::regex_search( dep.fullKey(), objNameRegex ) ) continue;
1198
1199 const auto [itr, inserted] = definedObjects.insert( dep.hash() );
1200 std::string objIndex = "obj_" + std::to_string( dep.hash() );
1201 if ( inserted ) g.addNode( objIndex, dep.key() );
1202
1203 g.addEdge( objIndex, algIndex );
1204 } // loop on ideps
1205
1206 const auto& odeps = outDeps.at( algName );
1207 for ( const auto& dep : odeps ) {
1208 if ( not std::regex_search( dep.fullKey(), objNameRegex ) ) continue;
1209
1210 const auto [itr, inserted] = definedObjects.insert( dep.hash() );
1211 std::string objIndex = "obj_" + std::to_string( dep.hash() );
1212 if ( inserted ) g.addNode( objIndex, dep.key() );
1213
1214 g.addEdge( algIndex, objIndex );
1215 } // loop on odeps
1216
1217 ++algoIndex;
1218 } // loop on inDeps
1219
1220 return StatusCode::SUCCESS;
1221}
Gaudi::Property< std::string > m_dataDepsGraphObjectPattern
Gaudi::Property< std::string > m_dataDepsGraphFile
Gaudi::Property< std::string > m_dataDepsGraphAlgoPattern
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
dict g
Definition gaudirun.py:582

◆ dumpSchedulerState()

void AvalancheSchedulerSvc::dumpSchedulerState ( int iSlot)
private

Dump the state of the scheduler.

Used for debugging purposes, the state of the scheduler is dumped on screen in order to be inspected.

Definition at line 883 of file AvalancheSchedulerSvc.cpp.

883 {
884
885 // To have just one big message
886 std::ostringstream outputMS;
887
888 outputMS << "Dumping scheduler state\n"
889 << "=========================================================================================\n"
890 << "++++++++++++++++++++++++++++++++++++ SCHEDULER STATE ++++++++++++++++++++++++++++++++++++\n"
891 << "=========================================================================================\n\n";
892
893 //===========================================================================
894
895 outputMS << "------------------ Last schedule: Task/Event/Slot/Thread/State Mapping "
896 << "------------------\n\n";
897
898 // Figure if TimelineSvc is available (used below to detect threads IDs)
899 auto timelineSvc = serviceLocator()->service<ITimelineSvc>( "TimelineSvc", false );
900 if ( !timelineSvc.isValid() || !timelineSvc->isEnabled() ) {
901 outputMS << "WARNING Enable TimelineSvc in record mode (RecordTimeline = True) to trace the mapping\n";
902 } else {
903
904 // Figure optimal printout layout
905 size_t indt( 0 );
906 for ( auto& slot : m_eventSlots ) {
907
908 const auto& schedAlgs = slot.algsStates.algsInState( AState::SCHEDULED );
909 for ( uint algIndex : schedAlgs ) {
910 if ( index2algname( algIndex ).length() > indt ) indt = index2algname( algIndex ).length();
911 }
912 }
913
914 // Figure the last running schedule across all slots
915 for ( auto& slot : m_eventSlots ) {
916
917 const auto& schedAlgs = slot.algsStates.algsInState( AState::SCHEDULED );
918 for ( uint algIndex : schedAlgs ) {
919
920 const std::string& algoName{ index2algname( algIndex ) };
921
922 outputMS << " task: " << std::setw( indt ) << algoName << " evt/slot: " << slot.eventContext->evt() << "/"
923 << slot.eventContext->slot();
924
925 // Try to get POSIX threads IDs the currently running tasks are scheduled to
926 if ( timelineSvc.isValid() ) {
927 TimelineEvent te{};
928 te.algorithm = algoName;
929 te.slot = slot.eventContext->slot();
930 te.event = slot.eventContext->evt();
931
932 if ( timelineSvc->getTimelineEvent( te ) )
933 outputMS << " thread.id: 0x" << std::hex << te.thread << std::dec;
934 else
935 outputMS << " thread.id: [unknown]"; // this means a task has just
936 // been signed off as SCHEDULED,
937 // but has not been assigned to a thread yet
938 // (i.e., not running yet)
939 }
940 outputMS << " state: [" << m_algExecStateSvc->algExecState( algoName, *( slot.eventContext ) ) << "]\n";
941 }
942 }
943 }
944
945 //===========================================================================
946
947 outputMS << "\n---------------------------- Task/CF/FSM Mapping "
948 << ( 0 > iSlot ? "[all slots] --" : "[target slot] " ) << "--------------------------\n\n";
949
950 int slotCount = -1;
951 bool wasAlgError = ( iSlot >= 0 ) ? m_eventSlots[iSlot].algsStates.containsAny( { AState::ERROR } ) ||
952 subSlotAlgsInStates( m_eventSlots[iSlot], { AState::ERROR } )
953 : false;
954
955 for ( auto& slot : m_eventSlots ) {
956 ++slotCount;
957 if ( slot.complete ) continue;
958
959 outputMS << "[ slot: "
960 << ( slot.eventContext->valid() ? std::to_string( slot.eventContext->slot() ) : "[ctx invalid]" )
961 << ", event: "
962 << ( slot.eventContext->valid() ? std::to_string( slot.eventContext->evt() ) : "[ctx invalid]" );
963
964 if ( slot.eventContext->eventID().isValid() ) { outputMS << ", eventID: " << slot.eventContext->eventID(); }
965 outputMS << " ]:\n\n";
966
967 if ( 0 > iSlot || iSlot == slotCount ) {
968
969 // If an alg has thrown an error then it's not a failure of the CF/DF graph
970 if ( wasAlgError ) {
971 outputMS << "ERROR alg(s):";
972 int errorCount = 0;
973 const auto& errorAlgs = slot.algsStates.algsInState( AState::ERROR );
974 for ( uint algIndex : errorAlgs ) {
975 outputMS << " " << index2algname( algIndex );
976 ++errorCount;
977 }
978 if ( errorCount == 0 ) outputMS << " in subslot(s)";
979 outputMS << "\n\n";
980 } else {
981 // Snapshot of the Control Flow and FSM states
982 outputMS << m_precSvc->printState( slot ) << "\n";
983 }
984
985 // Mention sub slots (this is expensive if the number of sub-slots is high)
986 if ( m_verboseSubSlots && !slot.allSubSlots.empty() ) {
987 outputMS << "\nNumber of sub-slots: " << slot.allSubSlots.size() << "\n\n";
988 auto slotID = slot.eventContext->valid() ? std::to_string( slot.eventContext->slot() ) : "[ctx invalid]";
989 for ( auto& ss : slot.allSubSlots ) {
990 outputMS << "[ slot: " << slotID << ", sub-slot: "
991 << ( ss.eventContext->valid() ? std::to_string( ss.eventContext->subSlot() ) : "[ctx invalid]" )
992 << ", entry: " << ss.entryPoint << ", event: "
993 << ( ss.eventContext->valid() ? std::to_string( ss.eventContext->evt() ) : "[ctx invalid]" )
994 << " ]:\n\n";
995 if ( wasAlgError ) {
996 outputMS << "ERROR alg(s):";
997 const auto& errorAlgs = ss.algsStates.algsInState( AState::ERROR );
998 for ( uint algIndex : errorAlgs ) { outputMS << " " << index2algname( algIndex ); }
999 outputMS << "\n\n";
1000 } else {
1001 // Snapshot of the Control Flow and FSM states in sub slot
1002 outputMS << m_precSvc->printState( ss ) << "\n";
1003 }
1004 }
1005 }
1006 }
1007 }
1008
1009 //===========================================================================
1010
1011 if ( 0 <= iSlot && !wasAlgError ) {
1012 outputMS << "\n------------------------------ Algorithm Execution States -----------------------------\n\n";
1013 m_algExecStateSvc->dump( outputMS, *( m_eventSlots[iSlot].eventContext ) );
1014 }
1015
1016 outputMS << "\n=========================================================================================\n"
1017 << "++++++++++++++++++++++++++++++++++++++ END OF DUMP ++++++++++++++++++++++++++++++++++++++\n"
1018 << "=========================================================================================\n\n";
1019
1020 info() << outputMS.str() << endmsg;
1021}
Gaudi::Property< bool > m_verboseSubSlots
SmartIF< IAlgExecStateSvc > m_algExecStateSvc
Algorithm execution state manager.
SmartIF< IPrecedenceSvc > m_precSvc
A shortcut to the Precedence Service.
const std::string & index2algname(unsigned int index)
Convert an integer to a name.
std::vector< EventSlot > m_eventSlots
Vector of events slots.
virtual SmartIF< IService > & service(const Gaudi::Utils::TypeNameString &typeName, const bool createIf=true)=0
Returns a smart pointer to a service.
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator.
Definition Service.cpp:336
std::string algorithm
pthread_t thread

◆ dumpState()

void AvalancheSchedulerSvc::dumpState ( )
override

Dump scheduler state for all slots.

Definition at line 622 of file AvalancheSchedulerSvc.cpp.

622{ dumpSchedulerState( -1 ); }
void dumpSchedulerState(int iSlot)
Dump the state of the scheduler.

◆ eventFailed()

void AvalancheSchedulerSvc::eventFailed ( EventContext * eventContext)
private

Method to execute if an event failed.

It can be possible that an event fails.

In this case this method is called. It dumps the state of the scheduler and marks the event as finished.

Definition at line 862 of file AvalancheSchedulerSvc.cpp.

862 {
863 const uint slotIdx = eventContext->slot();
864
865 error() << "Event " << eventContext->evt() << " on slot " << slotIdx << " failed" << endmsg;
866
867 dumpSchedulerState( msgLevel( MSG::VERBOSE ) ? -1 : slotIdx );
868
869 // dump temporal and topological precedence analysis (if enabled in the PrecedenceSvc)
870 m_precSvc->dumpPrecedenceRules( m_eventSlots[slotIdx] );
871
872 // Push into the finished events queue the failed context
873 m_eventSlots[slotIdx].complete = true;
874 m_finishedEvents.push( m_eventSlots[slotIdx].eventContext.release() );
875}
tbb::concurrent_bounded_queue< EventContext * > m_finishedEvents
Queue of finished events.
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
ContextEvt_t evt() const
ContextID_t slot() const
@ VERBOSE
Definition IMessageSvc.h:22

◆ finalize()

StatusCode AvalancheSchedulerSvc::finalize ( )
override

Finalise.

Here the scheduler is deactivated and the thread joined.

Definition at line 427 of file AvalancheSchedulerSvc.cpp.

427 {
428
429 StatusCode sc( Service::finalize() );
430 if ( sc.isFailure() ) warning() << "Base class could not be finalized" << endmsg;
431
432 sc = deactivate();
433 if ( sc.isFailure() ) warning() << "Scheduler could not be deactivated" << endmsg;
434
435 debug() << "Deleting FiberManager" << endmsg;
436 m_fiberManager.reset();
437
438 info() << "Joining Scheduler thread" << endmsg;
439 m_thread.join();
440
441 // Final error check after thread pool termination
442 if ( m_isActive == FAILURE ) {
443 error() << "problems in scheduler thread" << endmsg;
444 return StatusCode::FAILURE;
445 }
446
447 return sc;
448}
StatusCode deactivate()
Deactivate scheduler.
std::unique_ptr< FiberManager > m_fiberManager
std::thread m_thread
The thread in which the activate function runs.
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
StatusCode finalize() override
Definition Service.cpp:223
constexpr static const auto FAILURE
Definition StatusCode.h:100

◆ freeSlots()

unsigned int AvalancheSchedulerSvc::freeSlots ( )
override

Get free slots number.

Definition at line 618 of file AvalancheSchedulerSvc.cpp.

618{ return std::max( m_freeSlots.load(), 0 ); }

◆ index2algname()

const std::string & AvalancheSchedulerSvc::index2algname ( unsigned int index)
inlineprivate

Convert an integer to a name.

Definition at line 253 of file AvalancheSchedulerSvc.h.

253{ return m_algname_vect[index]; }
std::vector< std::string > m_algname_vect
Vector to bookkeep the information necessary to the index2name conversion.
size_t index(const Gaudi::ParticleProperty *property, const Gaudi::Interfaces::IParticlePropertySvc *service)
helper utility for mapping of Gaudi::ParticleProperty object into non-negative integral sequential id...

◆ initialize()

StatusCode AvalancheSchedulerSvc::initialize ( )
override

Initialise.

Here, among some "bureaucracy" operations, the scheduler is activated, executing the activate() function in a new thread.

In addition the algorithms list is acquired from the algResourcePool.

Definition at line 78 of file AvalancheSchedulerSvc.cpp.

78 {
79
80 // Initialise mother class (read properties, ...)
81 StatusCode sc( Service::initialize() );
82 if ( sc.isFailure() ) warning() << "Base class could not be initialized" << endmsg;
83
84 // Get hold of the TBBSvc. This should initialize the thread pool
85 m_threadPoolSvc = serviceLocator()->service( "ThreadPoolSvc" );
86 if ( !m_threadPoolSvc.isValid() ) {
87 fatal() << "Error retrieving ThreadPoolSvc" << endmsg;
89 }
90 auto castTPS = dynamic_cast<ThreadPoolSvc*>( m_threadPoolSvc.get() );
91 if ( !castTPS ) {
92 fatal() << "Cannot cast ThreadPoolSvc" << endmsg;
94 }
95 m_arena = castTPS->getArena();
96 if ( !m_arena ) {
97 fatal() << "Cannot find valid TBB task_arena" << endmsg;
99 }
100
101 // Activate the scheduler in another thread.
102 info() << "Activating scheduler in a separate thread" << endmsg;
103 std::binary_semaphore fiber_manager_initalized{ 0 };
104 m_thread = std::thread( [this, &fiber_manager_initalized]() {
105 // Initialize FiberManager
106 this->m_fiberManager = std::make_unique<FiberManager>( this->m_numOffloadThreads.value() );
107 fiber_manager_initalized.release();
108 this->activate();
109 } );
110 // Wait for initialization to complete
111 fiber_manager_initalized.acquire();
112
113 while ( m_isActive != ACTIVE ) {
114 if ( m_isActive == FAILURE ) {
115 fatal() << "Terminating initialization" << endmsg;
116 return StatusCode::FAILURE;
117 } else {
118 ON_DEBUG debug() << "Waiting for AvalancheSchedulerSvc to activate" << endmsg;
119 sleep( 1 );
120 }
121 }
122
123 if ( m_enableCondSvc ) {
124 // Get hold of the CondSvc
125 m_condSvc = serviceLocator()->service( "CondSvc" );
126 if ( !m_condSvc.isValid() ) {
127 warning() << "No CondSvc found, or not enabled. "
128 << "Will not manage CondAlgorithms" << endmsg;
129 m_enableCondSvc = false;
130 }
131 }
132
133 // Get the algo resource pool
134 m_algResourcePool = serviceLocator()->service( "AlgResourcePool" );
135 if ( !m_algResourcePool.isValid() ) {
136 fatal() << "Error retrieving AlgoResourcePool" << endmsg;
137 return StatusCode::FAILURE;
138 }
139
140 m_algExecStateSvc = serviceLocator()->service( "AlgExecStateSvc" );
141 if ( !m_algExecStateSvc.isValid() ) {
142 fatal() << "Error retrieving AlgExecStateSvc" << endmsg;
143 return StatusCode::FAILURE;
144 }
145
146 // Get Whiteboard
148 if ( !m_whiteboard.isValid() ) {
149 fatal() << "Error retrieving EventDataSvc interface IHiveWhiteBoard." << endmsg;
150 return StatusCode::FAILURE;
151 }
152
153 // Set the MaxEventsInFlight parameters from the number of WB stores
154 m_maxEventsInFlight = m_whiteboard->getNumberOfStores();
155
156 // Set the number of free slots
158
159 // Get the list of algorithms
160 const std::list<IAlgorithm*>& algos = m_algResourcePool->getFlatAlgList();
161 const unsigned int algsNumber = algos.size();
162 if ( algsNumber != 0 ) {
163 info() << "Found " << algsNumber << " algorithms" << endmsg;
164 } else {
165 error() << "No algorithms found" << endmsg;
166 return StatusCode::FAILURE;
167 }
168
169 /* Dependencies
170 1) Look for handles in algo, if none
171 2) Assume none are required
172 */
173
174 DataObjIDColl globalInp, globalOutp;
175
176 auto hasAsynchronousAlgorithms = false;
177
178 // figure out all outputs and check for asynchronous algorithms
179 std::map<std::string, DataObjIDColl> algosOutputDependenciesMap;
180 for ( IAlgorithm* ialgoPtr : algos ) {
181 Gaudi::Algorithm* algoPtr = dynamic_cast<Gaudi::Algorithm*>( ialgoPtr );
182 if ( !algoPtr ) {
183 fatal() << "Could not convert IAlgorithm into Gaudi::Algorithm: this will result in a crash." << endmsg;
184 return StatusCode::FAILURE;
185 }
186
187 DataObjIDColl algoOutputs;
188 for ( auto id : algoPtr->outputDataObjs() ) {
189 globalOutp.insert( id );
190 algoOutputs.insert( id );
191 }
192 algosOutputDependenciesMap[algoPtr->name()] = algoOutputs;
193
194 hasAsynchronousAlgorithms = hasAsynchronousAlgorithms || algoPtr->isAsynchronous();
195 }
196
197 if ( m_numOffloadThreads <= 0 && hasAsynchronousAlgorithms ) {
198 fatal() << "Found asynchronous algorithms, but NumOffloadThreads is " << m_numOffloadThreads
199 << "; no fiber pool threads will be available to execute them." << endmsg;
200 return StatusCode::FAILURE;
201 }
202
203 std::ostringstream ostdd;
204 ostdd << "Data Dependencies for Algorithms:";
205
206 std::map<std::string, DataObjIDColl> algosInputDependenciesMap;
207 for ( IAlgorithm* ialgoPtr : algos ) {
208 Gaudi::Algorithm* algoPtr = dynamic_cast<Gaudi::Algorithm*>( ialgoPtr );
209 if ( nullptr == algoPtr ) {
210 fatal() << "Could not convert IAlgorithm into Gaudi::Algorithm for " << ialgoPtr->name()
211 << ": this will result in a crash." << endmsg;
212 return StatusCode::FAILURE;
213 }
214
215 DataObjIDColl i1, i2;
216 DHHVisitor avis( i1, i2 );
217 algoPtr->acceptDHVisitor( &avis );
218
219 ostdd << "\n " << algoPtr->name();
220
221 auto write_owners = [&avis, &ostdd]( const DataObjID& id ) {
222 auto owners = avis.owners_names_of( id );
223 if ( !owners.empty() ) { GaudiUtils::operator<<( ostdd << ' ', owners ); }
224 };
225
226 DataObjIDColl algoDependencies;
227 if ( !algoPtr->inputDataObjs().empty() || !algoPtr->outputDataObjs().empty() ) {
228 for ( const DataObjID* idp : sortedDataObjIDColl( algoPtr->inputDataObjs() ) ) {
229 DataObjID id = *idp;
230 ostdd << "\n o INPUT " << id;
231 write_owners( id );
232 algoDependencies.insert( id );
233 globalInp.insert( id );
234 }
235 for ( const DataObjID* id : sortedDataObjIDColl( algoPtr->outputDataObjs() ) ) {
236 ostdd << "\n o OUTPUT " << *id;
237 write_owners( *id );
238 if ( id->key().find( ":" ) != std::string::npos ) {
239 error() << " in Alg " << algoPtr->name() << " alternatives are NOT allowed for outputs! id: " << *id
240 << endmsg;
241 m_showDataDeps = true;
242 }
243 }
244 } else {
245 ostdd << "\n none";
246 }
247 algosInputDependenciesMap[algoPtr->name()] = algoDependencies;
248 }
249
250 if ( m_showDataDeps ) { info() << ostdd.str() << endmsg; }
251
252 // If requested, dump a graph of the data dependencies in a .dot, .md or .graphml file
253 if ( not m_dataDepsGraphFile.empty() ) {
254 if ( dumpDataDepsGraphFile( algosInputDependenciesMap, algosOutputDependenciesMap ).isFailure() ) {
255 return StatusCode::FAILURE;
256 }
257 }
258
259 // Check if we have unmet global input dependencies, and, optionally, heal them
260 // WARNING: this step must be done BEFORE the Precedence Service is initialized
261 DataObjIDColl unmetDepInp, unusedOutp;
262 if ( m_checkDeps || m_checkOutput ) {
263 std::set<std::string> requiredInputKeys;
264 for ( auto o : globalInp ) {
265 // track aliases
266 // (assuming there should be no items with different class and same key corresponding to different objects)
267 requiredInputKeys.insert( o.key() );
268 if ( globalOutp.find( o ) == globalOutp.end() ) unmetDepInp.insert( o );
269 }
270 if ( m_checkOutput ) {
271 for ( auto o : globalOutp ) {
272 if ( globalInp.find( o ) == globalInp.end() && requiredInputKeys.find( o.key() ) == requiredInputKeys.end() ) {
273 // check ignores
274 bool ignored{};
275 for ( const std::string& algoName : m_checkOutputIgnoreList ) {
276 auto it = algosOutputDependenciesMap.find( algoName );
277 if ( it != algosOutputDependenciesMap.end() ) {
278 if ( it->second.find( o ) != it->second.end() ) {
279 ignored = true;
280 break;
281 }
282 }
283 }
284 if ( !ignored ) { unusedOutp.insert( o ); }
285 }
286 }
287 }
288 }
289
290 if ( m_checkDeps ) {
291 if ( unmetDepInp.size() > 0 ) {
292
293 auto printUnmet = [&]( auto msg ) {
294 for ( const DataObjID* o : sortedDataObjIDColl( unmetDepInp ) ) {
295 msg << " o " << *o << " required by Algorithm: " << endmsg;
296
297 for ( const auto& p : algosInputDependenciesMap )
298 if ( p.second.find( *o ) != p.second.end() ) msg << " * " << p.first << endmsg;
299 }
300 };
301
302 if ( !m_useDataLoader.empty() ) {
303
304 // Find the DataLoader Alg
305 IAlgorithm* dataLoaderAlg( nullptr );
306 for ( IAlgorithm* algo : algos )
307 if ( m_useDataLoader == algo->name() ) {
308 dataLoaderAlg = algo;
309 break;
310 }
311
312 if ( dataLoaderAlg == nullptr ) {
313 fatal() << "No DataLoader Algorithm \"" << m_useDataLoader.value()
314 << "\" found, and unmet INPUT dependencies "
315 << "detected:" << endmsg;
316 printUnmet( fatal() );
317 return StatusCode::FAILURE;
318 }
319
320 info() << "Will attribute the following unmet INPUT dependencies to \"" << dataLoaderAlg->type() << "/"
321 << dataLoaderAlg->name() << "\" Algorithm" << endmsg;
322 printUnmet( info() );
323
324 // Set the property Load of DataLoader Alg
325 Gaudi::Algorithm* dataAlg = dynamic_cast<Gaudi::Algorithm*>( dataLoaderAlg );
326 if ( !dataAlg ) {
327 fatal() << "Unable to dcast DataLoader \"" << m_useDataLoader.value() << "\" IAlg to Gaudi::Algorithm"
328 << endmsg;
329 return StatusCode::FAILURE;
330 }
331
332 for ( auto& id : unmetDepInp ) {
333 ON_DEBUG debug() << "adding OUTPUT dep \"" << id << "\" to " << dataLoaderAlg->type() << "/"
334 << dataLoaderAlg->name() << endmsg;
336 }
337
338 } else {
339 fatal() << "Auto DataLoading not requested, "
340 << "and the following unmet INPUT dependencies were found:" << endmsg;
341 printUnmet( fatal() );
342 return StatusCode::FAILURE;
343 }
344
345 } else {
346 info() << "No unmet INPUT data dependencies were found" << endmsg;
347 }
348 }
349
350 if ( m_checkOutput ) {
351 if ( unusedOutp.size() > 0 ) {
352
353 auto printUnusedOutp = [&]( auto msg ) {
354 for ( const DataObjID* o : sortedDataObjIDColl( unusedOutp ) ) {
355 msg << " o " << *o << " produced by Algorithm: " << endmsg;
356
357 for ( const auto& p : algosOutputDependenciesMap )
358 if ( p.second.find( *o ) != p.second.end() ) msg << " * " << p.first << endmsg;
359 }
360 };
361
362 fatal() << "The following unused OUTPUT items were found:" << endmsg;
363 printUnusedOutp( fatal() );
364 return StatusCode::FAILURE;
365 } else {
366 info() << "No unused OUTPUT items were found" << endmsg;
367 }
368 }
369
370 // Get the precedence service
371 m_precSvc = serviceLocator()->service( "PrecedenceSvc" );
372 if ( !m_precSvc.isValid() ) {
373 fatal() << "Error retrieving PrecedenceSvc" << endmsg;
374 return StatusCode::FAILURE;
375 }
376 const PrecedenceSvc* precSvc = dynamic_cast<const PrecedenceSvc*>( m_precSvc.get() );
377 if ( !precSvc ) {
378 fatal() << "Unable to dcast PrecedenceSvc" << endmsg;
379 return StatusCode::FAILURE;
380 }
381
382 // Fill the containers to convert algo names to index
383 m_algname_vect.resize( algsNumber );
384 for ( IAlgorithm* algo : algos ) {
385 const std::string& name = algo->name();
386 auto index = precSvc->getRules()->getAlgorithmNode( name )->getAlgoIndex();
388 m_algname_vect.at( index ) = name;
389 }
390
391 // Shortcut for the message service
392 SmartIF<IMessageSvc> messageSvc( serviceLocator() );
393 if ( !messageSvc.isValid() ) error() << "Error retrieving MessageSvc interface IMessageSvc." << endmsg;
394
396 for ( size_t i = 0; i < m_maxEventsInFlight; ++i ) {
397 m_eventSlots.emplace_back( algsNumber, precSvc->getRules()->getControlFlowNodeCounter(), messageSvc );
398 m_eventSlots.back().complete = true;
399 }
400
401 // Clearly inform about the level of concurrency
402 info() << "Concurrency level information:" << endmsg;
403 info() << " o Number of events in flight: " << m_maxEventsInFlight << endmsg;
404 info() << " o TBB thread pool size: " << m_threadPoolSize << endmsg;
405 info() << " o Fiber thread pool size: " << m_numOffloadThreads << endmsg;
406
407 // Inform about task scheduling prescriptions
408 info() << "Task scheduling settings:" << endmsg;
409 info() << " o Avalanche generation mode: "
410 << ( m_optimizationMode.empty() ? "disabled" : m_optimizationMode.toString() ) << endmsg;
411 info() << " o Scheduling of condition tasks: " << ( m_enableCondSvc ? "enabled" : "disabled" ) << endmsg;
412
413 if ( m_showControlFlow ) m_precSvc->dumpControlFlow();
414
415 if ( m_showDataFlow ) m_precSvc->dumpDataFlow();
416
417 // Simulate execution flow
418 if ( m_simulateExecution ) sc = m_precSvc->simulate( m_eventSlots[0] );
419
420 return sc;
421}
std::unordered_set< DataObjID, DataObjID_Hasher > DataObjIDColl
Definition DataObjID.h:121
Gaudi::Property< std::vector< std::string > > m_checkOutputIgnoreList
Gaudi::Property< std::string > m_useDataLoader
void activate()
Activate scheduler.
Gaudi::Property< std::string > m_optimizationMode
SmartIF< ICondSvc > m_condSvc
A shortcut to service for Conditions handling.
Gaudi::Property< bool > m_showDataFlow
Gaudi::Property< bool > m_checkDeps
SmartIF< IAlgResourcePool > m_algResourcePool
Cache for the algorithm resource pool.
Gaudi::Property< bool > m_showControlFlow
Gaudi::Property< bool > m_simulateExecution
Gaudi::Property< std::string > m_whiteboardSvcName
Gaudi::Property< int > m_numOffloadThreads
Gaudi::Property< bool > m_checkOutput
Gaudi::Property< bool > m_enableCondSvc
StatusCode dumpDataDepsGraphFile(const std::map< std::string, DataObjIDColl > &inDeps, const std::map< std::string, DataObjIDColl > &outDeps) const
SmartIF< IHiveWhiteBoard > m_whiteboard
A shortcut to the whiteboard.
Gaudi::Property< bool > m_showDataDeps
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
MsgStream & msg() const
shortcut for the method msgStream(MSG::INFO)
const DataObjIDColl & outputDataObjs() const override
void addDependency(const DataObjID &id, const Gaudi::DataHandle::Mode &mode) override
const DataObjIDColl & inputDataObjs() const override
void acceptDHVisitor(IDataHandleVisitor *) const override
const std::string & name() const override
The identifying name of the algorithm object.
bool isAsynchronous() const
Definition Algorithm.h:376
const concurrency::PrecedenceRulesGraph * getRules() const
Precedence rules accessor.
const std::string & name() const override
Retrieve name of the service.
Definition Service.cpp:333
StatusCode initialize() override
Definition Service.cpp:118
unsigned int getAlgoIndex() const
Get algorithm index.
unsigned int getControlFlowNodeCounter() const
Get total number of control flow graph nodes.
AlgorithmNode * getAlgorithmNode(const std::string &algoName) const
Get the AlgorithmNode from by algorithm name using graph index.
std::ostream & operator<<(std::ostream &s, const std::pair< T1, T2 > &p)
Serialize an std::pair in a python like format. E.g. "(1, 2)".

◆ isStalled()

bool AvalancheSchedulerSvc::isStalled ( const EventSlot & slot) const
private

Check if scheduling in a particular slot is in a stall.

Check if we are in present of a stall condition for a particular slot.

This is the case when a slot has no actions queued in the actionsQueue, has no scheduled algorithms and has no algorithms with all of its dependencies satisfied.

Definition at line 844 of file AvalancheSchedulerSvc.cpp.

844 {
845
846 if ( !slot.algsStates.containsAny( { AState::DATAREADY, AState::SCHEDULED, AState::RESOURCELESS } ) &&
847 !subSlotAlgsInStates( slot, { AState::DATAREADY, AState::SCHEDULED, AState::RESOURCELESS } ) ) {
848
849 error() << "*** Stall detected, event context: " << slot.eventContext.get() << endmsg;
850
851 return true;
852 }
853 return false;
854}
bool containsAny(std::initializer_list< State > l) const
check if the collection contains at least one state of any listed types
std::unique_ptr< EventContext > eventContext
Cache for the eventContext.
Definition EventSlot.h:82
AlgsExecutionStates algsStates
Vector of algorithms states.
Definition EventSlot.h:84

◆ iterate()

StatusCode AvalancheSchedulerSvc::iterate ( )
private

Loop on all slots to schedule DATAREADY algorithms and sign off ready events.

Loop on all slots to schedule DATAREADY algorithms, sign off ready ones or detect execution stalls.

To check if an event is finished the method verifies that the root control flow decision of the task precedence graph is resolved and there are no algorithms moving in-between INITIAL and EVTACCEPTED FSM states.

Definition at line 669 of file AvalancheSchedulerSvc.cpp.

669 {
670
671 StatusCode global_sc( StatusCode::SUCCESS );
672
673 // Retry algorithms
674 const size_t retries = m_retryQueue.size();
675 for ( unsigned int retryIndex = 0; retryIndex < retries; ++retryIndex ) {
676 TaskSpec retryTS = std::move( m_retryQueue.front() );
677 m_retryQueue.pop();
678 global_sc = schedule( std::move( retryTS ) );
679 }
680
681 // Loop over all slots
682 OccupancySnapshot nextSnap;
683 auto now = std::chrono::system_clock::now();
684 for ( EventSlot& thisSlot : m_eventSlots ) {
685
686 // Ignore slots without a valid context (relevant when populating scheduler for first time)
687 if ( !thisSlot.eventContext ) continue;
688
689 int iSlot = thisSlot.eventContext->slot();
690
691 // Cache the states of the algorithms to improve readability and performance
692 AlgsExecutionStates& thisAlgsStates = thisSlot.algsStates;
693
694 StatusCode partial_sc = StatusCode::FAILURE;
695
696 // Make an occupancy snapshot
697 if ( m_snapshotInterval != std::chrono::duration<int64_t, std::milli>::min() &&
699
700 // Initialise snapshot
701 if ( nextSnap.states.empty() ) {
702 nextSnap.time = now;
703 nextSnap.states.resize( m_eventSlots.size() );
704 }
705
706 // Store alg states
707 std::vector<int>& slotStateTotals = nextSnap.states[iSlot];
708 slotStateTotals.resize( AState::MAXVALUE );
709 for ( uint8_t state = 0; state < AState::MAXVALUE; ++state ) {
710 slotStateTotals[state] = thisSlot.algsStates.sizeOfSubset( AState( state ) );
711 }
712
713 // Add subslot alg states
714 for ( auto& subslot : thisSlot.allSubSlots ) {
715 for ( uint8_t state = 0; state < AState::MAXVALUE; ++state ) {
716 slotStateTotals[state] += subslot.algsStates.sizeOfSubset( AState( state ) );
717 }
718 }
719 }
720
721 // Perform DR->SCHEDULED
722 const auto& drAlgs = thisAlgsStates.algsInState( AState::DATAREADY );
723 for ( uint algIndex : drAlgs ) {
724 const std::string& algName{ index2algname( algIndex ) };
725 unsigned int rank{ m_optimizationMode.empty() ? 0 : m_precSvc->getPriority( algName ) };
726 bool asynchronous{ m_precSvc->isAsynchronous( algName ) };
727
728 partial_sc =
729 schedule( TaskSpec( nullptr, algIndex, algName, rank, asynchronous, iSlot, thisSlot.eventContext.get() ) );
730
731 ON_VERBOSE if ( partial_sc.isFailure() ) verbose()
732 << "Could not apply transition from " << AState::DATAREADY << " for algorithm " << algName
733 << " on processing slot " << iSlot << endmsg;
734 }
735
736 // Check for algorithms ready in sub-slots
737 for ( auto& subslot : thisSlot.allSubSlots ) {
738 const auto& drAlgsSubSlot = subslot.algsStates.algsInState( AState::DATAREADY );
739 for ( uint algIndex : drAlgsSubSlot ) {
740 const std::string& algName{ index2algname( algIndex ) };
741 unsigned int rank{ m_optimizationMode.empty() ? 0 : m_precSvc->getPriority( algName ) };
742 bool asynchronous{ m_precSvc->isAsynchronous( algName ) };
743 partial_sc =
744 schedule( TaskSpec( nullptr, algIndex, algName, rank, asynchronous, iSlot, subslot.eventContext.get() ) );
745 }
746 }
747
749 std::stringstream s;
750 s << "START, " << thisAlgsStates.sizeOfSubset( AState::CONTROLREADY ) << ", "
751 << thisAlgsStates.sizeOfSubset( AState::DATAREADY ) << ", " << thisAlgsStates.sizeOfSubset( AState::SCHEDULED )
752 << ", " << std::chrono::high_resolution_clock::now().time_since_epoch().count() << "\n";
753 auto threads = ( m_threadPoolSize != -1 ) ? std::to_string( m_threadPoolSize )
754 : std::to_string( std::thread::hardware_concurrency() );
755 std::ofstream myfile;
756 myfile.open( "IntraEventFSMOccupancy_" + threads + "T.csv", std::ios::app );
757 myfile << s.str();
758 myfile.close();
759 }
760
761 // Not complete because this would mean that the slot is already free!
762 if ( m_precSvc->CFRulesResolved( thisSlot ) &&
763 !thisSlot.algsStates.containsAny(
764 { AState::CONTROLREADY, AState::DATAREADY, AState::SCHEDULED, AState::RESOURCELESS } ) &&
765 !subSlotAlgsInStates( thisSlot,
766 { AState::CONTROLREADY, AState::DATAREADY, AState::SCHEDULED, AState::RESOURCELESS } ) &&
767 !thisSlot.complete ) {
768
769 thisSlot.complete = true;
770 // if the event did not fail, add it to the finished events
771 // otherwise it is taken care of in the error handling
772 if ( m_algExecStateSvc->eventStatus( *thisSlot.eventContext ) == EventStatus::Success ) {
773 ON_DEBUG debug() << "Event " << thisSlot.eventContext->evt() << " finished (slot "
774 << thisSlot.eventContext->slot() << ")." << endmsg;
775 m_finishedEvents.push( thisSlot.eventContext.release() );
776 }
777
778 // now let's return the fully evaluated result of the control flow
779 ON_DEBUG debug() << m_precSvc->printState( thisSlot ) << endmsg;
780
781 thisSlot.eventContext.reset( nullptr );
782
783 } else if ( isStalled( thisSlot ) ) {
784 m_algExecStateSvc->setEventStatus( EventStatus::AlgStall, *thisSlot.eventContext );
785 eventFailed( thisSlot.eventContext.get() ); // can't release yet
786 }
787 partial_sc.ignore();
788 } // end loop on slots
789
790 // Process snapshot
791 if ( !nextSnap.states.empty() ) {
792 m_lastSnapshot = nextSnap.time;
793 m_snapshotCallback( std::move( nextSnap ) );
794 }
795
796 ON_VERBOSE verbose() << "Iteration done." << endmsg;
797 m_needsUpdate.store( false );
798 return global_sc;
799}
const boost::container::flat_set< int > algsInState(State state) const
size_t sizeOfSubset(State state) const
Gaudi::Property< bool > m_dumpIntraEventDynamics
std::chrono::system_clock::time_point m_lastSnapshot
std::function< void(OccupancySnapshot)> m_snapshotCallback
std::queue< TaskSpec > m_retryQueue
AlgsExecutionStates::State AState
bool isStalled(const EventSlot &) const
Check if scheduling in a particular slot is in a stall.
StatusCode schedule(TaskSpec &&)
std::chrono::duration< int64_t, std::milli > m_snapshotInterval
void eventFailed(EventContext *eventContext)
Method to execute if an event failed.
bool isFailure() const
Definition StatusCode.h:118
void ignore() const
Allow discarding a StatusCode without warning.
Definition StatusCode.h:128
Struct to hold entries in the alg queues.

◆ next()

bool AvalancheSchedulerSvc::next ( TaskSpec & ts,
bool asynchronous )
inline

Definition at line 368 of file AvalancheSchedulerSvc.h.

368 {
369 if ( asynchronous ) { return m_scheduledAsynchronousQueue.try_pop( ts ); }
370 return m_scheduledQueue.try_pop( ts );
371 }
tbb::concurrent_priority_queue< TaskSpec, AlgQueueSort > m_scheduledQueue
Queues for scheduled algorithms.
tbb::concurrent_priority_queue< TaskSpec, AlgQueueSort > m_scheduledAsynchronousQueue

◆ popFinishedEvent()

StatusCode AvalancheSchedulerSvc::popFinishedEvent ( EventContext *& eventContext)
override

Blocks until an event is available.

Get a finished event or block until one becomes available.

Definition at line 628 of file AvalancheSchedulerSvc.cpp.

628 {
629
630 // ON_DEBUG debug() << "popFinishedEvent: queue size: " << m_finishedEvents.size() << endmsg;
631 if ( m_freeSlots.load() == (int)m_maxEventsInFlight || m_isActive == INACTIVE ) {
632 // ON_DEBUG debug() << "freeslots: " << m_freeSlots << "/" << m_maxEventsInFlight
633 // << " active: " << m_isActive << endmsg;
634 return StatusCode::FAILURE;
635 } else {
636 // ON_DEBUG debug() << "freeslots: " << m_freeSlots << "/" << m_maxEventsInFlight
637 // << " active: " << m_isActive << endmsg;
638 m_finishedEvents.pop( eventContext );
639 ++m_freeSlots;
640 ON_DEBUG debug() << "Popped slot " << eventContext->slot() << " (event " << eventContext->evt() << ")" << endmsg;
641 return StatusCode::SUCCESS;
642 }
643}

◆ pushNewEvent()

StatusCode AvalancheSchedulerSvc::pushNewEvent ( EventContext * eventContext)
override

Make an event available to the scheduler.

Add event to the scheduler.

There are two cases possible: 1) No slot is free. A StatusCode::FAILURE is returned. 2) At least one slot is free. An action which resets the slot and kicks off its update is queued.

Definition at line 549 of file AvalancheSchedulerSvc.cpp.

549 {
550
551 if ( !eventContext ) {
552 fatal() << "Event context is nullptr" << endmsg;
553 return StatusCode::FAILURE;
554 }
555
556 if ( m_freeSlots.load() == 0 ) {
557 ON_DEBUG debug() << "A free processing slot could not be found." << endmsg;
558 return StatusCode::FAILURE;
559 }
560
561 // no problem as push new event is only called from one thread (event loop manager)
562 --m_freeSlots;
563
564 auto action = [this, eventContext]() -> StatusCode {
565 // Event processing slot forced to be the same as the wb slot
566 const unsigned int thisSlotNum = eventContext->slot();
567 EventSlot& thisSlot = m_eventSlots[thisSlotNum];
568 if ( !thisSlot.complete ) {
569 fatal() << "The slot " << thisSlotNum << " is supposed to be a finished event but it's not" << endmsg;
570 return StatusCode::FAILURE;
571 }
572
573 ON_DEBUG debug() << "Executing event " << eventContext->evt() << " on slot " << thisSlotNum << endmsg;
574 thisSlot.reset( eventContext );
575
576 // Result status code:
577 StatusCode result = StatusCode::SUCCESS;
578
579 // promote to CR and DR the initial set of algorithms
580 Cause cs = { Cause::source::Root, "RootDecisionHub" };
581 if ( m_precSvc->iterate( thisSlot, cs ).isFailure() ) {
582 error() << "Failed to call IPrecedenceSvc::iterate for slot " << thisSlotNum << endmsg;
583 result = StatusCode::FAILURE;
584 }
585
586 if ( this->iterate().isFailure() ) {
587 error() << "Failed to call AvalancheSchedulerSvc::updateStates for slot " << thisSlotNum << endmsg;
588 result = StatusCode::FAILURE;
589 }
590
591 return result;
592 }; // end of lambda
593
594 // Kick off scheduling
595 ON_VERBOSE {
596 verbose() << "Pushing the action to update the scheduler for slot " << eventContext->slot() << endmsg;
597 verbose() << "Free slots available " << m_freeSlots.load() << endmsg;
598 }
599
600 m_actionsQueue.push( action );
601
602 return StatusCode::SUCCESS;
603}
bool complete
Flags completion of the event.
Definition EventSlot.h:88
void reset(EventContext *theeventContext)
Reset all resources in order to reuse the slot (thread-unsafe).
Definition EventSlot.h:48

◆ pushNewEvents()

StatusCode AvalancheSchedulerSvc::pushNewEvents ( std::vector< EventContext * > & eventContexts)
override

Definition at line 607 of file AvalancheSchedulerSvc.cpp.

607 {
608 StatusCode sc;
609 for ( auto context : eventContexts ) {
610 sc = pushNewEvent( context );
611 if ( sc != StatusCode::SUCCESS ) return sc;
612 }
613 return sc;
614}
StatusCode pushNewEvent(EventContext *eventContext) override
Make an event available to the scheduler.

◆ recordOccupancy()

void AvalancheSchedulerSvc::recordOccupancy ( int samplePeriod,
std::function< void(OccupancySnapshot)> callback )
overridevirtual

Sample occupancy at fixed interval (ms) Negative value to deactivate, 0 to snapshot every change Each sample, apply the callback function to the result.

Definition at line 1158 of file AvalancheSchedulerSvc.cpp.

1158 {
1159
1160 auto action = [this, samplePeriod, callback = std::move( callback )]() -> StatusCode {
1161 if ( samplePeriod < 0 ) {
1162 this->m_snapshotInterval = std::chrono::duration<int64_t, std::milli>::min();
1163 } else {
1164 this->m_snapshotInterval = std::chrono::duration<int64_t, std::milli>( samplePeriod );
1165 m_snapshotCallback = std::move( callback );
1166 }
1167 return StatusCode::SUCCESS;
1168 };
1169
1170 m_actionsQueue.push( std::move( action ) );
1171}

◆ revise()

StatusCode AvalancheSchedulerSvc::revise ( unsigned int iAlgo,
EventContext * contextPtr,
AState state,
bool iterate = false )
private

Definition at line 803 of file AvalancheSchedulerSvc.cpp.

803 {
804 StatusCode sc;
805 auto slotIndex = contextPtr->slot();
806 EventSlot& slot = m_eventSlots[slotIndex];
807 Cause cs = { Cause::source::Task, index2algname( iAlgo ) };
808
809 if ( contextPtr->usesSubSlot() ) {
810 // Sub-slot
811 auto subSlotIndex = contextPtr->subSlot();
812 EventSlot& subSlot = slot.allSubSlots[subSlotIndex];
813
814 sc = subSlot.algsStates.set( iAlgo, state );
815
816 if ( sc.isSuccess() ) {
817 ON_VERBOSE verbose() << "Promoted " << index2algname( iAlgo ) << " to " << state << " [slot:" << slotIndex
818 << ", subslot:" << subSlotIndex << ", event:" << contextPtr->evt() << "]" << endmsg;
819 // Revise states of algorithms downstream the precedence graph
820 if ( iterate ) sc = m_precSvc->iterate( subSlot, cs );
821 }
822 } else {
823 // Event level (standard behaviour)
824 sc = slot.algsStates.set( iAlgo, state );
825
826 if ( sc.isSuccess() ) {
827 ON_VERBOSE verbose() << "Promoted " << index2algname( iAlgo ) << " to " << state << " [slot:" << slotIndex
828 << ", event:" << contextPtr->evt() << "]" << endmsg;
829 // Revise states of algorithms downstream the precedence graph
830 if ( iterate ) sc = m_precSvc->iterate( slot, cs );
831 }
832 }
833 return sc;
834}
StatusCode set(unsigned int iAlgo, State newState)
ContextID_t subSlot() const
bool usesSubSlot() const
bool isSuccess() const
Definition StatusCode.h:302
std::vector< EventSlot > allSubSlots
Actual sub-slot instances.
Definition EventSlot.h:99

◆ schedule()

StatusCode AvalancheSchedulerSvc::schedule ( TaskSpec && ts)
private

Definition at line 1025 of file AvalancheSchedulerSvc.cpp.

1025 {
1026
1027 // Check if a free Algorithm instance is available
1028 StatusCode getAlgSC( m_algResourcePool->acquireAlgorithm( ts.algName, ts.algPtr ) );
1029
1030 // If an instance is available, proceed to scheduling
1031 StatusCode sc;
1032 if ( getAlgSC.isSuccess() ) {
1033
1034 // Decide how to schedule the task and schedule it
1035 if ( -100 != m_threadPoolSize ) {
1036
1037 // Cache values before moving the TaskSpec further
1038 unsigned int algIndex{ ts.algIndex };
1039 std::string_view algName( ts.algName );
1040 unsigned int algRank{ ts.algRank };
1041 bool asynchronous{ ts.asynchronous };
1042 int slotIndex{ ts.slotIndex };
1043 EventContext* contextPtr{ ts.contextPtr };
1044
1045 if ( asynchronous ) {
1046 // Add to asynchronous scheduled queue
1047 m_scheduledAsynchronousQueue.push( std::move( ts ) );
1048
1049 // Schedule task
1050 m_fiberManager->schedule( AlgTask( this, serviceLocator(), m_algExecStateSvc, asynchronous ) );
1051 }
1052
1053 if ( !asynchronous ) {
1054 // Add the algorithm to the scheduled queue
1055 m_scheduledQueue.push( std::move( ts ) );
1056
1057 // Prepare a TBB task that will execute the Algorithm according to the above queued specs
1058 m_arena->enqueue( AlgTask( this, serviceLocator(), m_algExecStateSvc, asynchronous ) );
1060 }
1061 sc = revise( algIndex, contextPtr, AState::SCHEDULED );
1062
1063 ON_DEBUG debug() << "Scheduled " << algName << " [slot:" << slotIndex << ", event:" << contextPtr->evt()
1064 << ", rank:" << algRank << ", asynchronous:" << ( asynchronous ? "yes" : "no" )
1065 << "]. Scheduled algorithms: " << m_algosInFlight << endmsg;
1066
1067 } else { // Avoid scheduling via TBB if the pool size is -100. Instead, run here in the scheduler's control thread
1068 // Beojan: I don't think this bit works. ts hasn't been pushed into any queue so AlgTask won't retrieve it
1070 sc = revise( ts.algIndex, ts.contextPtr, AState::SCHEDULED );
1071 AlgTask( this, serviceLocator(), m_algExecStateSvc, ts.asynchronous )();
1073 }
1074 } else { // if no Algorithm instance available, retry later
1075
1076 sc = revise( ts.algIndex, ts.contextPtr, AState::RESOURCELESS );
1077 // Add the algorithm to the retry queue
1078 m_retryQueue.push( std::move( ts ) );
1079 }
1080
1082
1083 return sc;
1084}
StatusCode revise(unsigned int iAlgo, EventContext *contextPtr, AState state, bool iterate=false)
unsigned int m_algosInFlight
Number of algorithms presently in flight.

◆ scheduleEventView()

StatusCode AvalancheSchedulerSvc::scheduleEventView ( const EventContext * sourceContext,
const std::string & nodeName,
std::unique_ptr< EventContext > viewContext )
overridevirtual

Method to inform the scheduler about event views.

Definition at line 1118 of file AvalancheSchedulerSvc.cpp.

1119 {
1120 // Prevent view nesting
1121 if ( sourceContext->usesSubSlot() ) {
1122 fatal() << "Attempted to nest EventViews at node " << nodeName << ": this is not supported" << endmsg;
1123 return StatusCode::FAILURE;
1124 }
1125
1126 ON_VERBOSE verbose() << "Queuing a view for [" << viewContext.get() << "]" << endmsg;
1127
1128 // It's not possible to create an std::functional from a move-capturing lambda
1129 // So, we have to release the unique pointer
1130 auto action = [this, slotIndex = sourceContext->slot(), viewContextPtr = viewContext.release(),
1131 &nodeName]() -> StatusCode {
1132 // Attach the sub-slot to the top-level slot
1133 EventSlot& topSlot = this->m_eventSlots[slotIndex];
1134
1135 if ( viewContextPtr ) {
1136 // Re-create the unique pointer
1137 auto viewContext = std::unique_ptr<EventContext>( viewContextPtr );
1138 topSlot.addSubSlot( std::move( viewContext ), nodeName );
1139 return StatusCode::SUCCESS;
1140 } else {
1141 // Disable the view node if there are no views
1142 topSlot.disableSubSlots( nodeName );
1143 return StatusCode::SUCCESS;
1144 }
1145 };
1146
1147 m_actionsQueue.push( std::move( action ) );
1148
1149 return StatusCode::SUCCESS;
1150}
void addSubSlot(std::unique_ptr< EventContext > viewContext, const std::string &nodeName)
Add a subslot to the slot (this constructs a new slot and registers it with the parent one).
Definition EventSlot.h:60
void disableSubSlots(const std::string &nodeName)
Disable event views for a given CF view node by registering an empty container Contact B.
Definition EventSlot.h:77

◆ signoff()

StatusCode AvalancheSchedulerSvc::signoff ( const TaskSpec & ts)
private

The call to this method is triggered only from within the AlgTask.

Definition at line 1091 of file AvalancheSchedulerSvc.cpp.

1091 {
1092
1093 Gaudi::Hive::setCurrentContext( ts.contextPtr );
1094
1096
1097 const AlgExecStateRef algstate = m_algExecStateSvc->algExecState( ts.algPtr, *( ts.contextPtr ) );
1098 AState state = algstate.execStatus().isSuccess()
1099 ? ( algstate.filterPassed() ? AState::EVTACCEPTED : AState::EVTREJECTED )
1100 : AState::ERROR;
1101
1102 // Update algorithm state and revise the downstream states
1103 auto sc = revise( ts.algIndex, ts.contextPtr, state, true );
1104
1105 ON_DEBUG debug() << "Executed " << ts.algName << " [slot:" << ts.slotIndex << ", event:" << ts.contextPtr->evt()
1106 << ", rank:" << ts.algRank << ", asynchronous:" << ( ts.asynchronous ? "yes" : "no" )
1107 << "]. Scheduled algorithms: " << m_algosInFlight << endmsg;
1108
1109 // Prompt a call to updateStates
1110 m_needsUpdate.store( true );
1111 return sc;
1112}
const StatusCode & execStatus() const
bool filterPassed() const
GAUDI_API void setCurrentContext(const EventContext *ctx)

◆ tryPopFinishedEvent()

StatusCode AvalancheSchedulerSvc::tryPopFinishedEvent ( EventContext *& eventContext)
override

Try to fetch an event from the scheduler.

Try to get a finished event, if not available just return a failure.

Definition at line 649 of file AvalancheSchedulerSvc.cpp.

649 {
650
651 if ( m_finishedEvents.try_pop( eventContext ) ) {
652 ON_DEBUG debug() << "Try Pop successful slot " << eventContext->slot() << "(event " << eventContext->evt() << ")"
653 << endmsg;
654 ++m_freeSlots;
655 return StatusCode::SUCCESS;
656 }
657 return StatusCode::FAILURE;
658}

◆ AlgTask

friend class AlgTask
friend

Definition at line 116 of file AvalancheSchedulerSvc.h.

Member Data Documentation

◆ m_actionsQueue

tbb::concurrent_bounded_queue<action> AvalancheSchedulerSvc::m_actionsQueue
private

Queue where closures are stored and picked for execution.

Definition at line 311 of file AvalancheSchedulerSvc.h.

◆ m_algExecStateSvc

SmartIF<IAlgExecStateSvc> AvalancheSchedulerSvc::m_algExecStateSvc
private

Algorithm execution state manager.

Definition at line 274 of file AvalancheSchedulerSvc.h.

◆ m_algname_index_map

std::unordered_map<std::string, unsigned int> AvalancheSchedulerSvc::m_algname_index_map
private

Map to bookkeep the information necessary to the name2index conversion.

Definition at line 250 of file AvalancheSchedulerSvc.h.

◆ m_algname_vect

std::vector<std::string> AvalancheSchedulerSvc::m_algname_vect
private

Vector to bookkeep the information necessary to the index2name conversion.

Definition at line 256 of file AvalancheSchedulerSvc.h.

◆ m_algosInFlight

unsigned int AvalancheSchedulerSvc::m_algosInFlight = 0
private

Number of algorithms presently in flight.

Definition at line 280 of file AvalancheSchedulerSvc.h.

◆ m_algResourcePool

SmartIF<IAlgResourcePool> AvalancheSchedulerSvc::m_algResourcePool
private

Cache for the algorithm resource pool.

Definition at line 306 of file AvalancheSchedulerSvc.h.

◆ m_arena

tbb::task_arena* AvalancheSchedulerSvc::m_arena { nullptr }
private

Definition at line 361 of file AvalancheSchedulerSvc.h.

361{ nullptr };

◆ m_checkDeps

Gaudi::Property<bool> AvalancheSchedulerSvc::m_checkDeps
private
Initial value:
{ this, "CheckDependencies", false,
"Runtime check of Algorithm Input Data Dependencies" }

Definition at line 191 of file AvalancheSchedulerSvc.h.

191 { this, "CheckDependencies", false,
192 "Runtime check of Algorithm Input Data Dependencies" };

◆ m_checkOutput

Gaudi::Property<bool> AvalancheSchedulerSvc::m_checkOutput
private
Initial value:
{ this, "CheckOutputUsage", false,
"Runtime check of Algorithm Output Data usage" }

Definition at line 193 of file AvalancheSchedulerSvc.h.

193 { this, "CheckOutputUsage", false,
194 "Runtime check of Algorithm Output Data usage" };

◆ m_checkOutputIgnoreList

Gaudi::Property<std::vector<std::string> > AvalancheSchedulerSvc::m_checkOutputIgnoreList
private
Initial value:
{
this,
"CheckOutputUsageIgnoreList",
{},
"Ignore outputs of the Algorithms of this name when doing the check",
"OrderedSet<std::string>" }

Definition at line 195 of file AvalancheSchedulerSvc.h.

195 {
196 this,
197 "CheckOutputUsageIgnoreList",
198 {},
199 "Ignore outputs of the Algorithms of this name when doing the check",
200 "OrderedSet<std::string>" };

◆ m_condSvc

SmartIF<ICondSvc> AvalancheSchedulerSvc::m_condSvc
private

A shortcut to service for Conditions handling.

Definition at line 277 of file AvalancheSchedulerSvc.h.

◆ m_dataDepsGraphAlgoPattern

Gaudi::Property<std::string> AvalancheSchedulerSvc::m_dataDepsGraphAlgoPattern
private
Initial value:
{
this, "DataDepsGraphAlgPattern", ".*",
"Regex pattern for selecting desired Algorithms by name, whose data dependency has to be included in the data "
"deps graph" }

Definition at line 223 of file AvalancheSchedulerSvc.h.

223 {
224 this, "DataDepsGraphAlgPattern", ".*",
225 "Regex pattern for selecting desired Algorithms by name, whose data dependency has to be included in the data "
226 "deps graph" };

◆ m_dataDepsGraphFile

Gaudi::Property<std::string> AvalancheSchedulerSvc::m_dataDepsGraphFile
private
Initial value:
{
this, "DataDepsGraphFile", "",
"Name of the output file (.dot, .md or .graphml extensions allowed) containing the data dependency graph "
"for some selected Algorithms" }

Definition at line 218 of file AvalancheSchedulerSvc.h.

218 {
219 this, "DataDepsGraphFile", "",
220 "Name of the output file (.dot, .md or .graphml extensions allowed) containing the data dependency graph "
221 "for some selected Algorithms" };

◆ m_dataDepsGraphObjectPattern

Gaudi::Property<std::string> AvalancheSchedulerSvc::m_dataDepsGraphObjectPattern
private
Initial value:
{
this, "DataDepsGraphObjectPattern", ".*",
"Regex pattern for selecting desired input or output by their full key" }

Definition at line 228 of file AvalancheSchedulerSvc.h.

228 {
229 this, "DataDepsGraphObjectPattern", ".*",
230 "Regex pattern for selecting desired input or output by their full key" };

◆ m_dumpIntraEventDynamics

Gaudi::Property<bool> AvalancheSchedulerSvc::m_dumpIntraEventDynamics
private
Initial value:
{ this, "DumpIntraEventDynamics", false,
"Dump intra-event concurrency dynamics to csv file" }

Definition at line 185 of file AvalancheSchedulerSvc.h.

185 { this, "DumpIntraEventDynamics", false,
186 "Dump intra-event concurrency dynamics to csv file" };

◆ m_enableCondSvc

Gaudi::Property<bool> AvalancheSchedulerSvc::m_enableCondSvc { this, "EnableConditions", false, "Enable ConditionsSvc" }
private

Definition at line 205 of file AvalancheSchedulerSvc.h.

205{ this, "EnableConditions", false, "Enable ConditionsSvc" };

◆ m_eventSlots

std::vector<EventSlot> AvalancheSchedulerSvc::m_eventSlots
private

Vector of events slots.

Definition at line 265 of file AvalancheSchedulerSvc.h.

◆ m_fiberManager

std::unique_ptr<FiberManager> AvalancheSchedulerSvc::m_fiberManager { nullptr }
private

Definition at line 362 of file AvalancheSchedulerSvc.h.

362{ nullptr };

◆ m_finishedEvents

tbb::concurrent_bounded_queue<EventContext*> AvalancheSchedulerSvc::m_finishedEvents
private

Queue of finished events.

Definition at line 271 of file AvalancheSchedulerSvc.h.

◆ m_freeSlots

std::atomic_int AvalancheSchedulerSvc::m_freeSlots { 0 }
private

Atomic to account for asyncronous updates by the scheduler wrt the rest.

Definition at line 268 of file AvalancheSchedulerSvc.h.

268{ 0 };

◆ m_isActive

std::atomic<ActivationState> AvalancheSchedulerSvc::m_isActive { INACTIVE }
private

Flag to track if the scheduler is active or not.

Definition at line 241 of file AvalancheSchedulerSvc.h.

241{ INACTIVE };

◆ m_lastSnapshot

std::chrono::system_clock::time_point AvalancheSchedulerSvc::m_lastSnapshot = std::chrono::system_clock::now()
private

Definition at line 167 of file AvalancheSchedulerSvc.h.

◆ m_maxEventsInFlight

size_t AvalancheSchedulerSvc::m_maxEventsInFlight { 0 }
private

Definition at line 364 of file AvalancheSchedulerSvc.h.

364{ 0 };

◆ m_maxParallelismExtra

Gaudi::Property<int> AvalancheSchedulerSvc::m_maxParallelismExtra
private
Initial value:
{
this, "maxParallelismExtra", 0,
"Allows to add some extra threads to the maximum parallelism set in TBB"
"The TBB max parallelism is set as: ThreadPoolSize + maxParallelismExtra + 1" }

Definition at line 175 of file AvalancheSchedulerSvc.h.

175 {
176 this, "maxParallelismExtra", 0,
177 "Allows to add some extra threads to the maximum parallelism set in TBB"
178 "The TBB max parallelism is set as: ThreadPoolSize + maxParallelismExtra + 1" };

◆ m_needsUpdate

std::atomic<bool> AvalancheSchedulerSvc::m_needsUpdate { true }
private

Definition at line 355 of file AvalancheSchedulerSvc.h.

355{ true };

◆ m_numOffloadThreads

Gaudi::Property<int> AvalancheSchedulerSvc::m_numOffloadThreads
private
Initial value:
{
this, "NumOffloadThreads", 0,
"Number of threads to use for CPU portion of asynchronous algorithms. Asynchronous algorithms must be flagged "
"and use Boost Fiber functionality to suspend while waiting for offloaded work." }

Definition at line 187 of file AvalancheSchedulerSvc.h.

187 {
188 this, "NumOffloadThreads", 0,
189 "Number of threads to use for CPU portion of asynchronous algorithms. Asynchronous algorithms must be flagged "
190 "and use Boost Fiber functionality to suspend while waiting for offloaded work." };

◆ m_optimizationMode

Gaudi::Property<std::string> AvalancheSchedulerSvc::m_optimizationMode
private
Initial value:
{ this, "Optimizer", "",
"The following modes are currently available: PCE, COD, DRE, E" }

Definition at line 183 of file AvalancheSchedulerSvc.h.

183 { this, "Optimizer", "",
184 "The following modes are currently available: PCE, COD, DRE, E" };

◆ m_precSvc

SmartIF<IPrecedenceSvc> AvalancheSchedulerSvc::m_precSvc
private

A shortcut to the Precedence Service.

Definition at line 259 of file AvalancheSchedulerSvc.h.

◆ m_retryQueue

std::queue<TaskSpec> AvalancheSchedulerSvc::m_retryQueue
private

Definition at line 352 of file AvalancheSchedulerSvc.h.

◆ m_scheduledAsynchronousQueue

tbb::concurrent_priority_queue<TaskSpec, AlgQueueSort> AvalancheSchedulerSvc::m_scheduledAsynchronousQueue
private

Definition at line 351 of file AvalancheSchedulerSvc.h.

◆ m_scheduledQueue

tbb::concurrent_priority_queue<TaskSpec, AlgQueueSort> AvalancheSchedulerSvc::m_scheduledQueue
private

Queues for scheduled algorithms.

Definition at line 350 of file AvalancheSchedulerSvc.h.

◆ m_showControlFlow

Gaudi::Property<bool> AvalancheSchedulerSvc::m_showControlFlow
private
Initial value:
{ this, "ShowControlFlow", false,
"Show the configuration of all Algorithms and Sequences" }

Definition at line 213 of file AvalancheSchedulerSvc.h.

213 { this, "ShowControlFlow", false,
214 "Show the configuration of all Algorithms and Sequences" };

◆ m_showDataDeps

Gaudi::Property<bool> AvalancheSchedulerSvc::m_showDataDeps
private
Initial value:
{ this, "ShowDataDependencies", true,
"Show the INPUT and OUTPUT data dependencies of Algorithms" }

Definition at line 207 of file AvalancheSchedulerSvc.h.

207 { this, "ShowDataDependencies", true,
208 "Show the INPUT and OUTPUT data dependencies of Algorithms" };

◆ m_showDataFlow

Gaudi::Property<bool> AvalancheSchedulerSvc::m_showDataFlow
private
Initial value:
{ this, "ShowDataFlow", false,
"Show the configuration of DataFlow between Algorithms" }

Definition at line 210 of file AvalancheSchedulerSvc.h.

210 { this, "ShowDataFlow", false,
211 "Show the configuration of DataFlow between Algorithms" };

◆ m_simulateExecution

Gaudi::Property<bool> AvalancheSchedulerSvc::m_simulateExecution
private
Initial value:
{
this, "SimulateExecution", false,
"Flag to perform single-pass simulation of execution flow before the actual execution" }

Definition at line 180 of file AvalancheSchedulerSvc.h.

180 {
181 this, "SimulateExecution", false,
182 "Flag to perform single-pass simulation of execution flow before the actual execution" };

◆ m_snapshotCallback

std::function<void( OccupancySnapshot )> AvalancheSchedulerSvc::m_snapshotCallback
private

Definition at line 168 of file AvalancheSchedulerSvc.h.

◆ m_snapshotInterval

std::chrono::duration<int64_t, std::milli> AvalancheSchedulerSvc::m_snapshotInterval = std::chrono::duration<int64_t, std::milli>::min()
private

Definition at line 166 of file AvalancheSchedulerSvc.h.

◆ m_thread

std::thread AvalancheSchedulerSvc::m_thread
private

The thread in which the activate function runs.

Definition at line 244 of file AvalancheSchedulerSvc.h.

◆ m_threadPoolSize

Gaudi::Property<int> AvalancheSchedulerSvc::m_threadPoolSize
private
Initial value:
{
this, "ThreadPoolSize", -1,
"Size of the global thread pool initialised by TBB; a value of -1 requests to use"
"all available hardware threads; -100 requests to bypass TBB executing "
"all algorithms in the scheduler's thread." }

Definition at line 170 of file AvalancheSchedulerSvc.h.

170 {
171 this, "ThreadPoolSize", -1,
172 "Size of the global thread pool initialised by TBB; a value of -1 requests to use"
173 "all available hardware threads; -100 requests to bypass TBB executing "
174 "all algorithms in the scheduler's thread." };

◆ m_threadPoolSvc

SmartIF<IThreadPoolSvc> AvalancheSchedulerSvc::m_threadPoolSvc
private

Definition at line 360 of file AvalancheSchedulerSvc.h.

◆ m_useDataLoader

Gaudi::Property<std::string> AvalancheSchedulerSvc::m_useDataLoader
private
Initial value:
{ this, "DataLoaderAlg", "",
"Attribute unmet input dependencies to this DataLoader Algorithm" }

Definition at line 202 of file AvalancheSchedulerSvc.h.

202 { this, "DataLoaderAlg", "",
203 "Attribute unmet input dependencies to this DataLoader Algorithm" };

◆ m_verboseSubSlots

Gaudi::Property<bool> AvalancheSchedulerSvc::m_verboseSubSlots { this, "VerboseSubSlots", false, "Dump algorithm states for all sub-slots" }
private

Definition at line 216 of file AvalancheSchedulerSvc.h.

216{ this, "VerboseSubSlots", false, "Dump algorithm states for all sub-slots" };

◆ m_whiteboard

SmartIF<IHiveWhiteBoard> AvalancheSchedulerSvc::m_whiteboard
private

A shortcut to the whiteboard.

Definition at line 262 of file AvalancheSchedulerSvc.h.

◆ m_whiteboardSvcName

Gaudi::Property<std::string> AvalancheSchedulerSvc::m_whiteboardSvcName { this, "WhiteboardSvc", "EventDataSvc", "The whiteboard name" }
private

Definition at line 179 of file AvalancheSchedulerSvc.h.

179{ this, "WhiteboardSvc", "EventDataSvc", "The whiteboard name" };

The documentation for this class was generated from the following files: