Commit b601c494 authored by Marco Clemencic's avatar Marco Clemencic
Browse files

EventView isolation fix, and added testing (mr !540)

parents b8e23989 2116b84f
#!/usr/bin/env gaudirun.py
'''
A test for basic functionality of sub-event scheduling.
Algorithms A2 and A3 should run twice per event, in sub-event contexts.
The ViewTester is an algorithm specifically designed to create sub-event
contexts, pass them to the scheduler, and report on the current context.
Four instances of ViewTester are used as follows:
- Algorithm A1 creates two sub-event contexts
- Algorithms A2 and A3 run within the sub-event contexts
- Algorithm A4 runs in the whole event context, after the sub-events
'''
from Gaudi.Configuration import *
from Configurables import (HiveWhiteBoard, HiveSlimEventLoopMgr,
AvalancheSchedulerSvc, AlgResourcePool,
CPUCruncher, GaudiSequencer, Test__ViewTester)
# metaconfig -------------------------------------------------------------------
# It's confortable to collect the relevant parameters at the top of the optionfile
evtslots = 1
evtMax = 10
cardinality = 1
threads = 1
viewsPerEvt = 2
#-------------------------------------------------------------------------------
# The configuration of the whiteboard ------------------------------------------
# It is useful to call it EventDataSvc to replace the usual data service with
# the whiteboard transparently.
whiteboard = HiveWhiteBoard("EventDataSvc", EventSlots=evtslots)
#-------------------------------------------------------------------------------
# Event Loop Manager -----------------------------------------------------------
# It's called slim since it has less functionalities overall than the good-old
# event loop manager. Here we just set its outputlevel to DEBUG.
slimeventloopmgr = HiveSlimEventLoopMgr(
SchedulerName="AvalancheSchedulerSvc", OutputLevel=INFO)
#-------------------------------------------------------------------------------
# ForwardScheduler -------------------------------------------------------------
# We just decide how many algorithms in flight we want to have and how many
# threads in the pool. The default value is -1, which is for TBB equivalent
# to take over the whole machine.
scheduler = AvalancheSchedulerSvc(ThreadPoolSize=threads, OutputLevel=INFO)
#-------------------------------------------------------------------------------
# Algo Resource Pool -----------------------------------------------------------
# Nothing special here, we just set the debug level.
AlgResourcePool(OutputLevel=INFO)
#-------------------------------------------------------------------------------
# Set up of the crunchers, daily business --------------------------------------
a1 = Test__ViewTester("A1")
a1.baseViewName = 'view'
a1.viewNumber = viewsPerEvt
a1.viewNodeName = 'viewNode'
a2 = Test__ViewTester("A2")
a2.viewNodeName = ''
a3 = Test__ViewTester("A3")
a3.viewNodeName = ''
a4 = Test__ViewTester("A4")
a4.viewNodeName = ''
for algo in [a1, a2, a3, a4]:
algo.Cardinality = cardinality
algo.OutputLevel = INFO
viewNode = GaudiSequencer("viewNode",
Members=[a2, a3],
Sequential=False,
OutputLevel=INFO)
createViewSeq = GaudiSequencer("createViewSeq",
Members=[a1, viewNode, a4],
Sequential=True,
OutputLevel=INFO)
# Application Manager ----------------------------------------------------------
# We put everything together and change the type of message service
ApplicationMgr(EvtMax=evtMax,
EvtSel='NONE',
ExtSvc=[whiteboard],
EventLoop=slimeventloopmgr,
TopAlg=[createViewSeq],
MessageSvcType="InertMessageSvc")
#-------------------------------------------------------------------------------
#!/usr/bin/env gaudirun.py
'''
A test for control flow scheduling within sub-event contexts.
The sub-event control flow node has a child node attached.
The ViewTester is an algorithm specifically designed to create sub-event
contexts, pass them to the scheduler, and report on the current context.
Six instances of ViewTester are used as follows:
- Algorithm A1 creates two sub-event contexts
- Algorithms A2 and A3 run within the sub-event contexts
- Algorithms B1 and B2 run within the sub-event contexts,
on a child control flow node
- Algorithm A4 runs in the whole event context, after the sub-events
'''
from Gaudi.Configuration import *
from Configurables import (HiveWhiteBoard, HiveSlimEventLoopMgr,
AvalancheSchedulerSvc, AlgResourcePool,
CPUCruncher, GaudiSequencer, Test__ViewTester)
# metaconfig -------------------------------------------------------------------
# It's confortable to collect the relevant parameters at the top of the optionfile
evtslots = 1
evtMax = 10
cardinality = 1
threads = 1
viewsPerEvt = 2
#-------------------------------------------------------------------------------
# The configuration of the whiteboard ------------------------------------------
# It is useful to call it EventDataSvc to replace the usual data service with
# the whiteboard transparently.
whiteboard = HiveWhiteBoard("EventDataSvc", EventSlots=evtslots)
#-------------------------------------------------------------------------------
# Event Loop Manager -----------------------------------------------------------
# It's called slim since it has less functionalities overall than the good-old
# event loop manager. Here we just set its outputlevel to DEBUG.
slimeventloopmgr = HiveSlimEventLoopMgr(
SchedulerName="AvalancheSchedulerSvc", OutputLevel=DEBUG)
#-------------------------------------------------------------------------------
# ForwardScheduler -------------------------------------------------------------
# We just decide how many algorithms in flight we want to have and how many
# threads in the pool. The default value is -1, which is for TBB equivalent
# to take over the whole machine.
scheduler = AvalancheSchedulerSvc(ThreadPoolSize=threads, OutputLevel=INFO)
#-------------------------------------------------------------------------------
# Algo Resource Pool -----------------------------------------------------------
# Nothing special here, we just set the debug level.
AlgResourcePool(OutputLevel=DEBUG)
#-------------------------------------------------------------------------------
# Set up of the crunchers, daily business --------------------------------------
a1 = Test__ViewTester("A1")
a1.baseViewName = 'view'
a1.viewNumber = viewsPerEvt
a1.viewNodeName = 'viewNode'
a2 = Test__ViewTester("A2")
a2.viewNodeName = ''
a3 = Test__ViewTester("A3")
a3.viewNodeName = ''
a4 = Test__ViewTester("A4")
a4.viewNodeName = ''
b1 = Test__ViewTester("B1")
b1.viewNodeName = ''
b2 = Test__ViewTester("B2")
b2.viewNodeName = ''
for algo in [a1, a2, a3, a4, b1, b2]:
algo.Cardinality = cardinality
algo.OutputLevel = DEBUG
nodeInView = GaudiSequencer("nodeInView",
Members=[b1, b2],
Sequential=False,
OutputLevel=VERBOSE)
viewNode = GaudiSequencer("viewNode",
Members=[a2, nodeInView, a3],
Sequential=False,
OutputLevel=VERBOSE)
createViewSeq = GaudiSequencer("createViewSeq",
Members=[a1, viewNode, a4],
Sequential=True,
OutputLevel=VERBOSE)
# Application Manager ----------------------------------------------------------
# We put everything together and change the type of message service
ApplicationMgr(EvtMax=evtMax,
EvtSel='NONE',
ExtSvc=[whiteboard],
EventLoop=slimeventloopmgr,
TopAlg=[createViewSeq],
MessageSvcType="InertMessageSvc")
#-------------------------------------------------------------------------------
#!/usr/bin/env gaudirun.py
'''
A test for issue 13 in gitlab.
Two different sets of sub-event contexts are created, and the
same algorithms (attached to a common control flow node) run in each
The ViewTester is an algorithm specifically designed to create sub-event
contexts, pass them to the scheduler, and report on the current context.
Five instances of ViewTester are used as follows:
- Algorithm A1 creates two sub-event contexts
- Algorithms A2 and A3 run within the sub-event contexts
- Algorithm A4 creates two more sub-event contexts
- Algorithms A2 and A3 run again, in the new contexts
- Algorithm A5 runs in the whole event context, after the sub-events
'''
from Gaudi.Configuration import *
from Configurables import (HiveWhiteBoard, HiveSlimEventLoopMgr,
AvalancheSchedulerSvc, AlgResourcePool,
CPUCruncher, GaudiSequencer, Test__ViewTester)
# metaconfig -------------------------------------------------------------------
# It's confortable to collect the relevant parameters at the top of the optionfile
evtslots = 1
evtMax = 10
cardinality = 1
threads = 1
viewsPerEvt = 2
#-------------------------------------------------------------------------------
# The configuration of the whiteboard ------------------------------------------
# It is useful to call it EventDataSvc to replace the usual data service with
# the whiteboard transparently.
whiteboard = HiveWhiteBoard("EventDataSvc", EventSlots=evtslots)
#-------------------------------------------------------------------------------
# Event Loop Manager -----------------------------------------------------------
# It's called slim since it has less functionalities overall than the good-old
# event loop manager. Here we just set its outputlevel to DEBUG.
slimeventloopmgr = HiveSlimEventLoopMgr(
SchedulerName="AvalancheSchedulerSvc", OutputLevel=INFO)
#-------------------------------------------------------------------------------
# ForwardScheduler -------------------------------------------------------------
# We just decide how many algorithms in flight we want to have and how many
# threads in the pool. The default value is -1, which is for TBB equivalent
# to take over the whole machine.
scheduler = AvalancheSchedulerSvc(ThreadPoolSize=threads, OutputLevel=INFO)
#-------------------------------------------------------------------------------
# Algo Resource Pool -----------------------------------------------------------
# Nothing special here, we just set the debug level.
AlgResourcePool(OutputLevel=INFO)
#-------------------------------------------------------------------------------
# Set up of the crunchers, daily business --------------------------------------
a1 = Test__ViewTester("A1")
a1.baseViewName = 'viewOne'
a1.viewNumber = viewsPerEvt
a1.viewNodeName = 'viewNodeOne'
a2 = Test__ViewTester("A2")
a2.viewNodeName = ''
a3 = Test__ViewTester("A3")
a3.viewNodeName = ''
a4 = Test__ViewTester("A4")
a4.baseViewName = 'viewTwo'
a4.viewNumber = viewsPerEvt
a4.viewNodeName = 'viewNodeTwo'
a5 = Test__ViewTester("A5")
a5.viewNodeName = ''
for algo in [a1, a2, a3, a4, a5]:
algo.Cardinality = cardinality
algo.OutputLevel = INFO
extraNode = GaudiSequencer("extraNode",
Members=[a2, a3],
Sequential=True,
OutputLevel=INFO)
viewNodeOne = GaudiSequencer("viewNodeOne",
Members=[extraNode],
Sequential=False,
OutputLevel=INFO)
viewNodeTwo = GaudiSequencer("viewNodeTwo",
Members=[extraNode],
Sequential=False,
OutputLevel=INFO)
createViewSeq = GaudiSequencer("createViewSeq",
Members=[a1, viewNodeOne, a4, viewNodeTwo, a5],
Sequential=True,
OutputLevel=INFO)
# Application Manager ----------------------------------------------------------
# We put everything together and change the type of message service
ApplicationMgr(EvtMax=evtMax,
EvtSel='NONE',
ExtSvc=[whiteboard],
EventLoop=slimeventloopmgr,
TopAlg=[createViewSeq],
MessageSvcType="InertMessageSvc")
#-------------------------------------------------------------------------------
#!/usr/bin/env gaudirun.py
'''
A test for scheduling multiple sub-event contexts.
The main sequence has two steps of creating and running sub-events.
The ViewTester is an algorithm specifically designed to create sub-event
contexts, pass them to the scheduler, and report on the current context.
Seven instances of ViewTester are used as follows:
- Algorithm A1 creates two sub-event contexts
- Algorithms A2 and A3 run within the sub-event contexts
- Algorithm A4 creates two more sub-event contexts
- Algorithms A5 and A6 run within the new sub-event contexts
- Algorithm A7 runs in the whole event context, after the sub-events
'''
from Gaudi.Configuration import *
from Configurables import (HiveWhiteBoard, HiveSlimEventLoopMgr,
AvalancheSchedulerSvc, AlgResourcePool,
CPUCruncher, GaudiSequencer, Test__ViewTester)
# metaconfig -------------------------------------------------------------------
# It's confortable to collect the relevant parameters at the top of the optionfile
evtslots = 1
evtMax = 10
cardinality = 1
threads = 1
viewsPerEvt = 2
#-------------------------------------------------------------------------------
# The configuration of the whiteboard ------------------------------------------
# It is useful to call it EventDataSvc to replace the usual data service with
# the whiteboard transparently.
whiteboard = HiveWhiteBoard("EventDataSvc", EventSlots=evtslots)
#-------------------------------------------------------------------------------
# Event Loop Manager -----------------------------------------------------------
# It's called slim since it has less functionalities overall than the good-old
# event loop manager. Here we just set its outputlevel to DEBUG.
slimeventloopmgr = HiveSlimEventLoopMgr(
SchedulerName="AvalancheSchedulerSvc", OutputLevel=DEBUG)
#-------------------------------------------------------------------------------
# ForwardScheduler -------------------------------------------------------------
# We just decide how many algorithms in flight we want to have and how many
# threads in the pool. The default value is -1, which is for TBB equivalent
# to take over the whole machine.
scheduler = AvalancheSchedulerSvc(ThreadPoolSize=threads, OutputLevel=INFO)
#-------------------------------------------------------------------------------
# Algo Resource Pool -----------------------------------------------------------
# Nothing special here, we just set the debug level.
AlgResourcePool(OutputLevel=DEBUG)
#-------------------------------------------------------------------------------
# Set up of the crunchers, daily business --------------------------------------
a1 = Test__ViewTester("A1")
a1.baseViewName = 'viewOne'
a1.viewNumber = viewsPerEvt
a1.viewNodeName = 'viewNodeOne'
a2 = Test__ViewTester("A2")
a2.viewNodeName = ''
a3 = Test__ViewTester("A3")
a3.viewNodeName = ''
a4 = Test__ViewTester("A4")
a4.baseViewName = 'viewTwo'
a4.viewNumber = viewsPerEvt
a4.viewNodeName = 'viewNodeTwo'
a5 = Test__ViewTester("A5")
a5.viewNodeName = ''
a6 = Test__ViewTester("A6")
a6.viewNodeName = ''
a7 = Test__ViewTester("A7")
a7.viewNodeName = ''
for algo in [a1, a2, a3, a4, a5, a6, a7]:
algo.Cardinality = cardinality
algo.OutputLevel = DEBUG
viewNodeOne = GaudiSequencer("viewNodeOne",
Members=[a2, a3],
Sequential=False,
OutputLevel=VERBOSE)
viewNodeTwo = GaudiSequencer("viewNodeTwo",
Members=[a5, a6],
Sequential=False,
OutputLevel=VERBOSE)
createViewSeq = GaudiSequencer("createViewSeq",
Members=[a1, viewNodeOne, a4, viewNodeTwo, a7],
Sequential=True,
OutputLevel=VERBOSE)
# Application Manager ----------------------------------------------------------
# We put everything together and change the type of message service
ApplicationMgr(EvtMax=evtMax,
EvtSel='NONE',
ExtSvc=[whiteboard],
EventLoop=slimeventloopmgr,
TopAlg=[createViewSeq],
MessageSvcType="InertMessageSvc")
#-------------------------------------------------------------------------------
......@@ -4,6 +4,8 @@
#include "GaudiKernel/DataObjID.h"
#include "GaudiKernel/ICondSvc.h"
#include <queue>
namespace concurrency
{
......@@ -144,6 +146,36 @@ namespace concurrency
//---------------------------------------------------------------------------
bool Supervisor::visitEnter( DecisionNode& node ) const
{
// Protect against graph traversal escaping from sub-slots
if ( m_slot->parentSlot ) {
// Examine the ancestry of this node, looking for sub-slot entry point
bool canFindExit = false;
std::queue<DecisionNode*> allAncestors;
allAncestors.push( &node );
while ( allAncestors.size() ) {
DecisionNode* thisAncestor = allAncestors.front();
allAncestors.pop();
if ( thisAncestor->getNodeName() == m_slot->entryPoint ) {
// This ancestor is the sub-slot exit
canFindExit = true;
break;
} else {
// Go further up the node ancestry
for ( auto& evenOlder : thisAncestor->m_parents ) {
allAncestors.push( evenOlder );
}
}
}
// If the sub-slot entry point is not in this node's ancestry, don't visit the node
if ( !canFindExit ) return false;
}
if ( m_slot->controlFlowState[node.getNodeIndex()] != -1 ) return false;
return true;
......@@ -158,8 +190,12 @@ namespace concurrency
bool foundPositiveChild = false;
int decision = -1;
// If currently in a sub-slot, leave it if you've got to the exit
if ( m_slot->parentSlot && m_slot->entryPoint == node.getNodeName() ) m_slot = m_slot->parentSlot;
// Leave a sub-slot if this is the exit node
EventSlot* oldSlot = nullptr;
if ( m_slot->parentSlot && m_slot->entryPoint == node.getNodeName() ) {
oldSlot = m_slot;
m_slot = m_slot->parentSlot;
}
// If children are in sub-slots, loop over all
auto searchResult = m_slot->subSlotsByNode.find( node.getNodeName() );
......@@ -251,6 +287,13 @@ namespace concurrency
if ( decision != -1 ) {
m_slot->controlFlowState[node.getNodeIndex()] = decision;
// if a decision was made for this node, propagate the result upwards
for ( auto parent : node.m_parents ) {
parent->accept( *this );
}
if ( oldSlot ) m_slot = oldSlot;
return true;
}
......@@ -279,6 +322,7 @@ namespace concurrency
}
}
if ( oldSlot ) m_slot = oldSlot;
return false;
}
......@@ -513,11 +557,23 @@ namespace concurrency
if ( childDecision == 1 && node.m_modeOR && node.m_modePromptDecision ) {
m_slot->controlFlowState[node.getNodeIndex()] = 1;
// if a decision was made for this node, propagate the result upwards
for ( auto parent : node.m_parents ) {
parent->accept( *this );
}
return true;
}
}
if ( allChildDecisionsResolved ) m_slot->controlFlowState[node.getNodeIndex()] = 1;
if ( allChildDecisionsResolved ) {
m_slot->controlFlowState[node.getNodeIndex()] = 1;
// if a decision was made for this node, propagate the result upwards
for ( auto parent : node.m_parents ) {
parent->accept( *this );
}
}
return allChildDecisionsResolved;
}
......
......@@ -64,16 +64,7 @@ namespace concurrency
if ( visitor.visitEnter( *this ) ) {
// try to aggregate a decision
bool result = visitor.visit( *this );
// if a decision was made for this node, propagate the result upwards
if ( result ) {
for ( auto parent : m_parents ) {
parent->accept( visitor );
}
return false;
}
return true; // visitor was accepted to try to aggregate the node's decision
return !result;
}
return false; // visitor was rejected (since the decision node has an aggregated decision already)
......
#include "ViewTester.h"
#include "GaudiKernel/ThreadLocalContext.h"
DECLARE_COMPONENT( Test::ViewTester )
#define ON_DEBUG if ( msgLevel( MSG::DEBUG ) )
#define DEBUG_MSG ON_DEBUG debug()
#define ON_VERBOSE if ( msgLevel( MSG::VERBOSE ) )
#define VERBOSE_MSG ON_VERBOSE verbose()
using namespace Test;
//------------------------------------------------------------------------------
ViewTester::ViewTester( const std::string& name, // the algorithm instance name
ISvcLocator* pSvc )
: GaudiAlgorithm( name, pSvc )
{
}
ViewTester::~ViewTester()
{
for ( uint i = 0; i < m_inputHandles.size(); ++i ) delete m_inputHandles[i];
for ( uint i = 0; i < m_outputHandles.size(); ++i ) delete m_outputHandles[i];
}
StatusCode ViewTester::initialize()
{
auto sc = GaudiAlgorithm::initialize();