diff --git a/GaudiExamples/CMakeLists.txt b/GaudiExamples/CMakeLists.txt index 51a0e500c6f5ded3bdf6c0447208d83ae1b0c815..4b8b7cc43d442c1072d1cfbee430fa4858a05585 100644 --- a/GaudiExamples/CMakeLists.txt +++ b/GaudiExamples/CMakeLists.txt @@ -35,6 +35,7 @@ set(GaudiExamples_srcs src/AlgSequencer/*.cpp src/AlgTools/*.cpp src/AnyData/*.cpp + src/Conditions/*.cpp src/DataOnDemand/*.cpp src/AlgErrAud/*.cpp src/NTuples/*.cpp diff --git a/GaudiExamples/options/Conditions.py b/GaudiExamples/options/Conditions.py new file mode 100644 index 0000000000000000000000000000000000000000..9f5d376ea1cf71291d59d63758ed781e129a9670 --- /dev/null +++ b/GaudiExamples/options/Conditions.py @@ -0,0 +1,23 @@ +from Gaudi.Configuration import * +from Configurables import AvalancheSchedulerSvc, DemoConditionAlg +from Configurables import HiveWhiteBoard, HiveSlimEventLoopMgr +from Configurables import DemoBackend__ConditionContextProducer as ConditionContextProducer +from Configurables import DemoBackend__detail__ConditionBackendSvc as ConditionBackendSvc + +# Application setup +condBackend = ConditionBackendSvc("ConditionBackendSvc") +scheduler = AvalancheSchedulerSvc(ThreadPoolSize=1) +slimEventLoopMgr = HiveSlimEventLoopMgr(OutputLevel=INFO) +whiteBoard = HiveWhiteBoard("EventDataSvc", EventSlots=2) + +# - Algorithms +topAlgs = [ConditionContextProducer("ConditionContextProducer"), + DemoConditionAlg("DemoConditionAlg")] + +# Application manager +app = ApplicationMgr(EvtMax=10, + ExtSvc=[whiteBoard, condBackend], + EventLoop=slimEventLoopMgr, + EvtSel='NONE', + HistogramPersistency='NONE', + TopAlg=topAlgs) diff --git a/GaudiExamples/src/Conditions/ConditionAccessor.h b/GaudiExamples/src/Conditions/ConditionAccessor.h new file mode 100644 index 0000000000000000000000000000000000000000..fcf2ae3eb1ce270e475f3be9415b2a10be330b8e --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionAccessor.h @@ -0,0 +1,57 @@ +#pragma once + +#include <string> + +#include "GaudiKernel/Property.h" + +#include "ConditionContext.h" +#include "ConditionKey.h" + +namespace DemoBackend +{ + // A condition accessor is to condition data what an EventReadHandle is to + // event data : it notifies the framework that an Algorithm or AlgTool depends + // on a certain condition, enables configuring the target condition from + // Python, and allows accessing that condition during event processing. + // + // ConditionAccessors are meant to be declared as members of the Algorithm or + // AlgTool that owns them. Declaring them in any other place (on the stack, + // on a separate heap location...) is likely to result in undefined behaviour. + // + template <typename T> + class ConditionAccessor { + public: + // Constructor takes the "this" pointer of the owner and the usual triplet + // of values needed to declare a property (in this case the condition's key) + template <typename Owner> + ConditionAccessor( Owner* owner, + const std::string& keyName, + const ConditionKey& keyDefault = {}, + const std::string& keyDoc = "" ) + : m_key{ owner, keyName, keyDefault, keyDoc } + { + owner->registerConditionAccessor( *this ); + } + + // Condition accessors can neither be moved nor copied + ConditionAccessor( const ConditionAccessor& ) = delete; + ConditionAccessor( ConditionAccessor&& ) = delete; + ConditionAccessor& operator=( const ConditionAccessor& ) = delete; + ConditionAccessor& operator=( ConditionAccessor&& ) = delete; + + // Access the key which this ConditionAccessor points to. + // The key may change during configuration of the owner. + const ConditionKey& key() const { + return m_key; + } + + // Access the value of the condition, for a given condition context + const T& get( const ConditionContext& ctx ) const { + return ctx.getCondition<T>( m_key ); + } + + private: + // Configurable key which this ConditoinAccessor points to. + Gaudi::Property<ConditionKey> m_key; + }; +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionAccessorAlg.h b/GaudiExamples/src/Conditions/ConditionAccessorAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..fdfe9ff376783b6e9a9f3a30b4991ef8138a6e57 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionAccessorAlg.h @@ -0,0 +1,11 @@ +#pragma once + +#include "GaudiKernel/Algorithm.h" + +#include "ConditionAccessorHolder.h" + +namespace DemoBackend +{ + // Base class for Algorithms that can use ConditionAccessors + using ConditionAccessorAlg = ConditionAccessorHolder<Gaudi::Algorithm>; +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionAccessorHolder.h b/GaudiExamples/src/Conditions/ConditionAccessorHolder.h new file mode 100644 index 0000000000000000000000000000000000000000..cae6830d0b7f70f7b37c49773c560ca6ea8fa5ba --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionAccessorHolder.h @@ -0,0 +1,84 @@ +#pragma once + +#include <typeinfo> +#include <utility> +#include <vector> + +#include "GaudiKernel/EventDataHandle.h" +#include "GaudiKernel/StatusCode.h" + +#include "ConditionAccessor.h" +#include "ConditionBackendSvc.h" +#include "ConditionContext.h" +#include "ConditionContextPath.h" +#include "ConditionKey.h" + +namespace DemoBackend +{ + // Wrapper around Algorithm or AlgTool that enables it to depend on + // conditions via ConditionAccessors. + // + // Together with ConditionAccessor, this is the main interface through which + // Algorithm and Tool writers interact with the condition management backend. + // Everything else is, in a sense, an implementation detail of them. + // + template <typename Base> + class ConditionAccessorHolder : public Base { + public: + // Forward the constructor from the Algorithm / AlgTool base class + using Base::Base; + + // The base class exposes to the user all the other components of the + // chosen back-end's interface: accessors, contexts and keys. + template <typename T> + using ConditionAccessor = DemoBackend::ConditionAccessor<T>; + using ConditionContext = DemoBackend::ConditionContext; + using ConditionKey = DemoBackend::ConditionKey; + + // At initialize() time, we must declare our condition inputs (whose key + // has been configured by now) to the condition management backend. + StatusCode initialize() override { + // Initialize the base (this will configure condition accessor keys) + auto status = Base::initialize(); + if ( status.isFailure() ) return status; + + // Get access to the condition backend service + auto backendSvcIF = Base::service( "ConditionBackendSvc" ); + if ( !backendSvcIF ) return StatusCode::FAILURE; + auto& backendSvc = dynamic_cast<detail::ConditionBackendSvc&>( *backendSvcIF ); + + // Declare the condition keys and types that we are going to use + for ( auto& info : m_accessorInfo ) { + backendSvc.registerCondition( *info.first, *info.second ); + } + return status; + } + + // We must also provide a way for a reentrant algorithm to access the + // condition handling context associated with this event. + const ConditionContext& getConditionContext( const EventContext& ctx ) const { + return m_ctxHandle.get( ctx ); + } + + private: + // This block of private declarations is an implementation detail of accessors + template <typename T> + friend class ConditionAccessor; + + // Track that a new ConditionAccessor has been declared + template <typename T> + void registerConditionAccessor( ConditionAccessor<T>& accessor ) { + m_accessorInfo.emplace_back( &accessor.key(), &typeid( T ) ); + } + + private: + // We must declare a dependency on the condition context + // (which will be produced by the ConditionContextProducer alg). + Gaudi::EventReadHandle<ConditionContext> m_ctxHandle{ + detail::CONDITION_CONTEXT_PATH, this }; + + // We must track some properties of our condition accessors to declare them + // during initialize(). An alternative would be some ConditionAccessorBase*. + std::vector<std::pair<const ConditionKey*, const std::type_info*>> m_accessorInfo; + }; +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionBackendSvc.cpp b/GaudiExamples/src/Conditions/ConditionBackendSvc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bb8b844ab2a3445455324bf8dd49880d2528982 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionBackendSvc.cpp @@ -0,0 +1,42 @@ +#include <stdexcept> +#include <unordered_map> + +#include "ConditionBackendSvc.h" + +namespace DemoBackend +{ + namespace detail + { + void ConditionBackendSvc::registerCondition( const ConditionKey& key, const std::type_info& type ) + { + if ( m_keysFrozen ) { + throw std::runtime_error( "Attempted to register a condition input after start()" ); + } + if ( type != typeid( float ) ) { + throw std::runtime_error( "This dummy condition back-end only supports float conditions" ); + } + m_keys.insert( key ); + } + + StatusCode ConditionBackendSvc::start() + { + auto status = Service::start(); + if ( status.isFailure() ) return status; + m_keysFrozen = true; + return status; + } + + ConditionContext ConditionBackendSvc::setupEvent( const EventTimestamp& eventTime ) { + if ( !m_keysFrozen ) { + throw std::runtime_error( "Attempted to access a condition before start()" ); + } + std::unordered_map<ConditionKey, float> conditions; + for ( const auto& key : m_keys ) { + conditions.emplace( key, 4.2 * eventTime * key.size() ); + } + return ConditionContext{ std::move( conditions ) }; + } + + DECLARE_COMPONENT( ConditionBackendSvc ) + } +} diff --git a/GaudiExamples/src/Conditions/ConditionBackendSvc.h b/GaudiExamples/src/Conditions/ConditionBackendSvc.h new file mode 100644 index 0000000000000000000000000000000000000000..708db4268973fdc16d7e45ba6dcfa591fa3ec94f --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionBackendSvc.h @@ -0,0 +1,55 @@ +#pragma once + +#include <typeinfo> +#include <unordered_set> + +#include "GaudiKernel/Service.h" +#include "GaudiKernel/StatusCode.h" + +#include "ConditionContext.h" +#include "ConditionKey.h" +#include "EventTimestamp.h" + +namespace DemoBackend +{ + namespace detail + { + // The actual condition handling back-end implementation (which should be + // a service as it is configurable and shared mutable global state) is not + // part of the propose API, and ConditionAccessorAlgs should never interact + // with it directly. + // + // Therefore, the API surface that is presented here is only a rough example + // of what is needed. A more reasonable back-end implementation would also + // feature performance shortcuts to access declared conditions more quickly, + // to start condition IO and derivation before conditions are actually + // needed, and a way for the ConditionContext destructor to notify the + // back-end that an event is done processing, so that usage of condition + // data can be tracked and unused conditions can be garbage-collected. + // + class ConditionBackendSvc final : public Service { + public: + // Inherited Service constructor + using Service::Service; + + // Notify the storage back-end that we will be accessing a condition + // Type info is provided to be able to type-check the condition dataflow + void registerCondition( const ConditionKey&, const std::type_info& ); + + // When event processing starts, the set of conditions to be used is + // considered complete, and new conditions cannot be registered anymore. + StatusCode start() override; + + // Given an event timestamp, this function carries our condition IO and + // derivation or gives access to previously prepared conditions. + ConditionContext setupEvent( const EventTimestamp& ); + + private: + // Set of condition keys that were registered so far + std::unordered_set<ConditionKey> m_keys; + + // Flag indicating when the above set can be considered complete + bool m_keysFrozen = false; + }; + } +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionContext.cpp b/GaudiExamples/src/Conditions/ConditionContext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92210a16a08d7e998412ccf7c1038cbdd1150a79 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionContext.cpp @@ -0,0 +1,8 @@ +#include "ConditionContext.h" + +namespace DemoBackend +{ + ConditionContext::ConditionContext( std::unordered_map<ConditionKey, float>&& data ) + : m_data{ std::move( data ) } + {} +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionContext.h b/GaudiExamples/src/Conditions/ConditionContext.h new file mode 100644 index 0000000000000000000000000000000000000000..e9783a0c9d18c64612be7e9473a83691d79d0a54 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionContext.h @@ -0,0 +1,52 @@ +#pragma once + +#include <stdexcept> +#include <typeinfo> +#include <unordered_map> + +#include "ConditionKey.h" + +namespace DemoBackend +{ + template <typename T> + class ConditionAccessor; + + namespace detail + { + class ConditionBackendSvc; + } + + // Much like the EventContext gives access to event data, a ConditionContext + // gives access to condition data. For technical reasons, the ConditionContext + // may be produced during event processing and is stored in the TES. + class ConditionContext { + public: + // Normally, we would tell the backend that we're done processing a given + // event via RAII, but this is not necessary for this dummy implementation. + ~ConditionContext() = default; + + private: + // This block of private declarations is an implementation detail of accessors + template <typename T> + friend class ConditionAccessor; + + // Query the condition slot for a given condition + template <typename ConditionType> + const ConditionType& getCondition( const ConditionKey& key ) const { + if ( typeid( ConditionType ) != typeid( float ) ) { + throw std::runtime_error( "This silly backend only supports float conditions" ); + } + return m_data.at( key ); + } + + private: + // This block of private declarations is an implementation detail of the back-end + friend class detail::ConditionBackendSvc; + + // Construct a ConditionContext from backend-internal data + ConditionContext( std::unordered_map<ConditionKey, float>&& ); + + private: + std::unordered_map<ConditionKey, float> m_data; + }; +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionContextPath.cpp b/GaudiExamples/src/Conditions/ConditionContextPath.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e2c263590e1e6cf220c22ab994d315c5fefa6d2 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionContextPath.cpp @@ -0,0 +1,9 @@ +#include "ConditionContextPath.h" + +namespace DemoBackend +{ + namespace detail + { + DataObjID CONDITION_CONTEXT_PATH{ "/Event/DemoBackendCondCtx" }; + } +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionContextPath.h b/GaudiExamples/src/Conditions/ConditionContextPath.h new file mode 100644 index 0000000000000000000000000000000000000000..8088d22f23078f6cacc79b6d4832c8f264b90205 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionContextPath.h @@ -0,0 +1,16 @@ +#pragma once + +#include "GaudiKernel/DataObjID.h" + +namespace DemoBackend +{ + namespace detail + { + // Right now, the path to the condition context in the TES is hardcoded. + // Later on, we'll want to make it configurable. + // + // FIXME: Could just be a Property of the ConditionBackendSvc? + // + extern DataObjID CONDITION_CONTEXT_PATH; + } +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionContextProducer.cpp b/GaudiExamples/src/Conditions/ConditionContextProducer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8994d537fe0ffcb44209d02bcb857d660326d255 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionContextProducer.cpp @@ -0,0 +1,26 @@ +#include "ConditionBackendSvc.h" +#include "ConditionContextProducer.h" +#include "EventTimestamp.h" + +namespace DemoBackend +{ + StatusCode ConditionContextProducer::initialize() { + auto status = Gaudi::Algorithm::initialize(); + if ( status.isFailure() ) return status; + + m_backendSvcIF = service( "ConditionBackendSvc" ); + if ( !m_backendSvcIF ) return StatusCode::FAILURE; + m_backendSvc = &dynamic_cast<detail::ConditionBackendSvc&>( *m_backendSvcIF ); + + return StatusCode::SUCCESS; + } + + StatusCode ConditionContextProducer::execute( const EventContext& ctx ) const { + // For this test, we just use the event number as an event timestamp + detail::EventTimestamp eventTime = ctx.evt(); + m_ctxHandle.put( ctx, m_backendSvc->setupEvent( eventTime ) ); + return StatusCode::SUCCESS; + } + + DECLARE_COMPONENT( ConditionContextProducer ) +} diff --git a/GaudiExamples/src/Conditions/ConditionContextProducer.h b/GaudiExamples/src/Conditions/ConditionContextProducer.h new file mode 100644 index 0000000000000000000000000000000000000000..76cf4ee4e3c94027708f37300e4bf0de5193180c --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionContextProducer.h @@ -0,0 +1,49 @@ +#pragma once + +#include "GaudiKernel/Algorithm.h" +#include "GaudiKernel/EventContext.h" +#include "GaudiKernel/EventDataHandle.h" +#include "GaudiKernel/IService.h" +#include "GaudiKernel/SmartIF.h" +#include "GaudiKernel/StatusCode.h" + +#include "ConditionContext.h" +#include "ConditionContextPath.h" + +namespace DemoBackend +{ + namespace detail + { + class ConditionBackendSvc; + } + + // Every condition handling back-end must define an Algorithm that is executed + // whenever the EventTimestamp is known, reads it from the TES, asks the + // back-end to prepare a ConditionContext for this event, and inserts that in + // a commonly agreed location of the TES. + // + // Whether the user need to insert this Algorithm in their data processing + // graph depends on how clever the Scheduler implementation is. Some + // Scheduler implementations can just insert it automatically. + // + class ConditionContextProducer final : public Gaudi::Algorithm { + public: + // Inherit Algorithm constructor + using Gaudi::Algorithm::Algorithm; + + // At initialization time, we get in touch with the back-end + StatusCode initialize() override; + + // Whenever the event timestamp is ready, we produce the ConditionContext + StatusCode execute( const EventContext& ctx ) const override; + + private: + // This DataHandle allows us to write down the ConditionContext in the TES + Gaudi::EventWriteHandle<ConditionContext> m_ctxHandle{ + detail::CONDITION_CONTEXT_PATH, this }; + + // These members allow us to contact the condition storage back-end + SmartIF<IService> m_backendSvcIF; + detail::ConditionBackendSvc* m_backendSvc = nullptr; + }; +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/ConditionKey.h b/GaudiExamples/src/Conditions/ConditionKey.h new file mode 100644 index 0000000000000000000000000000000000000000..3f332ebacbb55e2f144d8069f3dbbc40961d3a46 --- /dev/null +++ b/GaudiExamples/src/Conditions/ConditionKey.h @@ -0,0 +1,9 @@ +#pragma once + +#include <string> + +namespace DemoBackend +{ + // Keys are the way conditions are referred to during configuration + using ConditionKey = std::string; +} \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/DemoConditionAlg.cpp b/GaudiExamples/src/Conditions/DemoConditionAlg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22fb72bf85554f083d0477c10519e655e605e034 --- /dev/null +++ b/GaudiExamples/src/Conditions/DemoConditionAlg.cpp @@ -0,0 +1,37 @@ +#include "ConditionAccessorAlg.h" + +// This is a demonstration of what it could feel like to write an Algorithm that +// uses conditions, until Gaudi::Functional fully hides it away from the user. +// +// We expect multiple condition management backends to coexist for a while. In +// the proposed infrastructure, a single algorithm may only use a single +// condition management backend, but multiple algorithms may each use a +// different condition management backend. +// +// The selection of a condition management backend is done by the choice of +// "ConditionAccessorAlg" base class, which transparently makes available all +// the other components of the condition access interface: ConditionContexts, +// ConditionAccessors, and ConditionKeys. +// +class DemoConditionAlg final : public DemoBackend::ConditionAccessorAlg { +public: + // Inherit constructor from base class + using DemoBackend::ConditionAccessorAlg::ConditionAccessorAlg; + + // In this demonstrator, the condition context is fetched explicitly + StatusCode execute( const EventContext& evCtx ) const override { + const ConditionContext& condCtx = this->getConditionContext( evCtx ); + const float& condValue = m_myCondition.get( condCtx ); + info() << "Value of condition @ " << m_myCondition.key() + << " for event #" << evCtx.evt() + << " is " << condValue << endmsg; + return StatusCode::SUCCESS; + } + +private: + // ConditionAccessors feel like EventReadHandles for all intents and purposes + ConditionAccessor<float> m_myCondition { + this, "MyCondition", ConditionKey { "/Path/To/Condition" }, "Location of test condition" }; +}; + +DECLARE_COMPONENT( DemoConditionAlg ) \ No newline at end of file diff --git a/GaudiExamples/src/Conditions/EventTimestamp.h b/GaudiExamples/src/Conditions/EventTimestamp.h new file mode 100644 index 0000000000000000000000000000000000000000..e61988ac02f7fe4c40ef56e02ba03f8b19f05925 --- /dev/null +++ b/GaudiExamples/src/Conditions/EventTimestamp.h @@ -0,0 +1,13 @@ +#pragma once + +#include <cstdint> + +namespace DemoBackend +{ + namespace detail + { + // Timestamps are used to locate events in an experiment run and define + // the notion of a condition's interval of validity. + using EventTimestamp = uint64_t; + } +} \ No newline at end of file diff --git a/GaudiExamples/tests/qmtest/gaudiexamples.qms/conditions.qmt b/GaudiExamples/tests/qmtest/gaudiexamples.qms/conditions.qmt new file mode 100644 index 0000000000000000000000000000000000000000..50ee5da0a27599fcdaa66a2f7644ce74f5c97e08 --- /dev/null +++ b/GaudiExamples/tests/qmtest/gaudiexamples.qms/conditions.qmt @@ -0,0 +1,7 @@ +<?xml version="1.0" ?><!DOCTYPE extension PUBLIC '-//QM/2.3/Extension//EN' 'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'> +<extension class="GaudiTest.GaudiExeTest" kind="test"> +<argument name="program"><text>gaudirun.py</text></argument> +<argument name="args"><set><text>$GAUDIEXAMPLESROOT/options/Conditions.py</text></set></argument> +<argument name="use_temp_dir"><enumeral>true</enumeral></argument> +<argument name="reference"><text>refs/Conditions.ref</text></argument> +</extension> diff --git a/GaudiExamples/tests/qmtest/refs/Conditions.ref b/GaudiExamples/tests/qmtest/refs/Conditions.ref new file mode 100644 index 0000000000000000000000000000000000000000..da1c3f5c39109b42af0067d37e18c0234cde3fbb --- /dev/null +++ b/GaudiExamples/tests/qmtest/refs/Conditions.ref @@ -0,0 +1,46 @@ +# --> Including file '/root/Gaudi/GaudiExamples/options/Conditions.py' +# <-- End of file '/root/Gaudi/GaudiExamples/options/Conditions.py' +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v30r5) + running on 367e0b4f1840 on Wed Jan 23 22:34:24 2019 +==================================================================================================================================== +ApplicationMgr INFO Application Manager Configured successfully +ThreadPoolSvc INFO no thread init tools attached +AvalancheSchedu... INFO Activating scheduler in a separate thread +AlgResourcePool INFO TopAlg list empty. Recovering the one of Application Manager +AvalancheSchedu... INFO Found 2 algorithms +AvalancheSchedu... INFO Data Dependencies for Algorithms: + ConditionContextProducer + o OUTPUT '/Event/DemoBackendCondCtx' + DemoConditionAlg + o INPUT '/Event/DemoBackendCondCtx' +PrecedenceSvc INFO Assembling CF and DF task precedence rules +PrecedenceSvc INFO PrecedenceSvc initialized successfully +AvalancheSchedu... INFO Concurrency level information: +AvalancheSchedu... INFO o Number of events in flight: 2 +AvalancheSchedu... INFO o TBB thread pool size: 'ThreadPoolSize':1 +HiveSlimEventLo...WARNING Unable to locate service "EventSelector" +HiveSlimEventLo...WARNING No events will be processed from external input. +HistogramPersis...WARNING Histograms saving not required. +HiveSlimEventLo... INFO Found 0 events in black list +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr INFO Application Manager Started successfully +HiveSlimEventLo... INFO Starting loop on events +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #0 is 0 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #1 is 75.6 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #2 is 151.2 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #3 is 226.8 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #4 is 302.4 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #5 is 378 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #6 is 453.6 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #7 is 529.2 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #8 is 604.8 +DemoConditionAlg INFO Value of condition @ /Path/To/Condition for event #9 is 680.4 +HiveSlimEventLo... INFO ---> Loop Finished (skipping 1st evt) - WSS 69.2461 total time 1223367 +HiveSlimEventLo... INFO 0 events were SKIPed +ApplicationMgr INFO Application Manager Stopped successfully +HiveSlimEventLo... INFO Histograms converted successfully according to request. +AvalancheSchedu... INFO Joining Scheduler thread +ApplicationMgr INFO Application Manager Finalized successfully +ApplicationMgr INFO Application Manager Terminated successfully \ No newline at end of file