diff --git a/Control/AthenaExamples/TBBExamples/CMakeLists.txt b/Control/AthenaExamples/TBBExamples/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bfbe9f74ef0aa0ce4646c00bde725018ff45a7c --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/CMakeLists.txt @@ -0,0 +1,33 @@ +################################################################################ +# Package: TBBExamples +################################################################################ + +# Declare the package name: +atlas_subdir( TBBExamples ) + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + GaudiKernel + PRIVATE + AtlasTest/TestTools + Control/AthenaBaseComps + Control/AthenaKernel + Control/DataModel + TestPolicy ) + +# External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) +find_package( TBB ) + +# Component(s) in the package: +atlas_add_component( TBBExamples + src/*.cxx + src/components/*.cxx + INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS} + LINK_LIBRARIES ${Boost_LIBRARIES} ${TBB_LIBRARIES} GaudiKernel AthenaBaseComps AthenaKernel DataModel ) + +# Install files from the package: +atlas_install_headers( TBBExamples ) +atlas_install_joboptions( share/*.py ) +atlas_install_runtime( test/TBBExamples_TestConfiguration.xml ) + diff --git a/Control/AthenaExamples/TBBExamples/TBBExamples/IHelloTool.h b/Control/AthenaExamples/TBBExamples/TBBExamples/IHelloTool.h new file mode 100755 index 0000000000000000000000000000000000000000..d60a081720e38e9dd12fcd03c6e0fc1111550054 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/TBBExamples/IHelloTool.h @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHEXHELLOWORLD_IHELLOTOOL_H +#define ATHEXHELLOWORLD_IHELLOTOOL_H 1 + +#include "GaudiKernel/IAlgTool.h" +#include <string> + +class IHelloTool : virtual public IAlgTool { +public: + virtual int addToIt(int soFar) = 0; + virtual StatusCode saySomething(std::string& message) = 0; + static const InterfaceID& interfaceID() { + static const InterfaceID _IHelloToolID( "IHelloTool", 1, 0 ); + return _IHelloToolID; + } +}; +#endif // !ATHEXHELLOWORLD_IHELLOTOOL_H diff --git a/Control/AthenaExamples/TBBExamples/cmt/requirements b/Control/AthenaExamples/TBBExamples/cmt/requirements new file mode 100644 index 0000000000000000000000000000000000000000..677bdce23de570bfb61d7abace9a9811ec9d09e0 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/cmt/requirements @@ -0,0 +1,51 @@ +package TBBExamples + +author Paolo Calafiura <Paolo.Calafiura@cern.ch> + +use AtlasPolicy AtlasPolicy-* +use GaudiInterface GaudiInterface-* External + +private +use AtlasBoost AtlasBoost-* External +use AtlasTBB AtlasTBB-* External +use AthenaBaseComps AthenaBaseComps-* Control +use AthenaKernel AthenaKernel-* Control +use DataModel DataModel-* Control +macro_append cppflags " -std=c++0x " +end_private + + +library TBBExamples *.cxx -s=components *.cxx +apply_pattern component_library +#details about the component_library and dual_library patterns +# at http://www.cern.ch/Atlas/GROUPS/SOFTWARE/OO/architecture/General/Documentation/PackageStructure.txt + +apply_pattern declare_joboptions files="*.py" + +apply_pattern declare_python_modules files="*.py" + +macro TBBExamples_TestConfiguration "../test/TBBExamples_TestConfiguration.xml" +apply_pattern declare_runtime extras="../test/TBBExamples_TestConfiguration.xml" + +# for unit tests and automatic ATN xml validation +private +use TestPolicy TestPolicy-* +use TestTools TestTools-* AtlasTest -no_auto_imports + +apply_pattern validate_xml + + +apply_pattern athenarun_test name="HelloParFor" \ + pre_script="../cmt/setup.sh" \ + options="TBBExamples/HelloParForOptions.py" \ + post_script="${TESTTOOLSROOT}/share/post.sh HelloParFor $(q)^Py:ConfigurableDb +(WARNING|INFO|ERROR)|Py:Athena +INFO including file |Warning in .TEnvRec::ChangeValue.: duplicate entry|ToolSvc.finalize.. +INFO|^WriteData +INFO in initialize$$| [A-Z]+ 2[0-9][0-9][0-9]$$$(SGGoptignore)|^Py:Athena +INFO|[Rr]oo[Ff]it|NIKHEF|DeprecationWarning: object.__new__|^ newobj =|^\*+$$|drop-and-reload|^ *$$|we will keep the configuration around|object not modifiable when retrieved|Retrieved const handle to default|type EventInfo$(q)" + +apply_pattern athenarun_test name="HelloPipeAlg" \ + pre_script="../cmt/setup.sh" \ + options="TBBExamples/HelloPipeOptions.py" \ + post_script="${TESTTOOLSROOT}/share/post.sh HelloPipeAlg $(q)^Py:ConfigurableDb +(WARNING|INFO|ERROR)|Py:Athena +INFO including file |Warning in .TEnvRec::ChangeValue.: duplicate entry|ToolSvc.finalize.. +INFO|^WriteData +INFO in initialize$$| [A-Z]+ 2[0-9][0-9][0-9]$$$(SGGoptignore)|^Py:Athena +INFO|[Rr]oo[Ff]it|NIKHEF|DeprecationWarning: object.__new__|^ newobj =|^\*+$$|drop-and-reload|^ *$$|we will keep the configuration around|object not modifiable when retrieved|Retrieved const handle to default|type EventInfo$(q)" + + + + +end_private diff --git a/Control/AthenaExamples/TBBExamples/doc/MainPage.h b/Control/AthenaExamples/TBBExamples/doc/MainPage.h new file mode 100755 index 0000000000000000000000000000000000000000..c049fb555bd3076aed4b5604d648564e8d6a0d94 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/doc/MainPage.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + + @mainpage TBBExamples +This package contains HelloWorld-type examples of TBB task scheduling within +an athena Algorithm. + +@section Examples Examples + - HelloParForAlg + - HelloPipeAlg + - HelloGraphAlg + +@htmlinclude used_packages.html + + +@section reqs CMT requirements file +@include requirements + +@section Refs More Documentation + +The code can be browsed using LXR +(http://alxr.usatlas.bnl.gov/lxr/source/atlas/Control/AthenaExamples/TBBExamples) + +More information on TBB is available from +http://threadingbuildingblocks.org/documentation.php + +@author Paolo Calafiura <pcalafiura@lbl.gov> + +*/ diff --git a/Control/AthenaExamples/TBBExamples/share/HelloGraphOptions.py b/Control/AthenaExamples/TBBExamples/share/HelloGraphOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..c02a6c4685e0f68b936220b65bb59695423d130e --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/share/HelloGraphOptions.py @@ -0,0 +1,80 @@ +############################################################### +# +# Job options file +# +#============================================================== + +#-------------------------------------------------------------- +# ATLAS default Application Configuration options +#-------------------------------------------------------------- + +# Use McEventSelector so we can run with AthenaMP +import AthenaCommon.AtlasUnixGeneratorJob + +#-------------------------------------------------------------- +# Private Application Configuration options +#-------------------------------------------------------------- + +# Full job is a list of algorithms +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() + +# Add top algorithms to be run +from TBBExamples.TBBExamplesConf import HelloGraphAlg +job += HelloGraphAlg( "HelloWorld" ) # 1 alg, named "HelloWorld" + +#-------------------------------------------------------------- +# Set output level threshold (DEBUG, INFO, WARNING, ERROR, FATAL) +#-------------------------------------------------------------- + +svcMgr.MessageSvc.OutputLevel = Lvl.DEBUG + + +# You can set the global output level on the message svc (not +# recommended) or by using the -l athena CLI parameter + +#-------------------------------------------------------------- +# Event related parameters +#-------------------------------------------------------------- + +# Number of events to be processed (default is until the end of +# input, or -1, however, since we have no input, a limit needs +# to be set explicitly, here, choose 10) +theApp.EvtMax = 2 + +#-------------------------------------------------------------- +# Algorithms Private Options (all optional) +#-------------------------------------------------------------- + +# For convenience, get a reference to the HelloParForAlg Algorithm +# named "HelloWorld" in the job +HelloWorld = job.HelloWorld + +# Max number of pipe stages to run in parallel +HelloWorld.NIters = 10 + +#-------------------------------------------------------------- +# Algorithms Tool Usage Private Options (advanced and optional) +#-------------------------------------------------------------- + +# Import configurable for using our HelloTool +from TBBExamples.TBBExamplesConf import TBBTool +# Setup a public tool so that it can be used (again, note name) +ToolSvc += TBBTool( "PublicHello" ) +ToolSvc.PublicHello.MyIncrement = 100 + +# Tell "HelloWorld" to use this tool ("MyPublicHelloTool" is a +# ToolHandle property of HelloGraphAlg) +HelloWorld.MyPublicHelloTool = ToolSvc.PublicHello + +# Hand "HelloWorld" a private HelloTool ("MyPrivateHelloTool" is +# a ToolHandler property of HelloGraphAlg) +HelloWorld.MyPrivateHelloTool = TBBTool( "HelloTool" ) +HelloWorld.MyPrivateHelloTool.MyIncrement = -200 + +#============================================================== +# +# End of job options file +# +############################################################### + diff --git a/Control/AthenaExamples/TBBExamples/share/HelloParForOptions.py b/Control/AthenaExamples/TBBExamples/share/HelloParForOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..9cc3a5690602f4a9543f890a5a283a7a03d5720a --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/share/HelloParForOptions.py @@ -0,0 +1,80 @@ +############################################################### +# +# Job options file +# +#============================================================== + +#-------------------------------------------------------------- +# ATLAS default Application Configuration options +#-------------------------------------------------------------- + +# Use McEventSelector so we can run with AthenaMP +import AthenaCommon.AtlasUnixGeneratorJob + +#-------------------------------------------------------------- +# Private Application Configuration options +#-------------------------------------------------------------- + +# Full job is a list of algorithms +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() + +# Add top algorithms to be run +from TBBExamples.TBBExamplesConf import HelloParForAlg +job += HelloParForAlg( "HelloWorld" ) # 1 alg, named "HelloWorld" + +#-------------------------------------------------------------- +# Set output level threshold (DEBUG, INFO, WARNING, ERROR, FATAL) +#-------------------------------------------------------------- + +svcMgr.MessageSvc.OutputLevel = Lvl.DEBUG + +# You can set the global output level on the message svc (not +# recommended) or by using the -l athena CLI parameter + +#-------------------------------------------------------------- +# Event related parameters +#-------------------------------------------------------------- + +# Number of events to be processed (default is until the end of +# input, or -1, however, since we have no input, a limit needs +# to be set explicitly, here, choose 10) +theApp.EvtMax = 2 + +#-------------------------------------------------------------- +# Algorithms Private Options (all optional) +#-------------------------------------------------------------- + +# For convenience, get a reference to the HelloParForAlg Algorithm +# named "HelloWorld" in the job +HelloWorld = job.HelloWorld + +# Set an int property +HelloWorld.NIters = 10 + +#-------------------------------------------------------------- +# Algorithms Tool Usage Private Options (advanced and optional) +#-------------------------------------------------------------- + +# Import configurable for using our TBBTool +from TBBExamples.TBBExamplesConf import TBBTool + +# Setup a public tool so that it can be used (again, note name) +ToolSvc += TBBTool( "PublicHello" ) +ToolSvc.PublicHello.MyMessage = "One!" + +# Tell "HelloWorld" to use this tool ("MyPublicHelloTool" is a +# ToolHandle property of HelloParForAlg) +HelloWorld.MyPublicHelloTool = ToolSvc.PublicHello + +# Hand "HelloWorld" a private HelloTool ("MyPrivateHelloTool" is +# a ToolHandler property of HelloParForAlg) +HelloWorld.MyPrivateHelloTool = TBBTool( "HelloTool" ) +HelloWorld.MyPrivateHelloTool.MyMessage = "Two!" + +#============================================================== +# +# End of job options file +# +############################################################### + diff --git a/Control/AthenaExamples/TBBExamples/share/HelloPipeOptions.py b/Control/AthenaExamples/TBBExamples/share/HelloPipeOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..254b93e275c225b3ddc8cfb16c193d77e319d052 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/share/HelloPipeOptions.py @@ -0,0 +1,81 @@ +############################################################### +# +# Job options file +# +#============================================================== + +#-------------------------------------------------------------- +# ATLAS default Application Configuration options +#-------------------------------------------------------------- + +# Use McEventSelector so we can run with AthenaMP +import AthenaCommon.AtlasUnixGeneratorJob + +#-------------------------------------------------------------- +# Private Application Configuration options +#-------------------------------------------------------------- + +# Full job is a list of algorithms +from AthenaCommon.AlgSequence import AlgSequence +job = AlgSequence() + +# Add top algorithms to be run +from TBBExamples.TBBExamplesConf import HelloPipeAlg +job += HelloPipeAlg( "HelloWorld" ) # 1 alg, named "HelloWorld" + +#-------------------------------------------------------------- +# Set output level threshold (DEBUG, INFO, WARNING, ERROR, FATAL) +#-------------------------------------------------------------- + +svcMgr.MessageSvc.OutputLevel = Lvl.DEBUG + +# You can set the global output level on the message svc (not +# recommended) or by using the -l athena CLI parameter + +#-------------------------------------------------------------- +# Event related parameters +#-------------------------------------------------------------- + +# Number of events to be processed (default is until the end of +# input, or -1, however, since we have no input, a limit needs +# to be set explicitly, here, choose 10) +theApp.EvtMax = 2 + +#-------------------------------------------------------------- +# Algorithms Private Options (all optional) +#-------------------------------------------------------------- + +# For convenience, get a reference to the HelloParForAlg Algorithm +# named "HelloWorld" in the job +HelloWorld = job.HelloWorld + +# Max number of pipe stages to run in parallel +HelloWorld.NTokens = 10 +HelloWorld.FilterSerial = False + +#-------------------------------------------------------------- +# Algorithms Tool Usage Private Options (advanced and optional) +#-------------------------------------------------------------- + +# Import configurable for using our TBBTool +from TBBExamples.TBBExamplesConf import TBBTool + +# Setup a public tool so that it can be used (again, note name) +ToolSvc += TBBTool( "PublicHello" ) +ToolSvc.PublicHello.MyMessage = "One!" + +# Tell "HelloWorld" to use this tool ("MyPublicHelloTool" is a +# ToolHandle property of HelloPipeAlg) +HelloWorld.MyPublicHelloTool = ToolSvc.PublicHello + +# Hand "HelloWorld" a private TBBTool ("MyPrivateHelloTool" is +# a ToolHandler property of HelloPipeAlg) +HelloWorld.MyPrivateHelloTool = TBBTool( "TBBTool" ) +HelloWorld.MyPrivateHelloTool.MyMessage = "Two!" + +#============================================================== +# +# End of job options file +# +############################################################### + diff --git a/Control/AthenaExamples/TBBExamples/src/HelloGraphAlg.cxx b/Control/AthenaExamples/TBBExamples/src/HelloGraphAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b738f818103ede0406de272413593a079bdfede8 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/HelloGraphAlg.cxx @@ -0,0 +1,173 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TBBExamples/IHelloTool.h" +#include "HelloGraphAlg.h" +#include "AthenaKernel/CloneTool.h" +#include <boost/bind.hpp> +#include <tuple> +using namespace std; +using namespace boost; +using namespace tbb::flow; + +HelloGraphAlg::HelloGraphAlg(const std::string& name, ISvcLocator* pSvcLocator) : + AthAlgorithm(name, pSvcLocator), m_nIters(0), m_concurrency(1), + m_myPrivateHelloTool("HelloTool",this), m_myPublicHelloTool("HelloTool"), m_graph(), m_input(m_graph) +{ + + // Part 2: Declare the properties + declareProperty("NIters", m_nIters, "number of iterations to feed to the graph"); + + declareProperty("Concurrency", m_concurrency, "number of tasks to execute concurrently in the functional part of the graph: 0=unlimited , 1=serial (default), N tasks"); + + declareProperty("MyPrivateHelloTool", m_myPrivateHelloTool, "private IHelloTool"); + declareProperty("MyPublicHelloTool", m_myPublicHelloTool, "public, shared IHelloTool"); + +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +class Summer { +private: + int m_sum; +public: + Summer() : m_sum(0) {} + int operator()(const std::tuple<int,int,int>& res) { + m_sum += get<0>(res) + get<1>(res) + get<2>(res); + cout << "this iteration " + << get<0>(res) + get<1>(res) + get<2>(res) << endl; + return m_sum; + } +}; + +void printGraphResult(int res) { + cout << "accumulated graph result " << res << endl; +} + +StatusCode HelloGraphAlg::initialize() { + + // Part 1: print where you are + ATH_MSG_INFO ("initialize()"); + + ATH_MSG_INFO + (" " << m_myPrivateHelloTool.propertyName() + << " = " << m_myPrivateHelloTool.type() + << endreq + << " " << m_myPublicHelloTool.propertyName() + << " = " << m_myPublicHelloTool.type()); + + + // Part 3: Retrieve the tools using the ToolHandles + if ( m_myPrivateHelloTool.retrieve().isFailure() ) { + ATH_MSG_FATAL + (m_myPrivateHelloTool.propertyName() << ": Failed to retrieve tool " + << m_myPrivateHelloTool.type()); + return StatusCode::FAILURE; + } else { + ATH_MSG_INFO + (m_myPrivateHelloTool.propertyName() << ": Retrieved tool " + << m_myPrivateHelloTool.type()); + } + if ( m_myPublicHelloTool.retrieve().isFailure() ) { + ATH_MSG_FATAL + (m_myPublicHelloTool.propertyName() << ": Failed to retrieve tool " + << m_myPublicHelloTool); + return StatusCode::FAILURE; + } else { + ATH_MSG_INFO (m_myPublicHelloTool.propertyName() << ": Retrieved tool " + << m_myPublicHelloTool.type()); + } + + IHelloTool* clonedPrivate(0); + if(!(CloneTool::clone(*m_myPrivateHelloTool, "clonedPrivate", clonedPrivate).isSuccess())) { + ATH_MSG_FATAL("Error cloning " << m_myPrivateHelloTool.name()); + return StatusCode::FAILURE; + } + IHelloTool* clonedPublic(0); + if(!(CloneTool::clone(*m_myPublicHelloTool, "clonedPublic", clonedPublic).isSuccess())) { + ATH_MSG_FATAL("Error cloning " << m_myPublicHelloTool.name()); + return StatusCode::FAILURE; + } + + function_node<int,int>* pAdder = + new function_node<int,int>(m_graph, m_concurrency, + bind(&IHelloTool::addToIt, &*m_myPublicHelloTool, _1)); + m_nodes.push_back(pAdder); + + function_node<int,int>* pAdder2 = + new function_node<int,int>(m_graph, m_concurrency, + bind(&IHelloTool::addToIt, clonedPublic, _1)); + m_nodes.push_back(pAdder2); + + function_node<int,int>* pSubtracter = + new function_node<int,int>(m_graph, m_concurrency, + bind(&IHelloTool::addToIt, &*m_myPrivateHelloTool, _1)); + m_nodes.push_back(pSubtracter); + + function_node<int,int>* pSubtracter2 = + new function_node<int,int>(m_graph, m_concurrency, + bind(&IHelloTool::addToIt, clonedPrivate, _1)); + m_nodes.push_back(pSubtracter2); + + join_node< std::tuple<int,int,int>, queueing >* pJoiner = + new join_node< std::tuple<int,int,int>, queueing >(m_graph); + m_nodes.push_back(pJoiner); + + function_node< std::tuple<int,int,int>, int >* pSummer = + new function_node< std::tuple<int,int,int>, int >(m_graph, serial, Summer()); + m_nodes.push_back(pSummer); + + function_node< int >* pPrinter = + new function_node< int >(m_graph, serial, bind(&printGraphResult,_1)); + m_nodes.push_back(pPrinter); + + make_edge(m_input, *pAdder); + make_edge(m_input, *pAdder2); + make_edge(m_input, *pSubtracter); + make_edge(*pSubtracter, *pSubtracter2); + make_edge(*pAdder, input_port<0>(*pJoiner)); + make_edge(*pAdder2, input_port<1>(*pJoiner)); + make_edge(*pSubtracter2, input_port<2>(*pJoiner)); + make_edge(*pJoiner, *pSummer); + make_edge(*pSummer, *pPrinter); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloGraphAlg::execute() { + // Part 1: print where you are + ATH_MSG_INFO ("execute()"); + + for (size_t i=0; i<m_nIters; ++i) m_input.try_put(i); + m_graph.wait_for_all(); + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloGraphAlg::finalize() { + + // Part 1: print where you are + ATH_MSG_INFO ("finalize()"); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloGraphAlg::beginRun() { + // Part 1: print where you are + ATH_MSG_INFO ("beginRun()"); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloGraphAlg::endRun() { + // Part 1: print where you are + ATH_MSG_INFO ("endRun()"); + + return StatusCode::SUCCESS; +} diff --git a/Control/AthenaExamples/TBBExamples/src/HelloGraphAlg.h b/Control/AthenaExamples/TBBExamples/src/HelloGraphAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..8b6d58a8a84330e3b34998462e15aabfdd4100be --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/HelloGraphAlg.h @@ -0,0 +1,44 @@ +// -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHEXHELLOWORLD_HELLOGRAPHALG_H +#define ATHEXHELLOWORLD_HELLOGRAPHALG_H 1 + +#include "GaudiKernel/ToolHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" + +#include <string> + +#include "tbb/flow_graph.h" +#include "DataModel/DataVector.h" + +///////////////////////////////////////////////////////////////////////////// +// derived from http://threadingbuildingblocks.org/docs/help/reference/flow_graph/message_flow_graph_example.htm +class IHelloTool; + +class HelloGraphAlg : public AthAlgorithm { +public: + HelloGraphAlg( const std::string& name, ISvcLocator* pSvcLocator ); + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + StatusCode beginRun(); + StatusCode endRun(); + +private: + size_t m_nIters; ///property + size_t m_concurrency; ///property + + ToolHandle< IHelloTool > m_myPrivateHelloTool; + ToolHandle< IHelloTool > m_myPublicHelloTool; + + tbb::flow::graph m_graph; + tbb::flow::broadcast_node<int> m_input; + DataVector<tbb::flow::graph_node> m_nodes; +}; + +#endif // ATHEXHELLOWORLD_HELLOGRAPHALG_H diff --git a/Control/AthenaExamples/TBBExamples/src/HelloParForAlg.cxx b/Control/AthenaExamples/TBBExamples/src/HelloParForAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6d039ebbb8c1ce356a29a1f05ca8063207fef7ee --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/HelloParForAlg.cxx @@ -0,0 +1,154 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#define TBBDEBUG +// STL includes +#include <vector> +#include <string> +#include <sstream> +using namespace std; + +#include "TBBExamples/IHelloTool.h" +#include "HelloParForAlg.h" +#include "tbb/parallel_for.h" +#include "tbb/blocked_range.h" + +HelloParForAlg::HelloParForAlg(const string& name, ISvcLocator* pSvcLocator) : + AthAlgorithm(name, pSvcLocator), m_nIters(0), + m_myPrivateHelloTool("HelloTool",this), m_myPublicHelloTool("HelloTool") +{ + + // Part 2: Declare the properties + declareProperty("NIters", m_nIters); + + declareProperty("MyPrivateHelloTool", m_myPrivateHelloTool, "private IHelloTool"); + declareProperty("MyPublicHelloTool", m_myPublicHelloTool, "public, shared IHelloTool"); + +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloParForAlg::initialize() { + + // Part 1: print where you are + ATH_MSG_INFO ("initialize()"); + + ATH_MSG_INFO + (" " << m_myPrivateHelloTool.propertyName() + << " = " << m_myPrivateHelloTool.type() + << endreq + << " " << m_myPublicHelloTool.propertyName() + << " = " << m_myPublicHelloTool.type()); + + + // Part 3: Retrieve the tools using the ToolHandles + if ( m_myPrivateHelloTool.retrieve().isFailure() ) { + ATH_MSG_FATAL + (m_myPrivateHelloTool.propertyName() << ": Failed to retrieve tool " + << m_myPrivateHelloTool.type()); + return StatusCode::FAILURE; + } else { + ATH_MSG_INFO + (m_myPrivateHelloTool.propertyName() << ": Retrieved tool " + << m_myPrivateHelloTool.type()); + } + if ( m_myPublicHelloTool.retrieve().isFailure() ) { + ATH_MSG_FATAL + (m_myPublicHelloTool.propertyName() << ": Failed to retrieve tool " + << m_myPublicHelloTool); + return StatusCode::FAILURE; + } else { + ATH_MSG_INFO (m_myPublicHelloTool.propertyName() << ": Retrieved tool " + << m_myPublicHelloTool.type()); + } + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +class Filler { +private: + string m_initial; + vector<string>& m_toFill; +public: + Filler(const std::string& initial, vector<string>& toFill) : + m_initial(initial), m_toFill(toFill) {} + void operator() (const tbb::blocked_range<size_t>& r) const { +#ifdef TBBDEBUG + cout << "Filler grainsize " << r.end() - r.begin(); +#endif + for( size_t i=r.begin(); i!=r.end(); ++i ) { + stringstream ss; + ss << m_initial << ' ' << i << ':' <<ends; + m_toFill[i] = ss.str(); + } + } +}; + +class SayTools { +private: + SayTools(); + HelloParForAlg& m_host; + mutable int m_called; //this is because operator() in parallel_for is const + vector<string>& m_messages; +public: + SayTools(HelloParForAlg& alg, vector<string>& m): + m_host(alg), m_called(0), m_messages(m) {} + void operator() (const tbb::blocked_range<size_t>& r) const { +#ifdef TBBDEBUG + cout << "SayTools grainsize " << r.end() - r.begin(); +#endif + for( size_t i=r.begin(); i!=r.end(); ++i ) { + // Part 1a: Let publicly declared tool say something + StatusCode sc1 = m_host.m_myPublicHelloTool->saySomething(m_messages[i]); + // Part 1b: Let privately declared tool say something + StatusCode sc2 = m_host.m_myPrivateHelloTool->saySomething(m_messages[i]); + if ( sc1.isFailure() || sc2.isFailure() ) { + throw("bad news"); + } + } + ++m_called; + } +}; + +StatusCode HelloParForAlg::execute() { + + // Part 1: print where you are + ATH_MSG_INFO ("execute()"); + + vector<string> messages(m_nIters); + Filler f("Counting in element ", messages); + tbb::parallel_for(tbb::blocked_range<size_t>(0,m_nIters), f); + SayTools s(*this, messages); + tbb::parallel_for(tbb::blocked_range<size_t>(0,m_nIters), s); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloParForAlg::finalize() { + + // Part 1: print where you are + ATH_MSG_INFO ("finalize()"); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloParForAlg::beginRun() { + // Part 1: print where you are + ATH_MSG_INFO ("beginRun()"); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloParForAlg::endRun() { + // Part 1: print where you are + ATH_MSG_INFO ("endRun()"); + + return StatusCode::SUCCESS; +} diff --git a/Control/AthenaExamples/TBBExamples/src/HelloParForAlg.h b/Control/AthenaExamples/TBBExamples/src/HelloParForAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..54eb533cf2f0301a7a78a5d134c8cad51a0c77f8 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/HelloParForAlg.h @@ -0,0 +1,58 @@ +// -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHEXHELLOWORLD_HELLOPARFORALG_H +#define ATHEXHELLOWORLD_HELLOPARFORALG_H 1 + +#include "GaudiKernel/ToolHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" + +#include <string> +#include <vector> +#include <utility> +#include <map> + +///////////////////////////////////////////////////////////////////////////// +/** @class HelloPipeAlg + * @brief an algorithm that sets up and run a TBB parallel_for + * details on TBB pipeline at http://threadingbuildingblocks.org/codesamples.php#Using_parallel_for + * + * parallel_for is the most promising TBB pattern to exploit mini-core + * platforms such as MIC. No framework services should be accessed in the + * loop body which is implemented via a functor. Notice that the functor + * is not generally handled a single iteration of the loop but a subrange + * of the loop. + * + * @param NIters number of iteration in for loop + * + * @author Paolo Calafiura - ATLAS Collaboration + */ + + +class IHelloTool; + +class SayTools; + +class HelloParForAlg : public AthAlgorithm { +public: + HelloParForAlg( const std::string& name, ISvcLocator* pSvcLocator ); + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + StatusCode beginRun(); + StatusCode endRun(); + +private: + friend class SayTools; + int m_nIters; + + ToolHandle< IHelloTool > m_myPrivateHelloTool; + ToolHandle< IHelloTool > m_myPublicHelloTool; + +}; + +#endif // ATHEXHELLOWORLD_HELLOPARFORALG_H diff --git a/Control/AthenaExamples/TBBExamples/src/HelloPipeAlg.cxx b/Control/AthenaExamples/TBBExamples/src/HelloPipeAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e9043b22aafd085c7495c6ff96702c0f592370ee --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/HelloPipeAlg.cxx @@ -0,0 +1,151 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <iterator> +#include "TBBExamples/IHelloTool.h" +#include "HelloPipeAlg.h" + +HelloPipeAlg::HelloPipeAlg(const std::string& name, ISvcLocator* pSvcLocator) : + AthAlgorithm(name, pSvcLocator), m_nTokens(4), m_filterSerial(true), + m_myPrivateHelloTool("HelloTool",this), m_myPublicHelloTool("HelloTool"), m_pipeline() +{ + + declareProperty("NTokens", m_nTokens, + "number of tokens running through the pipeline"); + declareProperty("FilterSerial", m_filterSerial, + "control processing filters running mode"); + + declareProperty("MyPrivateHelloTool", m_myPrivateHelloTool, "private IHelloTool"); + declareProperty("MyPublicHelloTool", m_myPublicHelloTool, "public, shared IHelloTool"); + +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +class PipeInput : public tbb::filter { +private: + int m_nTokensToDo; + int m_nTokens; + std::string m_message; +public: + PipeInput(int nTokens) : tbb::filter(tbb::filter::serial_in_order), + m_nTokensToDo(nTokens-1), + m_nTokens(nTokens-1), m_message("Counting") {} + void resetNTokens() { m_nTokens = m_nTokensToDo; } + void * operator()(void*) { + return (void*) ((0 >= --m_nTokens) ? 0 : &m_message); + } +}; + + +class IHTPipeWrapper : public tbb::filter { +private: + IHelloTool& m_iht; +public: + IHTPipeWrapper(IHelloTool& wrapped, tbb::filter::mode tbbmod=tbb::filter::serial_in_order) : + tbb::filter(tbbmod), m_iht(wrapped) { + //std::cout << "IHTPipeWrapper created for tool " << m_iht.name() << std::endl; + + } + void * operator()(void* item) { + std::string& message(*(std::string*)item); + m_iht.saySomething(message).ignore(); + //this may be used to pass something to the next tool in the pipe. + //Not used in this simple example + return (void*) &message; + } +}; + + +StatusCode HelloPipeAlg::initialize() { + + // Part 1: print where you are + ATH_MSG_INFO ("initialize()"); + + ATH_MSG_INFO + (" " << m_myPrivateHelloTool.propertyName() + << " = " << m_myPrivateHelloTool.type() + << endreq + << " " << m_myPublicHelloTool.propertyName() + << " = " << m_myPublicHelloTool.type()); + + + // Part 3: Retrieve the tools using the ToolHandles + if ( m_myPrivateHelloTool.retrieve().isFailure() ) { + ATH_MSG_FATAL + (m_myPrivateHelloTool.propertyName() << ": Failed to retrieve tool " + << m_myPrivateHelloTool.type()); + return StatusCode::FAILURE; + } else { + ATH_MSG_INFO + (m_myPrivateHelloTool.propertyName() << ": Retrieved tool " + << m_myPrivateHelloTool.type()); + } + if ( m_myPublicHelloTool.retrieve().isFailure() ) { + ATH_MSG_FATAL + (m_myPublicHelloTool.propertyName() << ": Failed to retrieve tool " + << m_myPublicHelloTool); + return StatusCode::FAILURE; + } else { + ATH_MSG_INFO (m_myPublicHelloTool.propertyName() << ": Retrieved tool " + << m_myPublicHelloTool.type()); + } + //FIXME, this should be wrapped + tbb::filter::mode concMode(tbb::filter::parallel); + if (m_filterSerial) concMode=tbb::filter::serial_in_order; + m_pipeFilters.push_back(new PipeInput(m_nTokens)); + m_pipeline.add_filter(*(m_pipeFilters.back())); + m_pipeFilters.push_back(new IHTPipeWrapper(*m_myPublicHelloTool, concMode)); + m_pipeline.add_filter(*(m_pipeFilters.back())); + m_pipeFilters.push_back(new IHTPipeWrapper(*m_myPrivateHelloTool, concMode)); + m_pipeline.add_filter(*(m_pipeFilters.back())); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloPipeAlg::execute() { + + // Part 1: print where you are + ATH_MSG_INFO ("execute()"); + //FIXME no filter run!!! + m_pipeline.run(m_nTokens*4); + PipeInput* pinf(dynamic_cast<PipeInput*>(&*(m_pipeFilters.front()))); + if (pinf) { + pinf->resetNTokens(); + return StatusCode::SUCCESS; + } else { + return StatusCode::FAILURE; + } +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloPipeAlg::finalize() { + + // Part 1: print where you are + ATH_MSG_INFO ("finalize()"); + m_pipeline.clear(); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloPipeAlg::beginRun() { + // Part 1: print where you are + ATH_MSG_INFO ("beginRun()"); + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode HelloPipeAlg::endRun() { + // Part 1: print where you are + ATH_MSG_INFO ("endRun()"); + + return StatusCode::SUCCESS; +} diff --git a/Control/AthenaExamples/TBBExamples/src/HelloPipeAlg.h b/Control/AthenaExamples/TBBExamples/src/HelloPipeAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..6eb5769bad2ed87ca77bda250cf60f3068924aaf --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/HelloPipeAlg.h @@ -0,0 +1,58 @@ +// -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHEXHELLOWORLD_HELLOPIPEALG_H +#define ATHEXHELLOWORLD_HELLOPIPEALG_H 1 + +#include "GaudiKernel/ToolHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" + +#include <string> +#include <vector> +#include <utility> +#include <map> + +#include "DataModel/DataVector.h" +#include "tbb/pipeline.h" + +///////////////////////////////////////////////////////////////////////////// +/** @class HelloPipeAlg + * @brief an algorithm that sets up a TBB pipeline of AlgTools and runs it + * details on TBB pipeline at http://threadingbuildingblocks.org/codesamples.php#pipeline + * + * The interest of a pipeline may reside in the ability to keep serial mode + * running with small tasks (in terms of memory footprint) + * + * @param NTokens number of tokens flowing through the pipeline (per event) + * @param FilterSerial controls if processing filters run serially + * + * @author Paolo Calafiura - ATLAS Collaboration + */ + +class IHelloTool; + +class HelloPipeAlg : public AthAlgorithm { +public: + HelloPipeAlg( const std::string& name, ISvcLocator* pSvcLocator ); + StatusCode initialize(); + StatusCode execute(); + StatusCode finalize(); + + StatusCode beginRun(); + StatusCode endRun(); + +private: + int m_nTokens; ///property + bool m_filterSerial; ///property + + ToolHandle< IHelloTool > m_myPrivateHelloTool; + ToolHandle< IHelloTool > m_myPublicHelloTool; + + DataVector<tbb::filter> m_pipeFilters; + tbb::pipeline m_pipeline; +}; + +#endif // ATHEXHELLOWORLD_HELLOPIPEALG_H diff --git a/Control/AthenaExamples/TBBExamples/src/TBBTool.cxx b/Control/AthenaExamples/TBBExamples/src/TBBTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fdcacdc44c3974b9df8d83c3b3d3026be7931150 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/TBBTool.cxx @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TBBTool.h" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +TBBTool::TBBTool( const std::string& type, const std::string& name, + const IInterface* parent ) + : AthAlgTool( type, name, parent ), m_myMessage("Default message set in TBBTool.cxx"), m_increment(1), m_called(1) +{ + declareProperty( "MyMessage", m_myMessage, "something to say" ); + declareProperty( "MyIncrement", m_increment, "something to add" ); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode TBBTool::queryInterface( const InterfaceID& riid, void** ppvIf ) +{ + if ( riid == IHelloTool::interfaceID() ) { + *ppvIf = (IHelloTool*)this; + addRef(); + return StatusCode::SUCCESS; + } + + return AthAlgTool::queryInterface( riid, ppvIf ); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode TBBTool::saySomething(std::string& something) +{ + //wasting time trying to get slammed by another thread; + long long old_called = m_called; + something += " - " + m_myMessage; + double val = atan((double)m_called); + if (rand() > 0.5) val += atan((double)m_called/2.); + ATH_MSG_DEBUG ("message #" << m_called + << " to the world: " << something); + StatusCode c(StatusCode::SUCCESS); + m_called = old_called + (val == 0 ? 1 : round(val/val)); + return c; +} + +int TBBTool::addToIt(int soFar) { + ATH_MSG_DEBUG ("adding " << m_increment + << " to " << soFar); + return (soFar + m_increment); +} diff --git a/Control/AthenaExamples/TBBExamples/src/TBBTool.h b/Control/AthenaExamples/TBBExamples/src/TBBTool.h new file mode 100644 index 0000000000000000000000000000000000000000..fe74050407f07827a4e2ec40108ec04fc0609b82 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/TBBTool.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHEXHELLOWORLD_HELLOTOOL_H +#define ATHEXHELLOWORLD_HELLOTOOL_H 1 + +#include "AthenaBaseComps/AthAlgTool.h" +#include "TBBExamples/IHelloTool.h" + +#include <string> + +class TBBTool : virtual public IHelloTool, virtual public AthAlgTool { +public: + TBBTool( const std::string&, const std::string&, const IInterface* ); + +// to allow access to the IHelloTool interface + StatusCode queryInterface( const InterfaceID& riid, void** ppvIf ); + +// the magic method this tool provides + virtual StatusCode saySomething(std::string& something); + virtual int addToIt(int soFar); + +private: + std::string m_myMessage; + int m_increment; + int m_called; +}; + +#endif diff --git a/Control/AthenaExamples/TBBExamples/src/components/TBBExamples_entries.cxx b/Control/AthenaExamples/TBBExamples/src/components/TBBExamples_entries.cxx new file mode 100755 index 0000000000000000000000000000000000000000..3f374e6db5e92d469ba3899536f27fb4aa3d3885 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/components/TBBExamples_entries.cxx @@ -0,0 +1,21 @@ +#include "../HelloGraphAlg.h" +#include "../HelloParForAlg.h" +#include "../HelloPipeAlg.h" +#include "../TBBTool.h" +//#include "../HelloSvc.h" + +#include "GaudiKernel/DeclareFactoryEntries.h" + +DECLARE_ALGORITHM_FACTORY( HelloGraphAlg ) +DECLARE_ALGORITHM_FACTORY( HelloParForAlg ) +DECLARE_ALGORITHM_FACTORY( HelloPipeAlg ) +DECLARE_TOOL_FACTORY( TBBTool ) +//DECLARE_SERVICE_FACTORY( HelloSvc ) + +DECLARE_FACTORY_ENTRIES(TBBExamples) { + DECLARE_ALGORITHM( HelloGraphAlg ) + DECLARE_ALGORITHM( HelloParForAlg ) + DECLARE_ALGORITHM( HelloPipeAlg ) + DECLARE_TOOL( TBBTool ) + // DECLARE_SERVICE( HelloSvc ) +} diff --git a/Control/AthenaExamples/TBBExamples/src/components/TBBExamples_load.cxx b/Control/AthenaExamples/TBBExamples/src/components/TBBExamples_load.cxx new file mode 100755 index 0000000000000000000000000000000000000000..fcb9b84fc97be24322a3622bcec45c50cdd4aeba --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/src/components/TBBExamples_load.cxx @@ -0,0 +1,4 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(TBBExamples) + diff --git a/Control/AthenaExamples/TBBExamples/test/TBBExamples_TestConfiguration.xml b/Control/AthenaExamples/TBBExamples/test/TBBExamples_TestConfiguration.xml new file mode 100755 index 0000000000000000000000000000000000000000..c326a4cf6696e1e8477153e36631284d8aa499e7 --- /dev/null +++ b/Control/AthenaExamples/TBBExamples/test/TBBExamples_TestConfiguration.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<!DOCTYPE unifiedTestConfiguration SYSTEM "http://www.hep.ucl.ac.uk/atlas/AtlasTesting/DTD/unifiedTestConfiguration.dtd"> + +<unifiedTestConfiguration> + <atn> + <TEST name="TBBExamples" type="athena" suite="Examples"> + <options_atn>TBBExamples/HelloParForOptions.py</options_atn> + <timelimit>2</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov </mailto> + <expectations> + <errorMessage>FAILURE (ERROR)</errorMessage> + <successMessage></successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> + </atn> +</unifiedTestConfiguration>