From 319da689e634139c64cfe34fbe5404cfd5b32416 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Tue, 1 Mar 2016 17:59:24 +0100 Subject: [PATCH 01/17] Pipeline (alone - not integrated yet) --- livre/core/pipeline/Executable.h | 64 ++++++ livre/core/pipeline/Executor.h | 84 ++++++++ livre/core/pipeline/Filter.h | 78 +++++++ livre/core/pipeline/FunctionFilter.cpp | 88 ++++++++ livre/core/pipeline/FunctionFilter.h | 72 +++++++ livre/core/pipeline/Future.cpp | 81 ++++++++ livre/core/pipeline/Future.h | 109 ++++++++++ livre/core/pipeline/InputPort.cpp | 97 +++++++++ livre/core/pipeline/InputPort.h | 81 ++++++++ livre/core/pipeline/OutputPort.cpp | 188 +++++++++++++++++ livre/core/pipeline/OutputPort.h | 122 +++++++++++ livre/core/pipeline/PipeFilter.cpp | 256 +++++++++++++++++++++++ livre/core/pipeline/PipeFilter.h | 132 ++++++++++++ livre/core/pipeline/Pipeline.cpp | 197 ++++++++++++++++++ livre/core/pipeline/Pipeline.h | 111 ++++++++++ livre/core/pipeline/PortData.h | 96 +++++++++ livre/core/pipeline/PortFutures.cpp | 156 ++++++++++++++ livre/core/pipeline/PortFutures.h | 245 ++++++++++++++++++++++ livre/core/pipeline/PortInfo.h | 80 +++++++ livre/core/pipeline/PortPromises.cpp | 93 +++++++++ livre/core/pipeline/PortPromises.h | 88 ++++++++ livre/core/pipeline/PortType.h | 60 ++++++ livre/core/pipeline/Promise.cpp | 72 +++++++ livre/core/pipeline/Promise.h | 57 +++++ livre/core/pipeline/SimpleExecutor.cpp | 107 ++++++++++ livre/core/pipeline/SimpleExecutor.h | 70 +++++++ livre/core/pipeline/Workers.cpp | 120 +++++++++++ livre/core/pipeline/Workers.h | 68 ++++++ tests/pipeline/pipeline.cpp | 277 +++++++++++++++++++++++++ 29 files changed, 3349 insertions(+) create mode 100644 livre/core/pipeline/Executable.h create mode 100644 livre/core/pipeline/Executor.h create mode 100644 livre/core/pipeline/Filter.h create mode 100644 livre/core/pipeline/FunctionFilter.cpp create mode 100644 livre/core/pipeline/FunctionFilter.h create mode 100644 livre/core/pipeline/Future.cpp create mode 100644 livre/core/pipeline/Future.h create mode 100644 livre/core/pipeline/InputPort.cpp create mode 100644 livre/core/pipeline/InputPort.h create mode 100644 livre/core/pipeline/OutputPort.cpp create mode 100644 livre/core/pipeline/OutputPort.h create mode 100644 livre/core/pipeline/PipeFilter.cpp create mode 100644 livre/core/pipeline/PipeFilter.h create mode 100644 livre/core/pipeline/Pipeline.cpp create mode 100644 livre/core/pipeline/Pipeline.h create mode 100644 livre/core/pipeline/PortData.h create mode 100644 livre/core/pipeline/PortFutures.cpp create mode 100644 livre/core/pipeline/PortFutures.h create mode 100644 livre/core/pipeline/PortInfo.h create mode 100644 livre/core/pipeline/PortPromises.cpp create mode 100644 livre/core/pipeline/PortPromises.h create mode 100644 livre/core/pipeline/PortType.h create mode 100644 livre/core/pipeline/Promise.cpp create mode 100644 livre/core/pipeline/Promise.h create mode 100644 livre/core/pipeline/SimpleExecutor.cpp create mode 100644 livre/core/pipeline/SimpleExecutor.h create mode 100644 livre/core/pipeline/Workers.cpp create mode 100644 livre/core/pipeline/Workers.h create mode 100644 tests/pipeline/pipeline.cpp diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h new file mode 100644 index 00000000..a56ff255 --- /dev/null +++ b/livre/core/pipeline/Executable.h @@ -0,0 +1,64 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _Executable_h_ +#define _Executable_h_ + +#include +#include +#include + +namespace livre +{ + +/** + * The Executable class is the base class for objects that can be executed by workers. + */ +class Executable +{ +public: + + Executable() {} + /** + * Executes the executable + */ + virtual void execute() = 0; + + /** + * @return the input futures which the executable provides to wait. The + * names of the futures are unique. + */ + virtual ConstFutures getOutputFutures() const { return ConstFutures(); } + + /** + * @return the input futures which the executable is waiting to proceed. + * The names of the futures not necessarily unique. The inputs accepts + * multiple outputs with the same name. + */ + virtual ConstFutures getInputFutures() const { return ConstFutures(); } + +protected: + + virtual ~Executable() {} +}; + +} + +#endif // _Executable_h_ + diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h new file mode 100644 index 00000000..ebf7d674 --- /dev/null +++ b/livre/core/pipeline/Executor.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _Executor_h_ +#define _Executor_h_ + +#include + +namespace livre +{ + + +/** + * Executor class is the base class for implementing different scheduling + * algorithms for submited work. i.e. The IO or CPU intensive algorithms + * can implement their own scheduling algorithms. + */ +class Executor +{ +public: + + virtual ~Executor() {} + + /** + * Executes the executable. Returns the futures that can be queried for data. + * @param pipeline to be executed. + */ + PortFutures execute( ExecutablePtr executable ) + { + const ConstFutures& fs = _executable->getOutputFutures(); + _schedule( { executable } ); + return PortFutures( fs ); + } + + /** + * Executes the executable. Returns the futures that can be queried for data. + * @param pipeline to be executed. + */ + PortFutures execute( const Executables& executables ) + { + ConstFutures futures; + for( const ExecutablePtr& executable: executables ) + { + const ConstFutures& fs = executable->getOutputFutures(); + futures.insert( futures.back(), fs.begin(), fs.end( )); + } + + _schedule( executables ); + return PortFutures( futures ); + } + +protected: + + /** + * Schedules the executables for execution + * @param executables are the executables to schedule. + */ + virtual void _schedule( const Executables& executables ) = 0; + + /** + * Clears the executor + */ + virtual void clear() {} +}; + +} + +#endif // _Executor_h_ diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h new file mode 100644 index 00000000..1132f8ab --- /dev/null +++ b/livre/core/pipeline/Filter.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _Filter_h_ +#define _Filter_h_ + +#include +#include +#include +#include +#include + +namespace livre +{ + +/** + * Filters are similar to functions. Their inputs and + * outputs are provided through ports. These ports provide + * thread safe information retrieval, setting and querying. + * + * One input port may have many incoming connections and one output + * port can be connected to many other input connections. The ports + * have their unique names and these names are used to query, + * retrieve and set data. + * + * Execution part of filters can be thought as functions and + * port definitions can be thought as inputs and outputs to + * those functions. PipeFilters build the connection and execution + * functionality around filter instances. + */ + +class Filter +{ +public: + + /** + * This function is called by the @PipeFilter while the filter + * is being executed. + * @param input The Future that can be read for input parameters + * @param output The Promise that can be written to for output parameters + */ + virtual void execute( const InputPortFutures& input, PortPromises& output ) const = 0; + + /** + * @param inputPorts information is filled by the Filter class. + * These ports are constructed by the @PipeFilter. + */ + virtual PortInfos getInputPorts() const { return PortInfos(); } + + /** + * @param outputPorts information is filled by the Filter class. + * Afterwards, these ports are instantiated by the @PipeFilter. + */ + virtual PortInfos getOutputPorts() const { return PortInfos(); } + + virtual ~Filter() {} +}; + +} + +#endif // _Filter_h_ + diff --git a/livre/core/pipeline/FunctionFilter.cpp b/livre/core/pipeline/FunctionFilter.cpp new file mode 100644 index 00000000..f90951f0 --- /dev/null +++ b/livre/core/pipeline/FunctionFilter.cpp @@ -0,0 +1,88 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +namespace livre +{ + +struct FunctionFilter::Impl +{ + Impl( const FilterFunc& filterFunc, + const PortInfos& inputPorts, + const PortInfos& outputPorts ) + : _filterFunc( filterFunc ) + , _inputPorts( inputPorts ) + , _outputPorts( outputPorts ) + {} + + void execute( const PortFutures& input, PortPromises& output ) const + { + _filterFunc( filter ); + } + + PortInfos getInputPorts() const + { + return _inputPorts; + } + + PortInfos getInputPorts() const + { + return _outputPorts; + } + +private: + + + FilterFunc _filterFunc; + const PortInfos _inputPorts; + const PortInfos _outputPorts; +}; + +FunctionFilter::FunctionFilter( const FilterFunc& filterFunc, + const PortInfos& inputPorts, + const PortInfos& outputPorts ) + : _impl( new FunctionFilter::Impl( filterFunc, + inputPorts, + outputPorts )) +{} + +FunctionFilter::~FunctionFilter() +{} + +void FunctionFilter::execute( const PortFutures& input, PortPromises& output ) const +{ + _impl->execute( input, output ); +} + +PortInfos FunctionFilter::getInputPorts() const +{ + _impl->getInputPorts(); +} + +PortInfos FunctionFilter::getOutputPorts( ) const +{ + _impl->getOutputPorts(); +} + +} + + + diff --git a/livre/core/pipeline/FunctionFilter.h b/livre/core/pipeline/FunctionFilter.h new file mode 100644 index 00000000..3d58a103 --- /dev/null +++ b/livre/core/pipeline/FunctionFilter.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _FunctionFilter_h_ +#define _FunctionFilter_h_ + +#include +#include + +namespace livre +{ + +/** + * The FunctionFilter class is used to create filters based + * on filter function definitions. i.e. A class can implement + * a filter by using a function. + */ +struct FunctionFilter final : public Filter +{ + /** + * Constructs a filter based on function object. + * @param filterFunc The filter function object. + * @param inputPorts are the input ports information. + * @param outputPorts are the output ports information. + */ + FunctionFilter( const FilterFunc& filterFunc, + const PortInfos& inputPorts, + const PortInfos& outputPorts ); + ~FunctionFilter(); + + /** + * @copydoc Filter::execute( PipeFilter& filter ) + */ + void execute( const PortFutures& input, PortPromises& output ) const final; + + /** + * @copydoc Filter::getInputPorts() + */ + PortInfos getInputPorts() const final; + + /** + * @copydoc Filter::getOutputPorts() + */ + PortInfos getOutputPorts() const final; + +private: + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _FunctionFilter_h_ + + diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp new file mode 100644 index 00000000..59b706e5 --- /dev/null +++ b/livre/core/pipeline/Future.cpp @@ -0,0 +1,81 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +namespace livre +{ + +struct Future::Impl +{ + Impl( const AsyncData& data ) + : _data( data ) + {} + + const std::string& getName() const + { + return _data.getName(); + } + + void set( const ConstPortDataPtr& data ) + { + _data.set( data ); + } + + ConstPortDataPtr get() const + { + return _data.get(); + } + + const AsyncData& _data; +}; + +Future::Future( const AsyncData& data ) + : _impl( new Future::Impl( data )) +{} + +Future::~Future() +{} + +const AsyncData& Future::getAsyncData() const +{ + return _impl->_data; +} + +const std::string& Future::getName() const +{ + return _impl->getName(); +} + +bool Future::isReady() const +{ + return _impl->isReady(); +} + +void Future::_set( const ConstPortDataPtr& data ) +{ + _impl->set( data ); +} + +ConstPortDataPtr Future::_get() const +{ + return _impl->get(); +} + +} diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h new file mode 100644 index 00000000..2a465923 --- /dev/null +++ b/livre/core/pipeline/Future.h @@ -0,0 +1,109 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _Future_h_ +#define _Future_h_ + +#include + +namespace livre +{ + +class Future +{ +public: + + Future( const AsyncData& data ); + ~Future(); + + /** + * @return the async data implementation + */ + const AsyncData& getAsyncData() const; + + /** + * @return name of the future + */ + const std::string& getName() const; + + /** + * Gets the value with the given type T. If output is not set + * this function will block. + * @return the value. + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + const T& get() const + { + typedef typename std::remove_const::type UnconstT; + const auto& dataPtr = + boost::dynamic_pointer_cast< const PortDataT< UnconstT >>( _get( )); + + if( !dataPtr ) + LBTHROW( std::runtime_error( "Invalid data type" )); + + return dataPtr->data; + } + + /** + * Moves the value with the given type T. If output is not set + * this function will block. + * @return the value. + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + const T&& move() const + { + typedef typename std::remove_const::type UnconstT; + const auto& dataPtr = + boost::dynamic_pointer_cast< const PortDataT< UnconstT >>( _get( )); + + if( !dataPtr ) + LBTHROW( std::runtime_error( "Invalid data type" )); + + return std::move( dataPtr->data ); + } + + /** + * Waits until the data is ready. + */ + void wait() const; + + /** + * @return true if port is ready for data retrieval. + */ + bool isReady() const; + +private: + + friend livre::waitForAny( const ConstFutures& future ); + + void _set( const ConstPortDataPtr& data ); + ConstPortDataPtr _get() const; + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _Future_h_ + diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp new file mode 100644 index 00000000..c2e73b8b --- /dev/null +++ b/livre/core/pipeline/InputPort.cpp @@ -0,0 +1,97 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +namespace livre +{ + +struct InputPort::Impl +{ + Impl( InputPort& inputPort, + const PortInfo& info ) + : _inputPort( inputPort ) + , _info( info ) + {} + + ~Impl() + {} + + const std::string& getName() const + { + return _info.portName; + } + + size_t getSize() const + { + return _futures.size(); + } + + const std::type_index& getDataType() const + { + return _info.getDataType(); + } + + void connect( const OutputPort& outputPort ) + { + if( getDataType() != outputPort->getDataType( )) + LB_THROW( std::exception( "Data types does not match between ports")); + + _futures.push_back( outputPort.getPromise()-getFuture( )); + } + + ConstFutures _futures; + const PortInfo _info; +}; + +InputPort::InputPort( const PortInfo& portInfo ) + : _impl( new InputPort::Impl( portInfo )) +{} + +InputPort::~InputPort() +{} + +ConstFutures InputPort::getFutures() const +{ + return _impl->getFutures(); +} + +void InputPort::connect( const OutputPort& outputPort ) +{ + _impl->connect( outputPort ); +} + +const std::string& InputPort::getName() const +{ + return _impl->getName(); +} + +const std::type_index& InputPort::getDataType() const +{ + return _impl->getDataType(); +} + +size_t InputPort::getSize() const +{ + return _impl->getSize(); +} + + +} diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h new file mode 100644 index 00000000..2ee30a55 --- /dev/null +++ b/livre/core/pipeline/InputPort.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _InputPort_h_ +#define _InputPort_h_ + +#include +#include +#include +#include + +namespace livre +{ + +/** + * InputPort class implements the input port to a @PipeFilter. It + * provides thread safe query and retrieval. + */ +class InputPort +{ +public: + + /** + * InputPort constructor based on port information + * @param portInfo is the port information + */ + InputPort( const PortInfo& portInfo ); + ~InputPort(); + + /** + * @return name of the port + */ + const std::string& getName() const; + + /** + * @return data type of the port + */ + const std::type_index& getDataType() const; + + /** + * @return the number of the inputs to the port + */ + size_t getSize() const; + + /** + * @return Return all the input futures that port has. + */ + ConstFutures getFutures() const; + + /** + * Connects an output port to input port + * @param inputPort input port + */ + void connect( const OutputPort& inputPort ); + +private: + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _InputPort_h_ + diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp new file mode 100644 index 00000000..d9ec304c --- /dev/null +++ b/livre/core/pipeline/OutputPort.cpp @@ -0,0 +1,188 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include + +#include + +namespace livre +{ + +typedef boost::shared_future< ConstPortDataPtr > ConstPortDataFuture; +typedef boost::promise< ConstPortDataPtr > ConstPortDataPromise; + +typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; +typedef std::vector< ConstPortDataPromise > ConstPortDataPromises; + +struct OutputPort::Impl +{ + Impl( const PortInfo& portInfo ) + : _info( portInfo ) + , _data( portInfo.name ) + , _portPromise( new PortPromise( _data )) + {} + + ~Impl() + { + flush(); + } + + void flush() + { + _data.set( ConstPortDataPtr( )); + } + + const std::string& getName() const + { + return _info.portName; + } + + PortInfo _info; + AsyncData _data; + PromisePtr _portPromise; +}; + +OutputPort::OutputPort( const PortInfo& portInfo ) + : _impl( new OutputPort::Impl( portInfo )) +{} + + +OutputPort::~OutputPort() +{} + +const std::string& OutputPort::getName() const +{ + return _impl->getName(); +} + +const std::type_index& OutputPort::getDataType() const +{ + return _impl->_info.getDataType(); +} + +ConstFuturePtr OutputPort::getFuture() const +{ + return _impl->_portFuture; +} + +PromisePtr OutputPort::getPromise() const +{ + return _impl->_portPromise; +} + +void OutputPort::connect( InputPort& inputPort ) +{ + _inputPort->connect( *this ); +} + +struct AsyncData::Impl +{ + Impl( const std::string name ) + : _future( _promise.get_future( )) + , _name( name ) + {} + + ~Impl() + { + if( !isReady()) + _promise.set_value( result ); + } + + ConstPortDataPtr get() const + { + return _future.get(); + } + + void set( const ConstPortDataPtr& data ) + { + if( result ) + { + if( data->getDataType() != _info->getDataType( )) + LBTHROW( std::runtime_error( "Types does not match on set value")); + } + + if( !isReady()) + _promise.set_value( result ); + } + + bool isReady() const + { + return _future.is_ready(); + } + + void wait() const + { + _future.wait(); + } + + ConstPortDataPromise _promise; + mutable ConstPortDataFuture _future; + const std::string _name; +}; + +AsyncData::AsyncData( const std::string& name ) + : AsyncData( name ) + , _impl( new Impl( )) +{} + +ConstPortDataPtr AsyncData::get() const +{ + return _impl->get(); +} + +const std::string& AsyncData::getName() const +{ + return _impl->_name; +} + +void AsyncData::set( const ConstPortDataPtr& data ) +{ + _impl->set( data ); +} + +bool AsyncData::isReady() const +{ + return _impl->isReady(); +} + +void AsyncData::wait() const +{ + _impl->wait(); +} + +bool waitForAny( const ConstFutures& futures ) +{ + ConstPortDataFutures futures; + for( const auto& future: futures ) + { + if( !future->isReady()) + futures.push_back( future->getAsyncData()._impl->_future ); + } + + if( futures.empty( )) + return false; + + boost::wait_for_any( futures.begin(), futures.end( )); + return true; +} + +} diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h new file mode 100644 index 00000000..9fc1ce29 --- /dev/null +++ b/livre/core/pipeline/OutputPort.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _OutputPort_h_ +#define _OutputPort_h_ + +#include + +namespace livre +{ + +/** + * The AsyncData class provides thread safe operations on data setting/retrieval/querying + * based on boost::shared_future ( boost::wait_for_any is not supported by std yet ). + */ +class AsyncData +{ +public: + + /** + * When connection is instantiated the data is not + * set yet, so any get() call will block the retrieval + * @param name of the connection + */ + AsyncData( const std::string& name ); + + /** + * @return the name of the connection + */ + const std::string& getName() const; + + /** + * @param data sets the data + */ + void set( ConstPortDataPtr data ); + + /** + * @return the data. If data is not set it will block. + */ + ConstPortDataPtr get() const; + + /** + * @return true if data is set. + */ + bool isReady() const; + + /** + * Waits until data is set + */ + void wait() const; + +private: + + /** + * Waits for any future to be ready. + * @param futures queried to be ready. + * @note this function needs internal access to the futures ( which is not exposed in the API ). + * @return true if any new futures are ready. + */ + friend bool waitForAny( const ConstFutures& futures ); + + struct Impl; + std::unique_ptr _impl; +}; + +class OutputPort +{ + +public: + + OutputPort( const PortInfo& portInfo ); + ~OutputPort(); + + /** + * @return name of the port + */ + const std::string& getName() const; + + /** + * @return data type of the port + */ + const std::type_index& getDataType() const; + + /** + * @return the promise, that data can be written to + */ + PromisePtr getPromise() const; + + /** + * Connects an output port to input port + * @param inputPort input port + */ + void connect( InputPort& inputPort ); + +private: + + struct Impl; + std::unique_ptr _impl; +}; + +bool waitForAny( const ConstFutures& futures ); + +} + +#endif // _OutputPort_h_ + diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp new file mode 100644 index 00000000..d8a8b3bf --- /dev/null +++ b/livre/core/pipeline/PipeFilter.cpp @@ -0,0 +1,256 @@ + +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace livre +{ + +struct PipeFilter::Impl +{ + Impl( PipeFilter& pipeFilter, + const std::string& name, + FilterPtr filter ) + : _pipeFilter( pipeFilter ) + , _name( name ) + , _id( servus::make_UUID( )) + , _filter( filter ) + { + addPorts( filter->getInputPorts(), + filter->getOutputPorts( )); + } + + Impl( PipeFilter& pipeFilter, + const std::string& name, + const FilterFunc& filterFunc, + const PortInfos& inputPorts, + const PortInfos& outputPorts ) + : _pipeFilter( pipeFilter ) + , _name( name ) + , _id( servus::make_UUID( )) + , _filter( new FunctionFilter( filterFunc, + inputPorts, + outputPorts )) + { + addPorts( inputPorts, outputPorts ); + } + + + bool hasInputPort( const std::string& portName ) const + { + return _inputMap.count( portName ) > 0; + } + + bool hasOutputPort( const std::string& portName ) const + { + return _outputMap.count( portName ) > 0; + } + + void throwError( const std::string& portName ) const + { + LBTHROW( std::runtime_error( std::string( "There is no port with name: ") + + portName )); + } + + void addPorts( const PortInfos& iPortInfos, const PortInfos& oPortInfos ) + { + for( const PortInfo& portInfo: iPortInfos ) + _inputMap[ portInfo.name ] = new InputPort( portInfo ); + + for( const PortInfo& portInfo: oPortInfos ) + _outputMap[ portInfo.name ] = new OutputPort( portInfo ); + + // Connect notification ports + _inputMap[ _id.getString( )] = + new InputPort( makePortInfo< ConstPortDataPtr >( _id.getString( ))); + _outputMap[ _id.getString( )] = + new OutputPort( makePortInfo< ConstPortDataPtr >( _id.getString( ))); + } + + void execute() + { + lunchbox::Strings& inputNames; + const ConstFutures& inputFutures = getInputFutures( inputNames ); + + InputPorts ports; + for( auto pair: _inputMap ) + ports.push_back( pair.second ); + + const InputPortFutures futures( ports ); + PortPromises promises( getOutputPromises( )); + _filter->execute( futures, promises ); + promises.flush(); + } + + Promises getInputPromises() + { + Promises promises; + for( auto pair: _inputMap ) + { + InputPortPtr& inputPort = pair.second; + if( _outputsToInputMap.getCount( inputPort->getName( )) == 0 && + inputPort->getSize() == 0 && inputPort->getName() != _id.getString( )) + { + OutputPortPtr outputPort( new OutputPort( + makePortInfo( inputPort->getName(), + inputPort->getDataType( )))); + _outputsToInputMap[ inputPort->getName() ] = outputPort; + promises.push_back( outputPort->getPromise( )); + } + } + + return promises; + } + + Promises getOutputPromises() const + { + Promises promises; + promises.reserve( _outputPorts.size( )); + for( const auto& pair: _outputMap ) + promises.push_back( pair.second->getPromise( )); + + return promises; + } + + ConstFutures getOutputFutures() const + { + for( const auto& pair: _outputPorts ) + { + ConstFuturePtr outputFuture = pair.second->getPromise()->getFuture(); + futures.push_back( outputFuture ); + } + return futures; + } + + ConstFutures getInputFutures( lunchbox::Strings& names ) const + { + ConstFutures futures; + for( const auto& pair: _inputPorts ) + { + ConstFutures inputFutures = port->getFutures(); + futures.insert( futures.end(), inputFutures.begin(), inputFutures.end( )); + names.push_back( pair.second->getName( )) + } + return futures; + } + + void connect( const std::string& srcPortName, + PipeFilterPtr dst, + const std::string& dstPortName ) + { + if( !hasOutputPort( srcPortName )) + throwError( srcPortName ); + + if( !dst->_impl.hasInputPort( dstPortName )) + throwError( dstPortName ); + + _outputMap[ srcPortName ]->connect( *dst->_impl->inputMap[ dstPortName ] ) + } + + void PipeFilter::connect( PipeFilterPtr dst ) + { + OutputPortPtr outputPort = _outputMap[ _id.getString() ]; + InputPortPtr inputPort = dst->_impl->_inputMap[ dst->_impl->_id.getString() ]; + inputPort->connect( *outputPort ); + } + + PipeFilter& _pipeFilter; + const std::string _name; + const servus::uint128_t _id; + FilterPtr _filter; + InputPortMap _inputMap; + OutputPortMap _outputMap; + OutputPortMap _outputsToInputMap; +}; + +PipeFilter::PipeFilter( const std::string& name, + FilterPtr filter ) + : _impl( new PipeFilter::Impl( *this, name, filter )) + , Executable( _impl->_promise ) +{} + +PipeFilter::PipeFilter( const std::string& name, + const FilterFunc& func, + const PortInfos& inputPorts, + const PortInfos& outputPorts ) + : _impl( new PipeFilter::Impl( *this, + name, + func, + inputPorts, + outputPorts )) + , Executable( _filterOutput.getPorts( )) +{} + +PipeFilter::~PipeFilter() +{} + +void PipeFilter::execute() +{ + _impl->execute(); +} + +const servus::uint128_t& PipeFilter::getId() const +{ + return _impl->_id; +} + +const std::string& PipeFilter::getName() const +{ + return _impl->_name; +} + +ConstFutures PipeFilter::getInputFutures() const +{ + lunchbox::Strings& names; + return _impl->getInputFutures( names ); +} + +Promises PipeFilter::getPromises() +{ + return _impl->getInputPromises(); +} + +ConstFutures PipeFilter::getOutputFutures() const +{ + return _impl->getOutputFutures(); +} + +void PipeFilter::connect( const std::string& srcPortName, + PipeFilterPtr dst, + const std::string& dst ) +{ + _impl->connect( srcPortName, dst, dst ); +} + +void PipeFilter::connect( PipeFilterPtr dst ) +{ + _impl->connect( dst ); +} + +} diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h new file mode 100644 index 00000000..d794690d --- /dev/null +++ b/livre/core/pipeline/PipeFilter.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _PipeFilter_h_ +#define _PipeFilter_h_ + +#include +#include +#include +#include +#include +#include +#include + +namespace livre +{ + +/** + * PipeFilter class instantiates the @Filter classes by constructing + * the communication layer around the filter. While adding the ports, + * it add its name as prefix to port name. i.e. if the name of the + * pipefilter is "Rescale" and output port name for the filter is "Volume" + * the port will be named as + */ +class PipeFilter : public Executable +{ +public: + + /** + * Constructs a PipeFilter with a given filter + * @param name of the pipefilter + * @param filter the filter object + */ + PipeFilter( const std::string& name, + FilterPtr filter ); + + /** + * Constructs a PipeFilter with a given filter function + * @param name of the pipefilter + * @param func is the filter function object + * @param inputPorts input ports + * @param outputPorts output ports + */ + PipeFilter( const std::string& name, + const FilterFunc& func, + const PortInfos& inputPorts, + const PortInfos& outputPorts ); + + ~PipeFilter(); + + /** + * Executes the filter. If a filter input port is + * connected and no input is provided to the port + * the execution will block. + */ + void execute() final; + + /** + * @return the unique name of the filter. + */ + const std::string& getName() const; + + /** + * Connect to given pipe filter with the given port names. Both filters + * should have the same port data type. + * @param srcPortName is the source pipe filter. + * @param dst is the destination pipe filter. + * @param dstPortName connection port name. + * @throws std::exception if connection can not be established + */ + void connect( const std::string& srcPortName, + PipeFilterPtr dst, + const std::string& dstPortName ); + + /** + * Connect to given pipe filter for notification when source filter execution + * is complete. + * @param dst is the destination pipe filter. + * @return true if connection is successful. + * @throws std::exception if connection can not be established + */ + void connect( PipeFilterPtr dst ); + + /** + * @copydoc Executable::getOutputFutures() + */ + ConstFutures getOutputFutures() const final; + + /** + * @copydoc Executable::getInputFutures() + * @note PipeFilter guarantees that only connected input futures are returned. + */ + ConstFutures getInputFutures() const final; + + /** + * @return return inputs for the pipe filter. + */ + Promises getPromises(); + + /** + * @return the unique id of the filter. + */ + const servus::uint128_t& getId() const; + +private: + + friend class Pipeline; + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _PipeFilter_h_ + diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp new file mode 100644 index 00000000..755dfb85 --- /dev/null +++ b/livre/core/pipeline/Pipeline.cpp @@ -0,0 +1,197 @@ + +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace livre +{ + +struct Pipeline::Impl +{ + typedef std::map< std::string, ConstPipelinePtr > PipelineMap; + typedef std::map< std::string, ConstPipeFilterPtr > PipeFilterMap; + + Impl( Pipeline& pipeline ) + : _pipeline( pipeline ) + {} + + PipeFilterPtr add( const std::string& name, + const FilterFunc& filterFunc, + const PortInfos& inputPorts, + const PortInfos& outputPorts, + bool wait ) +{ + FilterPtr filter( new FunctionFilter( filterFunc, + inputPorts, + outputPorts )); + return add( name, filter, wait ); + } + + PipeFilterPtr add( const std::string& name, + FilterPtr filter, + bool wait ) + { + if( _filters.count( name ) > 0 || _pipelines.count( name )) + LBTHROW( std::runtime_error( name + " already exists")); + + PipeFilterPtr pipefilter( new PipeFilter( name, filter )); + _filters[ name ] = pipefilter; + if( wait ) + { + const PortFutures portFutures( pipefilter->getOutputFutures( )); + _waitFutures.push_back( portFutures.getFutures( pipefilter->getId().getString( ))); + } + } + + void add( const std::string& name, + const ConstPipelinePtr& pipeline, + bool wait ) + { + if( pipeline.get() == _pipeline ) + return; + + _pipelines[ name ] = pipeline; + + if( wait ) + { + const ConstFutures& futures = pipeline->getOutputFutures(); + _waitFutures.insert( _waitFutures.end(), futures.begin(), futures.end( )); + } + } + + void execute() + { + Executables executables = getExecutables(); + Executables::iterator it = executables.begin(); + while( !executables.empty()) + { + ExecutablePtr executable = *it; + const PortFutures portFutures( executable->getInputFutures( )); + if( portFutures.isReady( )) + { + executable->execute(); + executables.erase( it ); + it = executables.begin(); + } + else + { + if( it == executables.end( )) + break; + ++it; + } + } + } + + Executables getExecutables() const + { + Executables executables; + executables.reserve( _filters.size() + _pipelines.size( )); + + for( auto pair: _filters ) + executables.push_back( pair.second ); + + for( auto pair: _pipelines ) + executables.push_back( pair.second ); + + return executables; + } + + ConstFutures getInputFutures() const + { + return ConstFutures(); + } + + ConstFutures getOutputFutures() const + { + return _waitFutures; + } + + ~Impl() + {} + + Pipeline& _pipeline; + PipeFilterMap _filters; + PipelineMap _pipelines; + ConstFutures _waitFutures; +}; + +Pipeline::Pipeline() + : _impl( new Pipeline::Impl( this )) +{ +} + +Pipeline::~Pipeline() +{} + +void Pipeline::add( const std::string& name, + PipelinePtr pipeline, + bool wait ) +{ + return _impl->addPipeline( name, pipeline, wait ); +} + +PipeFilterPtr Pipeline::add( const std::string& name, + FilterPtr filter, + bool wait ) +{ + return _impl->add( name, filter, wait ); +} + +PipeFilterPtr Pipeline::add( const std::string& name, + const FilterFunc& filterFunc, + const PortInfos& inputPorts, + const PortInfos& outputPorts, + bool wait ) +{ + return _impl->add( name, + filterFunc, + inputPorts, + outputPorts, + wait ); +} + +Executables Pipeline::getExecutables() const +{ + return _impl->getExecutables(); +} + +void Pipeline::execute() +{ + return _impl->execute(); +} + +ConstFutures Pipeline::getInputFutures() const +{ + return _impl->getInputFutures(); +} + +ConstFutures Pipeline::getOutputFutures() const +{ + return _impl->getOutputFutures(); +} + +} diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h new file mode 100644 index 00000000..dcf13462 --- /dev/null +++ b/livre/core/pipeline/Pipeline.h @@ -0,0 +1,111 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _Pipeline_h_ +#define _Pipeline_h_ + +#include +#include +#include + +namespace livre +{ + +/** + * Pipeline represents a filter graph. On asynchronous + * execution through the Executor, the status of the + * execution can be queried whether the execution is + * complete or not. + */ +class Pipeline : public Executable +{ + +public: + + Pipeline(); + ~Pipeline(); + + /** + * Adds a pipeline to be executed. + * @param pipeline is added to list of executables + * @param wait If true, on asynchronous execution, pipeline + * can wait on given pipeline. + */ + void add( const std::string& name, + PipelinePtr pipeline, + bool wait = true ); + + /** + * Adds a filter to be executed + * @param filter is added to list of executables. + * @param wait If true, on asynchronous execution, pipeline + * can wait on given filter. + * @return returns the generated pipe filter. + */ + PipeFilterPtr add( const std::string& name, + FilterPtr filter, + bool wait = true ); + + /** + * Adds a filter function to be executed + * @param filterFunc is the filter function object. + * @param inputPorts are the input ports information. + * @param outputPorts are the output ports information. + * @param wait If true, on asynchronous execution, pipeline + * can wait on given filter function. + * @return returns the generated pipe filter. + */ + PipeFilterPtr add( const std::string& name, + const FilterFunc& filterFunc, + const PortInfos& inputPorts, + const PortInfos& outputPorts, + bool wait = true ); + + /** + * @return the list of all executables ( pipe filters and + * pipelines ) + */ + Executables getExecutables() const; + +private: + + /** + * Executes each executable element in the graph + * synchronously. + */ + void _execute() final; + + /** + * @return Returns the writable future + */ + ConstFutures getInputFutures() const final; + + /** + * @return Returns the writable future + */ + ConstFutures getOutputFutures() const final; + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _Pipeline_h_ + diff --git a/livre/core/pipeline/PortData.h b/livre/core/pipeline/PortData.h new file mode 100644 index 00000000..ea652aa1 --- /dev/null +++ b/livre/core/pipeline/PortData.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _PortData_h_ +#define _PortData_h_ + +#include + +#include "PortType.h" + +namespace livre +{ + +/** + * PortData class is base class for keeping the track for types + * by using the std::type_index. + */ +class PortData : public PortType +{ +protected: + PortData( const std::type_index& typeIndex ) + : PortType( typeIndex) {} + virtual ~PortData() {} +}; + +/** + * Holds the T typed data. + */ +template< class T> +struct PortDataT final : public PortData +{ + explicit PortDataT( const T& data_ ) + : PortData( std::type_index( typeid( T ))) + , data( data_ ) + {} + + explicit PortDataT( const T&& data_ ) + : PortData( std::type_index( typeid( T ))) + , data( std::move( data_ )) + {} + + ~PortDataT() {} + const T data; +}; + +template +using PortDataTPtr = boost::shared_ptr< PortDataT< T >>; + +template +using ConstPortDataTPtr = boost::shared_ptr< PortDataT< T >>; + +template +using PortDataTPtrs = std::vector< PortDataTPtr< T >>; + +template +using ConstPortDataTPtrs = std::vector< ConstPortDataTPtr< T >>; + +/** + * Constructs a PortDataTPtr object from type T + */ +template< class T > +PortDataTPtr< T > makePortDataPtr( const T& data ) +{ + return boost::make_shared< PortDataT< T >>( data ); +} + +/** + * Constructs a PortDataTPtr object from type T. + * Moves the to the port data. + */ +template< class T > +PortDataTPtr< T > makePortDataPtr( const T&& data ) +{ + return boost::make_shared< PortDataT< T >>( data ); +} + +} + +#endif // _PortData_h_ + diff --git a/livre/core/pipeline/PortFutures.cpp b/livre/core/pipeline/PortFutures.cpp new file mode 100644 index 00000000..808c9863 --- /dev/null +++ b/livre/core/pipeline/PortFutures.cpp @@ -0,0 +1,156 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +namespace livre +{ + +typedef std::multimap< std::string, ConstFuturePtr > NameFutureMap; +typedef std::pair< std::string, ConstFuturePtr > NameFuturePair; + +struct PortFutures::Impl +{ + void throwError( const std::string& portName ) const + { + LBTHROW( std::runtime_error( std::string( "No futures assigned with the given port with name: ") + + portName )); + } + + bool hasPort( const std::string& portName ) const + { + return _futureMap.count( portName ) > 0; + } + + ConstFutures getFutures( const std::string& portName ) const + { + if( portName == ALL_PORTS ) + { + ConstFutures futures; + futures.insert( futures.end(), _futureMap.begin(), _futureMap.end( )); + return futures; + } + + if( !hasPort( portName )) + throwError( portName ); + + ConstFutures futures; + NameFutureMap::const_iterator it = _futureMap.find( portName ); + futures.insert( futures.end(), it, _futureMap.end( )); + return futures; + } + + + bool areReady() + { + for( const auto& future: getFutures( portName )) + { + if( !future->isReady()) + return false; + } + return true; + } + + void wait() + { + for( const auto& future: getFutures( portName )) + future->wait(); + } + + void waitForAny( const std::string& portName ) const + { + return livre::waitForAny( getFutures( portName )); + } + + void addFuture( const std::string& name, const ConstFuturePtr& future ) + { + _futureMap[ name ] = future; + } + + NameFutureMap _futureMap; +}; + + +PortFutures::PortFutures( const ConstFutures& futures, + const lunchbox::Strings& portNames /* = lunchbox::Strings() */) + : _impl( new PortFutures::Impl( futures, portNames )) +{} + +PortFutures::~PortFutures() +{} + +size_t PortFutures::getInputSize( const std::string& portName ) const +{ + return _impl->getPortSize( portName ); +} + +ConstFutures PortFutures::getFutures( const std::string& portName ) const +{ + return _impl->getFutures( portName ); +} + +bool PortFutures::areReady( const std::string& portName ) const +{ + return _impl->areReady( portName ); +} + +void PortFutures::wait( const std::string& portName ) const +{ + return _impl->wait( portName ); +} + +void PortFutures::waitForAny( const std::string& portName ) const +{ + return _impl->waitForAny( portName ); +} + +PortFutures::PortFutures() +{} + +void PortFutures::_addFuture( const std::string& name, const ConstFuturePtr& future ) +{ + _impl->addFuture( name, future ); +} + +OutputPortFutures::OutputPortFutures( const ConstFutures& futures ) +{ + for( const auto& future: futures ) + _addFuture( future->getName(), future ); + +} + +OutputPortFutures::~OutputPortFutures() +{} + +InputPortFutures::InputPortFutures( const InputPorts& inputPorts ) +{ + for( const auto& inputPort: inputPorts ) + { + const ConstFutures& futures = inputPort->getFutures(); + for( const auto& future: futures ) + _addFuture( future->getName(), future ); + } +} + +InputPortFutures::~InputPortFutures() +{} + + +} diff --git a/livre/core/pipeline/PortFutures.h b/livre/core/pipeline/PortFutures.h new file mode 100644 index 00000000..2fb56c85 --- /dev/null +++ b/livre/core/pipeline/PortFutures.h @@ -0,0 +1,245 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _PortFutures_h_ +#define _PortFutures_h_ + +#include +#include +#include + +namespace livre +{ + +/** + * The PortFutures class is a wrapper class to access the group of future + * and execute thread-safe operations on them. With a given portName (name) + * many futures can be associated. + */ +class PortFutures +{ +public: + + /** + * @param portName is the port name assoicated with futures. If port name + * is ALL_PORTS, all futures are marked to return. + * @return the futures associated with port name. + */ + ConstFutures getFutures( const std::string& portName = ALL_PORTS ) const; + + /** + * Queries if port is ready + * @param portName is the port name assoicated with futures. + * @return true if all port inputs are ready. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + bool isReady( const std::string& portName ) const; + + /** + * Waits all futures associated with port name + * @param portName is the port name assoicated with futures. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + void wait( const std::string& portName ) const; + + /** + * Waits all futures associated with port name. + * @param portName is the port name assoicated with futures. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + void waitForAny( const std::string& portName ) const; + +protected: + + PortFutures(); + + /** + * Adds a future + * @param future future to add + */ + void _addFuture( const std::string& name, const ConstFuturePtr& future ); + + + struct Impl; + std::unique_ptr _impl; +}; + +/** + * PortFutures for managing ports with unique names. + */ +class OutputPortFutures : public PortFutures +{ +public: + + /** + * @param futures the list of futures. + * @param portNames is the list of port names futures to be tagged with. If not given, + * future names are used for name-future association. + */ + OutputPortFutures( const ConstFutures& futures ); + + /** + * @param futures the list of futures. + * @param portNames is the list of port names futures to be tagged with. If not given, + * future names are used for name-future association. + */ + OutputPortFutures( const ConstFutures& futures ); + ~OutputPortFutures(); + + /** + * Gets the copy of value(s) with the given type T. If input + * is connected and values are not provided this function will + * block. + * @param portName is the port name assoicated with futures. + * @return the values port, value map. + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + const T& get( const std::string& portName ) const + { + ResultMapT< T > results; + for( const auto& future: getFutures( portName )) + results.insert( std::make_pair( future->getName(), future->get< T >( ))); + + return results[ future->getName() ]; + } + + /** + * Moves the value(s) with the given type T. If input + * is connected and values are not provided this function will + * block. + * @param portName is the port name assoicated with futures. + * @return the values vector. + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + const T&& move( const std::string& portName ) const + { + ResultMapT< T > results; + for( const auto& future: getFutures( portName )) + results.insert( std::make_pair( future->getName(), future->move< T >( ))); + + return results[ future->getName() ]; + } + +}; + +/** + * PortFutures for managing ports with non unique named ports. + */ +class InputPortFutures : public PortFutures +{ +public: + + /** + * @param inputPorts is the list of input ports + * future names are used for name-future association. + */ + InputPortFutures( const InputPorts& inputPorts ); + ~InputPortFutures(); + + /** + * Gets the copy of value(s) with the given type T. If input + * is connected and values are not provided this function will + * block. + * @param portName is the port name assoicated with futures. + * @return the values port, value map. + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + ResultMapT< T > get( const std::string& portName ) const + { + ResultMapT< T > results; + for( const auto& future: getFutures( portName )) + results.insert( std::make_pair( future->getName(), future->get< T >( ))); + + return results; + } + + /** + * Moves the value(s) with the given type T. If input + * is connected and values are not provided this function will + * block. + * @param portName is the port name assoicated with futures. + * @return the values vector. + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + ResultMapT< T > move( const std::string& portName ) const + { + ResultMapT< T > results; + for( const auto& future: getFutures( portName )) + results.insert( std::make_pair( future->getName(), future->move< T >( ))); + + return results; + } + + /** + * Gets the copy of ready value(s) with the given type T. + * @param portName is the port name assoicated with futures. + * @return the values vector. + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + ResultMapT< T > getReady( const std::string& portName ) const + { + ResultMapT< T > results; + for( const auto& future: getFutures( portName )) + { + if( !future->isReady()) + continue; + + results.insert( std::make_pair( future->getName(), future->get< T >( ))); + } + return results; + } + + /** + * Moves the ready value(s) with the given type T + * @param portName is the port name assoicated with futures. + * @return the values vector. + * @throw std::runtime_error when the port data is not exact + * type T or there is no future assigned to given port name + */ + template< class T > + ResultMapT< T > moveReady( const std::string& portName ) const + { + ResultMapT< T > results; + for( const auto& future: getFutures( portName )) + { + if( !future->isReady()) + continue; + + results.insert( std::make_pair( future->getName(), future->move< T >( ))); + } + return results; + } +}; + +} + +#endif // _PortFutures_h_ diff --git a/livre/core/pipeline/PortInfo.h b/livre/core/pipeline/PortInfo.h new file mode 100644 index 00000000..986ccc38 --- /dev/null +++ b/livre/core/pipeline/PortInfo.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _PortInfo_h_ +#define _PortInfo_h_ + +#include + +#include "PortType.h" + +namespace livre +{ + +/** + * Structure that holds the port information ( name, default value ) + */ +struct PortInfo final : public PortType +{ + PortInfo( const std::string& name_, + std::type_index& typeIndex ) + : PortType( typeIndex ) + , name( portName_ ) + {} + + const std::string name; +}; + +/** + * Helper function to create port info. + * @param name is the port name + */ +template< class T > +PortInfo makePortInfo( const std::string& name ) +{ + return PortInfo( name, std::type_index( typeid( T ))); +} + +/** + * Helper function to create port info. + * @param name is the port name + */ +PortInfo makePortInfo( const std::string& name, + const std::type_index& typeIndex ) +{ + return PortInfo( name, typeIndex ); +} + +/** + * Helper function to add port info to the list of port infos. + * @param portInfos is the list of port infos. + * @param portName is the port name + */ +template< class T > +void addPortInfo( PortInfos& portInfos, + const std::string& portname ) +{ + portInfos.push_back( makePortInfo< T >( portname )); +} + + +} + +#endif // _PortInfo_h_ + diff --git a/livre/core/pipeline/PortPromises.cpp b/livre/core/pipeline/PortPromises.cpp new file mode 100644 index 00000000..850b8a55 --- /dev/null +++ b/livre/core/pipeline/PortPromises.cpp @@ -0,0 +1,93 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +namespace livre +{ + +typedef std::pair< std::string, PromisePtr > NamePromisePair; +typedef std::map< std::string, PromisePtr > NamePromiseMap; + +struct PortPromises::Impl +{ + Impl( const Promises& promises ) + { + for( PromisePtr& promise: promises ) + _promiseMap[ promise->getName( )] = promise; + } + + void throwError( const std::string& portName ) const + { + std::stringstream err; + err << "Unknown port: " << portName << std::endl; + _promiseMap( std::runtime_error( err.str( ))); + } + + bool hasPort( const std::string& portName ) const + { + return _promiseMap.count( portName ) > 0; + } + + void flush( const std::string& portName ) + { + if( portName != ALL_PORTS && !hasPort( portName )) + throwError( portName ); + + for( const NamePromisePair& namePromisePair: _promiseMap ) + { + PromisePtr& promise = namePromisePair.second; + if( portName == ALL_PORTS || promise->getName() == portName ) + promise->flush(); + } + } + + void set( const std::string& portName, ConstPortDataPtr data ) + { + if( !hasPort( portName )) + throwError( portName ); + + _promiseMap[ portName ]->set( data ); + } + + NamePromiseMap _promiseMap; +}; + +PortPromises::PortPromises( const Promises& promises ) + : _impl( new PortPromises::Impl( promises )) +{} + +PortPromises::~PipeFilterOutput() +{} + +void PortPromises::flush( const std::string& portName /* = ALL_PORTS */ ) +{ + _impl->flush( portName ); +} + +void PortPromises::_set( const std::string& name, + ConstPortDataPtr data ) +{ + _impl->set( name, data ); +} + + +} diff --git a/livre/core/pipeline/PortPromises.h b/livre/core/pipeline/PortPromises.h new file mode 100644 index 00000000..e9ec3908 --- /dev/null +++ b/livre/core/pipeline/PortPromises.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _PortPromises_h_ +#define _PortPromises_h_ + +#include +#include + +namespace livre +{ + +/** + * The PipeFilterOutput class is used by the @PipeFilter class to instantiate + * the outgoing connections to a given filter using the connection info + * provided by the filter. + * + * It provides functionality to wait on any or all the ports given by + * name. + * + * It also provides thread safe functions to query the state of the port. + */ +class PortPromises +{ + +public: + + PortPromises( const Promises& promises ); + ~PortPromises(); + + /** + * Sets the port with the value. + * @param value to be set + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + void set( const std::string& portName, const T& value ) + { + _set( portName, makePortDataPtr( value )); + } + + /** + * Sets the port with the value. + * @param value to be set + * @throw std::runtime_error when the port data is not exact + * type T + */ + template< class T > + void set( const std::string& portName, const T&& value ) + { + _set( portName, makePortDataPtr( value )); + } + + /** + * Writes empty values to promises + * @param portName is the port name. If ALL_PORTS is given, + * all promises will be flushed + */ + void flush( const std::string& portName = ALL_PORTS ); + +private: + + void _set( const std::string& portName, ConstPortDataPtr data ); + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _PortPromises_h_ diff --git a/livre/core/pipeline/PortType.h b/livre/core/pipeline/PortType.h new file mode 100644 index 00000000..389b65ab --- /dev/null +++ b/livre/core/pipeline/PortType.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _PortType_h_ +#define _PortType_h_ + +#include + +namespace livre +{ + +/** + * PortType class is base class for keeping the track for types + * by using the std::type_index. + */ +class PortType +{ +public: + + /** + * @return the type index + */ + const std::type_index& getDataType() const + { return _typeIndex; } + +protected: + + /** + * PortType constructor + * @param typeIndex type index of the data of the + * derived classes data type. + */ + PortType( const std::type_index& typeIndex ) + : _typeIndex( typeIndex) {} + virtual ~PortData() {} + +private: + std::type_index _typeIndex; +}; + +} + +#endif // _PortData_h_ + diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp new file mode 100644 index 00000000..9507b2c5 --- /dev/null +++ b/livre/core/pipeline/Promise.cpp @@ -0,0 +1,72 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +namespace livre +{ + +struct Promise::Impl +{ + Impl( const Connection& connection ) + : _connection( connection ) + {} + + const std::string& getName() const + { + return _connection.getName(); + } + + void set( ConstPortDataPtr msg ) + { + _connection.set( msg ); + } + + ConstFuturePtr getFuture() const + { + return ConstFuturePtr( new Future( _connection )); + } + + const Connection& _connection; +}; + +Promise::Promise( const Connection& connection ) + : _impl( new Promise::Impl( connection )) +{} + +Promise::~Promise() +{} + +const std::string& Promise::getName() const +{ + return _impl->getName(); +} + +void PortPromise::set( ConstPortDataPtr msg ) +{ + _impl->getName( msg ); +} + +ConstFuturePtr PortPromise::getFuture() const +{ + return _impl->getFuture(); +} + +} diff --git a/livre/core/pipeline/Promise.h b/livre/core/pipeline/Promise.h new file mode 100644 index 00000000..5c6ee242 --- /dev/null +++ b/livre/core/pipeline/Promise.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _Promise_h_ +#define _Promise_h_ + +#include +#include + +namespace livre +{ + +class PortPromise +{ +public: + + PortPromise( const Connection& connection ); + ~PortPromise(); + + const std::string& getName() const; + + /** + * @return sets the promise with data + */ + void set( ConstPortDataPtr msg ); + + /** + * @return the future, that can be queried for data retrieval + */ + ConstFuturePtr getFuture() const; + +private: + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _Promise_h_ + diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp new file mode 100644 index 00000000..1e055ccd --- /dev/null +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -0,0 +1,107 @@ + +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define BOOST_THREAD_PROVIDES_FUTURE +#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + +#include +#include + +namespace livre +{ + +struct SimpleExecutor::Impl +{ + + Impl( WorkersPtr workers ) + : _workThread( boost::thread( boost::bind( &Impl::execute, this ))) + , _workers( workers ) + {} + + ~Impl() + { + _mtWorkQueue.clear(); + _mtWorkQueue.push( Executables( )); + _workThread.join(); + } + + void schedule() + { + while( true ) + { + Executables executables = _mtWorkQueue.pop(); + if( !executable.empty() ) + break; + + for( ExecutablePtr& executable: executables ) + _workers->execute( executable ); + } + } + + void clear() + { + _mtWorkQueue.clear(); + } + + void submit( Executables work ) + { + _mtWorkQueue.push( work ); + } + + lunchbox::MTQueue< Executables > _mtWorkQueue; + boost::thread _workThread; + WorkersPtr _workers; +}; + +SimpleExecutor::SimpleExecutor( WorkersPtr workers ) + : _impl( new Impl( workers )) +{ +} + +SimpleExecutor::~SimpleExecutor( ) +{ + +} + +void SimpleExecutor::clear() +{ + _impl->clear(); +} + +void SimpleExecutor::_schedule( const Executables& executables ) +{ + _impl->submit( executables ); +} + +} diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h new file mode 100644 index 00000000..d5c84d97 --- /dev/null +++ b/livre/core/pipeline/SimpleExecutor.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _SimpleExecutor_h_ +#define _SimpleExecutor_h_ + +#include +#include + +namespace livre +{ + +/** + * SimpleExecutor class provides the simplest implementation + * for the @see Executor class. The submitted pipelines are + * pushed to the worker threads. The pipeline submission + * is thread safe. + * + * The scheduler implemented in this class, just pushes the + * executables without re-ordering. This may mean that if + * all workers are blocked, the processing can suspend. + * + */ +class SimpleExecutor : public Executor +{ +public: + + /** + * @param workers are thread pools that executes individual + * executables ( PipeFilter, Pipeline ) + */ + explicit SimpleExecutor( WorkersPtr workers ); + virtual ~SimpleExecutor(); + + /** + * @copydoc Executor::clear() + */ + void clear() final; + +private: + + /** + * @copydoc Executor::_schedule + */ + void _schedule( const Executables& executables ) final; + + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif // _SimpleExecutor_h_ diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp new file mode 100644 index 00000000..23a2651e --- /dev/null +++ b/livre/core/pipeline/Workers.cpp @@ -0,0 +1,120 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include + +#include + +#include + +namespace livre +{ + +struct Workers::Impl +{ + + + Impl( Workers& workers, + size_t nThreads, + GLContextPtr glContext ) + : _workers( workers ) + , _glContext( glContext ) + { + for( size_t i = 0; i < nThreads; ++i ) + _threadGroup.create_thread( boost::bind( &Impl::execute, + this )); + + } + + void execute() + { + if( _glContext ) + { + GLContextPtr context = _glContext->createContext(); + _glContext->shareContext( context ); + context->makeCurrent(); + } + + while( true ) + { + ExecutablePtr executable = _workQueue.pop(); + if( !executable ) + break; + + executable->execute(); + } + } + + ~Impl() + { + for( size_t i = 0; i < getSize(); ++i ) + _workQueue.push( ExecutablePtr()); + _threadGroup.join_all(); + } + + void submitWork( ExecutablePtr executable ) + { + _workQueue.push( executable ); + } + + size_t getSize() const + { + return _threadGroup.size(); + } + + struct Work + { + + + }; + + Workers& _workers; + lunchbox::MTQueue< ExecutablePtr > _workQueue; + boost::thread_group _threadGroup; + GLContextPtr _glContext; +}; + +Workers::Workers( size_t nThreads, + GLContextPtr glContext ) + : _impl( new Workers::Impl( *this, + nThreads, + glContext )) +{ +} + +Workers::~Workers() +{ + +} + +Future Workers::execute( ExecutablePtr executable ) +{ + _impl->submitWork( executable ); +} + +size_t Workers::getSize() const +{ + return _impl->getSize(); +} + +} diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h new file mode 100644 index 00000000..86fdad5a --- /dev/null +++ b/livre/core/pipeline/Workers.h @@ -0,0 +1,68 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _Workers_h_ +#define _Workers_h_ + +#include +#include + +namespace livre +{ + +/** + * A simple thread pool + */ +class Workers +{ +public: + + /** + * Constructs a thread pool given the number of threads. + * @param nThreads is the number of threads. + * @param glContext if given, the threads can share this + * context. + */ + Workers( size_t nThreads = 4, + GLContextPtr glContext = GLContextPtr( )); + ~Workers(); + + /** + * Submitted executable is executed by the available + * threads. + * @param executable is executed by thread pool. + */ + Future execute( ExecutablePtr executable ); + + /** + * @return the size of thread pool. + */ + size_t getSize() const; + +private: + + struct Impl; + std::unique_ptr _impl; + +}; + +} + +#endif // _Workers_h_ + diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp new file mode 100644 index 00000000..c428bcfd --- /dev/null +++ b/tests/pipeline/pipeline.cpp @@ -0,0 +1,277 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define BOOST_TEST_MODULE Pipeline + +#include +#include +#include +#include +#include + +#include + +namespace ut = boost::unit_test; + +const uint32_t defaultMeaningOfLife = 42; +const uint32_t defaultThanksForAllTheFish = 51; +const uint32_t addMoreFish = 10; + +struct InputData +{ + InputData( uint32_t value = defaultMeaningOfLife ) + : meaningOfLife( value ) + {} + + uint32_t meaningOfLife; +}; + +struct OutputData +{ + OutputData( uint32_t value = defaultThanksForAllTheFish ) + : thanksForAllTheFish( value ) + {} + + uint32_t thanksForAllTheFish; +}; + +class TestFilter : public livre::Filter +{ + void execute( const livre::InputPortFutures& input, livre::PortPromises& output ) const final + { + + const livre::ResultMapT< InputData >& result = input.get< InputData >( "InputData" ); + OutputData outputData; + + for( const auto& pair: result ) + { + const InputData& inputData = pair.second; + outputData.thanksForAllTheFish += inputData.meaningOfLife + addMoreFish; + } + + output.set( "OutputData", outputData ); + + } + + livre::PortInfos getInputPorts() const final + { + livre::PortInfos inputPorts; + livre::addPortInfo< InputData >( inputPorts, "TestInputData" ); + return inputPorts; + } + + livre::PortInfos getOutputPorts() const final + { + livre::PortInfos outputPorts; + livre::addPortInfo< OutputData >( outputPorts, "TestOutputData"); + return outputPorts; + } +}; + +class ConvertFilter : public livre::Filter +{ + void execute( const livre::InputPortFutures& input, livre::PortPromises& output ) const final + { + + const livre::ResultMapT< OutputData >& result = input.get< OutputData >( "ConvertInputData" ); + + InputData inputData; + inputData.meaningOfLife = result[ "TestOutputData" ].thanksForAllTheFish + addMoreFish; + pipeFilter.setOutput( "ConvertOutputData", inputData ); + } + + livre::PortInfos getInputPorts() const final + { + livre::PortInfos outputPorts; + livre::addPortInfo< OutputData >( outputPorts, "ConvertInputData"); + return outputPorts; + } + + livre::PortInfos getOutputPorts() const final + { + livre::PortInfos inputPorts; + livre::addPortInfo< InputData >( inputPorts, "ConvertOutputData" ); + return inputPorts; + } +}; + +bool check_error( const std::runtime_error& ) { return true; } + +BOOST_AUTO_TEST_CASE( testFilterNoInput ) +{ + livre::FilterPtr filter( new TestFilter( )); + livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( filter )); + pipeFilter->execute(); + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, defaultThanksForAllTheFish ); +} + +BOOST_AUTO_TEST_CASE( testFilterWithInput ) +{ + livre::FilterPtr filter( new TestFilter( )); + livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( filter )); + const uint32_t inputValue = 90; + + const livre::PortPromises portPromises( pipeFilter->getPromises( )); + portPromises->set( "InputData", InputData( inputValue )); + pipeFilter->execute(); + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const OutputData& outputData = + portFutures.get< OutputData >( "TestOutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 151 ); +} + +BOOST_AUTO_TEST_CASE( testSetAndGetWrongParameters ) +{ + livre::FilterPtr filter( new TestFilter( )); + livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( filter )); + const livre::PortPromises portPromises( pipeFilter->getPromises( )); + + BOOST_CHECK_EXCEPTION( portPromises.set( "TestInputData", OutputData( 0 )), + std::runtime_error, check_error ); + pipeFilter->execute(); + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures()); + BOOST_CHECK_EXCEPTION( portFutures.get( "TestOutputData" ), + std::runtime_error, check_error ); +} + +BOOST_AUTO_TEST_CASE( testInvalidConnection ) +{ + livre::FilterPtr filter( new TestFilter( )); + livre::PipeFilterPtr pipeFilter1( new livre::PipeFilter( filter )); + livre::PipeFilterPtr pipeFilter2( new livre::PipeFilter( filter )); + + BOOST_CHECK_EXCEPTION( pipeFilter1->connect( "TestOutputData", + pipeFilter2, + "Helloworld" ), + std::runtime_error, check_error ); +} + +BOOST_AUTO_TEST_CASE( testConnection ) +{ + livre::FilterPtr filter( new TestFilter( )); + livre::PipeFilterPtr pipeInput( new livre::PipeFilter( filter ) ); + livre::PipeFilterPtr pipeOutput( new livre::PipeFilter( filter ) ); + + livre::FilterPtr convertFilter( new ConvertFilter( )); + livre::PipeFilterPtr convertPipeFilter( new livre::PipeFilter( convertFilter ) ); + + pipeInput->connectFilters( "TestOutputData", convertPipeFilter, "ConvertInputData" ); + convertPipeFilter->connect( "ConvertOutputData", pipeOutput, "TestInputData" ); + + const uint32_t inputValue = 90; + livre::PortPromises portPromises( pipeFilter->getPromises( )); + portPromises->set( "InputData", InputData( inputValue )); + pipeInput->execute(); + convertPipeFilter->execute(); + pipeOutput->execute(); + + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const OutputData& outputData = + portFutures->get( "TestOutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); +} + +livre::PipelinePtr createPipeline( livre::PipeFilterPtr& pipeOutput, + uint32_t inputValue, + size_t nConvertFilter = 1 ) +{ + livre::FilterPtr filter( new TestFilter( )); + livre::PipelinePtr pipeline( new livre::Pipeline( )); + livre::PipeFilterPtr pipeInput = pipeline->add( filter ); + pipeOutput = pipeline->add( filter ); + + livre::FilterPtr convertFilter( new ConvertFilter( )); + for( size_t i = 0; i < nConvertFilter; ++i ) + { + livre::PipeFilterPtr convertPipeFilter = pipeline->add( convertFilter ); + pipeInput->connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); + convertPipeFilter->connect( "ConvertInputData", pipeOutput, "TestInputData" ); + } + + livre::PortPromises portPromises( pipeFilter->getPromises( )); + portPromises->set( "InputData", InputData( inputValue )); + return pipeline; +} + +livre::ExecutorPtr createExecutor() +{ + livre::WorkersPtr workers( new livre::Workers( 2 )); + livre::ExecutorPtr executor( new livre::SimpleExecutor( workers )); + return executor; +} + +BOOST_AUTO_TEST_CASE( testSynchronousPipeline ) +{ + livre::PipeFilterPtr pipeOutput; + const uint32_t inputValue = 90; + livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); + pipeline->execute(); + + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); +} + +BOOST_AUTO_TEST_CASE( testWaitPipeline ) +{ + livre::PipeFilterPtr pipeOutput; + const uint32_t inputValue = 90; + livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); + livre::ExecutorPtr executor = createExecutor(); + + const livre::OutputPortFutures pipelineFutures( executor->execute( pipeline )); + pipelineFutures->wait(); + + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); +} + +BOOST_AUTO_TEST_CASE( testAsynchronousPipeline ) +{ + livre::PipeFilterPtr pipeOutput; + const uint32_t inputValue = 90; + livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); + livre::ExecutorPtr executor = createExecutor(); + + executor->execute( pipeline ); + + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); +} + +BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) +{ + const size_t convertFilterCount = 10; + const uint32_t inputValue = 90; + livre::PipeFilterPtr pipeOutput; + livre::PipelinePtr pipeline = createPipeline( pipeOutput, + inputValue, + convertFilterCount ); + livre::ExecutorPtr executor = createExecutor(); + executor->execute( pipeline ); + + const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 1761 ); +} + From dacce73ee8151f46d173993d0c4bf4954435daca Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Wed, 2 Mar 2016 15:48:19 +0100 Subject: [PATCH 02/17] Fixes, refactoring and new functionality based on comments --- livre/core/pipeline/Executable.h | 5 +- livre/core/pipeline/Executor.h | 17 +-- livre/core/pipeline/Filter.h | 4 +- livre/core/pipeline/FunctionFilter.cpp | 4 +- livre/core/pipeline/FunctionFilter.h | 2 +- livre/core/pipeline/Future.cpp | 17 ++- livre/core/pipeline/Future.h | 23 ++-- livre/core/pipeline/InputPort.cpp | 14 +-- livre/core/pipeline/InputPort.h | 3 +- livre/core/pipeline/OutputPort.cpp | 135 +++++++++++----------- livre/core/pipeline/OutputPort.h | 8 +- livre/core/pipeline/PipeFilter.cpp | 76 +++++++------ livre/core/pipeline/PipeFilter.h | 21 ++-- livre/core/pipeline/Pipeline.cpp | 45 ++++---- livre/core/pipeline/Pipeline.h | 18 +-- livre/core/pipeline/PortFutures.cpp | 106 ++++++++++------- livre/core/pipeline/PortFutures.h | 151 ++++++++++++------------- livre/core/pipeline/PortInfo.h | 15 +-- livre/core/pipeline/PortPromises.cpp | 6 +- livre/core/pipeline/PortType.h | 8 +- livre/core/pipeline/Promise.cpp | 30 ++--- livre/core/pipeline/Promise.h | 10 +- livre/core/pipeline/SimpleExecutor.h | 11 +- livre/core/pipeline/Workers.cpp | 9 +- livre/core/pipeline/Workers.h | 2 +- tests/pipeline/pipeline.cpp | 55 +++++---- 26 files changed, 417 insertions(+), 378 deletions(-) diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h index a56ff255..eafc1253 100644 --- a/livre/core/pipeline/Executable.h +++ b/livre/core/pipeline/Executable.h @@ -22,7 +22,6 @@ #include #include -#include namespace livre { @@ -44,14 +43,14 @@ class Executable * @return the input futures which the executable provides to wait. The * names of the futures are unique. */ - virtual ConstFutures getOutputFutures() const { return ConstFutures(); } + virtual Futures getOutFutures() const { return Futures(); } /** * @return the input futures which the executable is waiting to proceed. * The names of the futures not necessarily unique. The inputs accepts * multiple outputs with the same name. */ - virtual ConstFutures getInputFutures() const { return ConstFutures(); } + virtual Futures getConnectedInFutures() const { return Futures(); } protected: diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h index ebf7d674..cdbc7876 100644 --- a/livre/core/pipeline/Executor.h +++ b/livre/core/pipeline/Executor.h @@ -20,6 +20,7 @@ #ifndef _Executor_h_ #define _Executor_h_ +#include #include namespace livre @@ -41,34 +42,34 @@ class Executor * Executes the executable. Returns the futures that can be queried for data. * @param pipeline to be executed. */ - PortFutures execute( ExecutablePtr executable ) + Futures execute( ExecutablePtr executable ) { - const ConstFutures& fs = _executable->getOutputFutures(); + const Futures& fs = _executable->getOutFutures(); _schedule( { executable } ); - return PortFutures( fs ); + return fs; } /** * Executes the executable. Returns the futures that can be queried for data. * @param pipeline to be executed. */ - PortFutures execute( const Executables& executables ) + Futures execute( const Executables& executables ) { - ConstFutures futures; + Futures futures; for( const ExecutablePtr& executable: executables ) { - const ConstFutures& fs = executable->getOutputFutures(); + const Futures& fs = executable->getOutFutures(); futures.insert( futures.back(), fs.begin(), fs.end( )); } _schedule( executables ); - return PortFutures( futures ); + return futures; } protected: /** - * Schedules the executables for execution + * Schedules the executables for execution. * @param executables are the executables to schedule. */ virtual void _schedule( const Executables& executables ) = 0; diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h index 1132f8ab..d6414743 100644 --- a/livre/core/pipeline/Filter.h +++ b/livre/core/pipeline/Filter.h @@ -23,8 +23,6 @@ #include #include #include -#include -#include namespace livre { @@ -55,7 +53,7 @@ class Filter * @param input The Future that can be read for input parameters * @param output The Promise that can be written to for output parameters */ - virtual void execute( const InputPortFutures& input, PortPromises& output ) const = 0; + virtual void execute( const InFutures& input, PortPromises& output ) const = 0; /** * @param inputPorts information is filled by the Filter class. diff --git a/livre/core/pipeline/FunctionFilter.cpp b/livre/core/pipeline/FunctionFilter.cpp index f90951f0..eda9e94b 100644 --- a/livre/core/pipeline/FunctionFilter.cpp +++ b/livre/core/pipeline/FunctionFilter.cpp @@ -33,7 +33,7 @@ struct FunctionFilter::Impl , _outputPorts( outputPorts ) {} - void execute( const PortFutures& input, PortPromises& output ) const + void execute( const InFutures& input, PortPromises& output ) const { _filterFunc( filter ); } @@ -67,7 +67,7 @@ FunctionFilter::FunctionFilter( const FilterFunc& filterFunc, FunctionFilter::~FunctionFilter() {} -void FunctionFilter::execute( const PortFutures& input, PortPromises& output ) const +void FunctionFilter::execute( const InFutures& input, PortPromises& output ) const { _impl->execute( input, output ); } diff --git a/livre/core/pipeline/FunctionFilter.h b/livre/core/pipeline/FunctionFilter.h index 3d58a103..d0ad23bc 100644 --- a/livre/core/pipeline/FunctionFilter.h +++ b/livre/core/pipeline/FunctionFilter.h @@ -47,7 +47,7 @@ struct FunctionFilter final : public Filter /** * @copydoc Filter::execute( PipeFilter& filter ) */ - void execute( const PortFutures& input, PortPromises& output ) const final; + void execute( const InFutures& input, PortPromises& output ) const final; /** * @copydoc Filter::getInputPorts() diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp index 59b706e5..d91539b2 100644 --- a/livre/core/pipeline/Future.cpp +++ b/livre/core/pipeline/Future.cpp @@ -24,8 +24,10 @@ namespace livre struct Future::Impl { - Impl( const AsyncData& data ) - : _data( data ) + Impl( const PipeFilter& pipeFilter, + const AsyncData& data ) + : _pipeFilter( pipeFilter ) + , _data( data ) {} const std::string& getName() const @@ -43,11 +45,13 @@ struct Future::Impl return _data.get(); } + const PipeFilter& _pipeFilter; const AsyncData& _data; }; -Future::Future( const AsyncData& data ) - : _impl( new Future::Impl( data )) +Future::Future( const PipeFilter& pipeFilter, + const AsyncData& data ) + : _impl( new Future::Impl( pipeFilter, data )) {} Future::~Future() @@ -68,6 +72,11 @@ bool Future::isReady() const return _impl->isReady(); } +const PipeFilter& Future::getPipeFilter() const +{ + return _impl->_pipeFilter; +} + void Future::_set( const ConstPortDataPtr& data ) { _impl->set( data ); diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h index 2a465923..799d6355 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/Future.h @@ -29,14 +29,10 @@ class Future { public: - Future( const AsyncData& data ); + Future( const PipeFilter& pipeFilter, + const AsyncData& data ); ~Future(); - /** - * @return the async data implementation - */ - const AsyncData& getAsyncData() const; - /** * @return name of the future */ @@ -92,15 +88,26 @@ class Future */ bool isReady() const; + /** + * @return the pipe filter that future belongs to. If executor supports pull mode, + * by getting futures, it will be possible to reach the source of the execution + */ + const PipeFilter& getPipeFilter() const; + + /** + * @return the async data implementation + */ + const AsyncData& getAsyncData() const; + private: - friend livre::waitForAny( const ConstFutures& future ); + friend livre::waitForAny( const Futures& future ); void _set( const ConstPortDataPtr& data ); ConstPortDataPtr _get() const; struct Impl; - std::unique_ptr _impl; + std::shared_ptr _impl; }; } diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp index c2e73b8b..fa2b807d 100644 --- a/livre/core/pipeline/InputPort.cpp +++ b/livre/core/pipeline/InputPort.cpp @@ -19,16 +19,16 @@ #include #include +#include +#include namespace livre { struct InputPort::Impl { - Impl( InputPort& inputPort, - const PortInfo& info ) - : _inputPort( inputPort ) - , _info( info ) + Impl( const PortInfo& info ) + : _info( info ) {} ~Impl() @@ -57,18 +57,18 @@ struct InputPort::Impl _futures.push_back( outputPort.getPromise()-getFuture( )); } - ConstFutures _futures; + Futures _futures; const PortInfo _info; }; InputPort::InputPort( const PortInfo& portInfo ) - : _impl( new InputPort::Impl( portInfo )) + : _impl( new InputPort::Impl( portInfo )) {} InputPort::~InputPort() {} -ConstFutures InputPort::getFutures() const +Futures InputPort::getFutures() const { return _impl->getFutures(); } diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index 2ee30a55..58d2bd52 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -23,7 +23,6 @@ #include #include #include -#include namespace livre { @@ -61,7 +60,7 @@ class InputPort /** * @return Return all the input futures that port has. */ - ConstFutures getFutures() const; + Futures getFutures() const; /** * Connects an output port to input port diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp index d9ec304c..8daf9a4f 100644 --- a/livre/core/pipeline/OutputPort.cpp +++ b/livre/core/pipeline/OutputPort.cpp @@ -19,80 +19,17 @@ #include #include - -#include +#include #include namespace livre { + typedef boost::shared_future< ConstPortDataPtr > ConstPortDataFuture; typedef boost::promise< ConstPortDataPtr > ConstPortDataPromise; - typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; -typedef std::vector< ConstPortDataPromise > ConstPortDataPromises; - -struct OutputPort::Impl -{ - Impl( const PortInfo& portInfo ) - : _info( portInfo ) - , _data( portInfo.name ) - , _portPromise( new PortPromise( _data )) - {} - - ~Impl() - { - flush(); - } - - void flush() - { - _data.set( ConstPortDataPtr( )); - } - - const std::string& getName() const - { - return _info.portName; - } - - PortInfo _info; - AsyncData _data; - PromisePtr _portPromise; -}; - -OutputPort::OutputPort( const PortInfo& portInfo ) - : _impl( new OutputPort::Impl( portInfo )) -{} - - -OutputPort::~OutputPort() -{} - -const std::string& OutputPort::getName() const -{ - return _impl->getName(); -} - -const std::type_index& OutputPort::getDataType() const -{ - return _impl->_info.getDataType(); -} - -ConstFuturePtr OutputPort::getFuture() const -{ - return _impl->_portFuture; -} - -PromisePtr OutputPort::getPromise() const -{ - return _impl->_portPromise; -} - -void OutputPort::connect( InputPort& inputPort ) -{ - _inputPort->connect( *this ); -} struct AsyncData::Impl { @@ -134,14 +71,14 @@ struct AsyncData::Impl _future.wait(); } + const PipeFilter& _pipeFilter; ConstPortDataPromise _promise; mutable ConstPortDataFuture _future; const std::string _name; }; AsyncData::AsyncData( const std::string& name ) - : AsyncData( name ) - , _impl( new Impl( )) + : _impl( new Impl( pipeFilter, name )) {} ConstPortDataPtr AsyncData::get() const @@ -169,7 +106,69 @@ void AsyncData::wait() const _impl->wait(); } -bool waitForAny( const ConstFutures& futures ) + +struct OutputPort::Impl +{ + Impl( const PipeFilter& pipeFilter, const PortInfo& portInfo ) + : _info( portInfo ) + , _data( portInfo.name ) + , _portPromise( new Promise( pipeFilter, _data )) + {} + + ~Impl() + { + flush(); + } + + void flush() + { + _data.set( ConstPortDataPtr( )); + } + + const std::string& getName() const + { + return _info.portName; + } + + PortInfo _info; + AsyncData _data; + PromisePtr _portPromise; +}; + +OutputPort::OutputPort( const PipeFilter& pipeFilter, const PortInfo& portInfo ) + : _impl( new OutputPort::Impl( pipeFilter, portInfo )) +{} + + +OutputPort::~OutputPort() +{} + +const std::string& OutputPort::getName() const +{ + return _impl->getName(); +} + +const std::type_index& OutputPort::getDataType() const +{ + return _impl->_info.getDataType(); +} + +ConstFuturePtr OutputPort::getFuture() const +{ + return _impl->_portFuture; +} + +PromisePtr OutputPort::getPromise() const +{ + return _impl->_portPromise; +} + +void OutputPort::connect( InputPort& inputPort ) +{ + _inputPort->connect( *this ); +} + +bool waitForAny( const Futures& futures ) { ConstPortDataFutures futures; for( const auto& future: futures ) diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h index 9fc1ce29..74440870 100644 --- a/livre/core/pipeline/OutputPort.h +++ b/livre/core/pipeline/OutputPort.h @@ -38,7 +38,7 @@ class AsyncData * set yet, so any get() call will block the retrieval * @param name of the connection */ - AsyncData( const std::string& name ); + AsyncData( const PipeFilter& pipeFilter, const std::string& name ); /** * @return the name of the connection @@ -73,7 +73,7 @@ class AsyncData * @note this function needs internal access to the futures ( which is not exposed in the API ). * @return true if any new futures are ready. */ - friend bool waitForAny( const ConstFutures& futures ); + friend bool waitForAny( const Futures& futures ); struct Impl; std::unique_ptr _impl; @@ -84,7 +84,7 @@ class OutputPort public: - OutputPort( const PortInfo& portInfo ); + OutputPort( const PipeFilter& pipeFilter, const PortInfo& portInfo ); ~OutputPort(); /** @@ -114,7 +114,7 @@ class OutputPort std::unique_ptr _impl; }; -bool waitForAny( const ConstFutures& futures ); +bool waitForAny( const Futures& futures ); } diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index d8a8b3bf..684bbe20 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -72,7 +72,7 @@ struct PipeFilter::Impl return _outputMap.count( portName ) > 0; } - void throwError( const std::string& portName ) const + void throwPortError( const std::string& portName ) const { LBTHROW( std::runtime_error( std::string( "There is no port with name: ") + portName )); @@ -84,48 +84,50 @@ struct PipeFilter::Impl _inputMap[ portInfo.name ] = new InputPort( portInfo ); for( const PortInfo& portInfo: oPortInfos ) - _outputMap[ portInfo.name ] = new OutputPort( portInfo ); + _outputMap[ portInfo.name ] = new OutputPort( *this, portInfo ); // Connect notification ports _inputMap[ _id.getString( )] = new InputPort( makePortInfo< ConstPortDataPtr >( _id.getString( ))); _outputMap[ _id.getString( )] = - new OutputPort( makePortInfo< ConstPortDataPtr >( _id.getString( ))); + new OutputPort( *this, makePortInfo< ConstPortDataPtr >( _id.getString( ))); } void execute() { - lunchbox::Strings& inputNames; - const ConstFutures& inputFutures = getInputFutures( inputNames ); - InputPorts ports; for( auto pair: _inputMap ) ports.push_back( pair.second ); - const InputPortFutures futures( ports ); + const InFutures futures( ports ); PortPromises promises( getOutputPromises( )); _filter->execute( futures, promises ); promises.flush(); } - Promises getInputPromises() + PromisePtr getInputPromise( const std::string& portName ) const { - Promises promises; - for( auto pair: _inputMap ) + if( !hasInputPort( portName )) + throwPortError( portName ); + + if( _outputsToInputMap.count( portName ) > 0 ) + return _outputsToInputMap[ portName ]->getPromise(); + + InputPortPtr& inputPort = _inputMap[ portName ]; + + if( inputPort->getSize() != 0 || // If there is another connection + inputPort->getName() == _id.getString( )) // If this is an notification port { - InputPortPtr& inputPort = pair.second; - if( _outputsToInputMap.getCount( inputPort->getName( )) == 0 && - inputPort->getSize() == 0 && inputPort->getName() != _id.getString( )) - { - OutputPortPtr outputPort( new OutputPort( - makePortInfo( inputPort->getName(), - inputPort->getDataType( )))); - _outputsToInputMap[ inputPort->getName() ] = outputPort; - promises.push_back( outputPort->getPromise( )); - } + LBTHROW( std::runtime_error( "The port is already connected or this is a" + "notification port" )); } - return promises; + OutputPortPtr outputPort( new OutputPort( *this, + makePortInfo( inputPort->getName(), + inputPort->getDataType( )))); + _outputsToInputMap[ inputPort->getName() ] = outputPort; + + return outputPort->getPromise(); } Promises getOutputPromises() const @@ -138,7 +140,7 @@ struct PipeFilter::Impl return promises; } - ConstFutures getOutputFutures() const + Futures getOutFutures() const { for( const auto& pair: _outputPorts ) { @@ -148,14 +150,14 @@ struct PipeFilter::Impl return futures; } - ConstFutures getInputFutures( lunchbox::Strings& names ) const + Futures getInputFutures( lunchbox::Strings& names ) const { - ConstFutures futures; + Futures futures; for( const auto& pair: _inputPorts ) { - ConstFutures inputFutures = port->getFutures(); + Futures inputFutures = port->getFutures(); futures.insert( futures.end(), inputFutures.begin(), inputFutures.end( )); - names.push_back( pair.second->getName( )) + names.push_back( pair.second->getName( )); } return futures; } @@ -165,12 +167,18 @@ struct PipeFilter::Impl const std::string& dstPortName ) { if( !hasOutputPort( srcPortName )) - throwError( srcPortName ); + throwPortError( srcPortName ); if( !dst->_impl.hasInputPort( dstPortName )) - throwError( dstPortName ); + throwPortError( dstPortName ); + + // The value on the output port may already be set + if( !dst->_impl._outputsToInputMap.count( dstPortName )) + std::runtime_error( std::string( "The value on port: ") + + portName + + "is already set" ); - _outputMap[ srcPortName ]->connect( *dst->_impl->inputMap[ dstPortName ] ) + _outputMap[ srcPortName ]->connect( *dst->_impl->inputMap[ dstPortName ] ); } void PipeFilter::connect( PipeFilterPtr dst ) @@ -225,20 +233,20 @@ const std::string& PipeFilter::getName() const return _impl->_name; } -ConstFutures PipeFilter::getInputFutures() const +Futures PipeFilter::getConnectedInFutures() const { lunchbox::Strings& names; return _impl->getInputFutures( names ); } -Promises PipeFilter::getPromises() +PromisePtr PipeFilter::getPromise( const std::string& portName ) { - return _impl->getInputPromises(); + return _impl->getInputPromise( portName ); } -ConstFutures PipeFilter::getOutputFutures() const +Futures PipeFilter::getOutFutures() const { - return _impl->getOutputFutures(); + return _impl->getOutFutures(); } void PipeFilter::connect( const std::string& srcPortName, diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index d794690d..40c37693 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -25,8 +25,6 @@ #include #include #include -#include -#include namespace livre { @@ -82,7 +80,7 @@ class PipeFilter : public Executable * @param srcPortName is the source pipe filter. * @param dst is the destination pipe filter. * @param dstPortName connection port name. - * @throws std::exception if connection can not be established + * @throws std::runtime_error if connection can not be established */ void connect( const std::string& srcPortName, PipeFilterPtr dst, @@ -93,25 +91,30 @@ class PipeFilter : public Executable * is complete. * @param dst is the destination pipe filter. * @return true if connection is successful. - * @throws std::exception if connection can not be established + * @throws std::runtime_error if connection can not be established or if the + * port already is set from outside. */ void connect( PipeFilterPtr dst ); /** - * @copydoc Executable::getOutputFutures() + * @copydoc Executable::getOutFutures() */ - ConstFutures getOutputFutures() const final; + Futures getOutFutures() const final; /** * @copydoc Executable::getInputFutures() * @note PipeFilter guarantees that only connected input futures are returned. */ - ConstFutures getInputFutures() const final; + Futures getConnectedInFutures() const final; /** - * @return return inputs for the pipe filter. + * @return return promise for the given input port. If there is no connection to the + * input port, a new promise is created for the port and no further connections are allowed, + * if there is a connection getting a promise is not allowed. + * @throws std::runtime_error if there is already a connection or if there is + * no inputport or it is a noification port. */ - Promises getPromises(); + PromisePtr getPromise( const std::string& portName ); /** * @return the unique id of the filter. diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp index 755dfb85..fabb79a6 100644 --- a/livre/core/pipeline/Pipeline.cpp +++ b/livre/core/pipeline/Pipeline.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ struct Pipeline::Impl { typedef std::map< std::string, ConstPipelinePtr > PipelineMap; typedef std::map< std::string, ConstPipeFilterPtr > PipeFilterMap; + typedef std::map< std::string, ExecutablePtr > ExecutableMap; Impl( Pipeline& pipeline ) : _pipeline( pipeline ) @@ -55,15 +55,16 @@ struct Pipeline::Impl FilterPtr filter, bool wait ) { - if( _filters.count( name ) > 0 || _pipelines.count( name )) + if( _executableMap.count( name ) > 0 ) LBTHROW( std::runtime_error( name + " already exists")); PipeFilterPtr pipefilter( new PipeFilter( name, filter )); - _filters[ name ] = pipefilter; + _executableMap[ name ] = pipefilter; + if( wait ) { - const PortFutures portFutures( pipefilter->getOutputFutures( )); - _waitFutures.push_back( portFutures.getFutures( pipefilter->getId().getString( ))); + const OutFutures portFutures( pipefilter->getOutFutures( )); + _waitFutures.push_back( portFutures.getFuture( pipefilter->getId().getString( ))); } } @@ -74,11 +75,14 @@ struct Pipeline::Impl if( pipeline.get() == _pipeline ) return; - _pipelines[ name ] = pipeline; + if( _executableMap.count( name ) > 0 ) + LBTHROW( std::runtime_error( name + " already exists")); + + _executableMap[ name ] = pipeline; if( wait ) { - const ConstFutures& futures = pipeline->getOutputFutures(); + const Futures& futures = pipeline->getOutFutures(); _waitFutures.insert( _waitFutures.end(), futures.begin(), futures.end( )); } } @@ -90,7 +94,7 @@ struct Pipeline::Impl while( !executables.empty()) { ExecutablePtr executable = *it; - const PortFutures portFutures( executable->getInputFutures( )); + const FutureMap portFutures( executable->getConnectedInFutures( )); if( portFutures.isReady( )) { executable->execute(); @@ -109,23 +113,19 @@ struct Pipeline::Impl Executables getExecutables() const { Executables executables; - executables.reserve( _filters.size() + _pipelines.size( )); - - for( auto pair: _filters ) - executables.push_back( pair.second ); - for( auto pair: _pipelines ) + for( auto pair: _executableMap ) executables.push_back( pair.second ); return executables; } - ConstFutures getInputFutures() const + Futures getConnectedInFutures() const { - return ConstFutures(); + return Futures(); } - ConstFutures getOutputFutures() const + Futures getOutFutures() const { return _waitFutures; } @@ -134,9 +134,8 @@ struct Pipeline::Impl {} Pipeline& _pipeline; - PipeFilterMap _filters; - PipelineMap _pipelines; - ConstFutures _waitFutures; + ExecutableMap _executableMap; + Futures _waitFutures; }; Pipeline::Pipeline() @@ -184,14 +183,14 @@ void Pipeline::execute() return _impl->execute(); } -ConstFutures Pipeline::getInputFutures() const +Futures Pipeline::getConnectedInFutures() const { - return _impl->getInputFutures(); + return _impl->getConnectedInFutures(); } -ConstFutures Pipeline::getOutputFutures() const +Futures Pipeline::getOutFutures() const { - return _impl->getOutputFutures(); + return _impl->getOutFutures(); } } diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index dcf13462..ff346814 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -52,10 +52,12 @@ class Pipeline : public Executable bool wait = true ); /** - * Adds a filter to be executed + * Creates and adds a pipefilter around a filter to be executed. The + * notification of completion of execution is connected to the pipeline + * if user wants to wait on execution of whole pipeline. * @param filter is added to list of executables. * @param wait If true, on asynchronous execution, pipeline - * can wait on given filter. + * can wait on the added filter. * @return returns the generated pipe filter. */ PipeFilterPtr add( const std::string& name, @@ -63,12 +65,14 @@ class Pipeline : public Executable bool wait = true ); /** - * Adds a filter function to be executed + * Adds a filter function to be executed. The + * notification of completion of execution is connected to the pipeline + * if user wants to wait on execution of whole pipeline. * @param filterFunc is the filter function object. * @param inputPorts are the input ports information. * @param outputPorts are the output ports information. * @param wait If true, on asynchronous execution, pipeline - * can wait on given filter function. + * can wait on the added filter function. * @return returns the generated pipe filter. */ PipeFilterPtr add( const std::string& name, @@ -89,17 +93,17 @@ class Pipeline : public Executable * Executes each executable element in the graph * synchronously. */ - void _execute() final; + void execute() final; /** * @return Returns the writable future */ - ConstFutures getInputFutures() const final; + Futures getConnectedInFutures() const final; /** * @return Returns the writable future */ - ConstFutures getOutputFutures() const final; + Futures getOutFutures() const final; struct Impl; std::unique_ptr _impl; diff --git a/livre/core/pipeline/PortFutures.cpp b/livre/core/pipeline/PortFutures.cpp index 808c9863..764d1ef4 100644 --- a/livre/core/pipeline/PortFutures.cpp +++ b/livre/core/pipeline/PortFutures.cpp @@ -26,9 +26,11 @@ namespace livre typedef std::multimap< std::string, ConstFuturePtr > NameFutureMap; typedef std::pair< std::string, ConstFuturePtr > NameFuturePair; -struct PortFutures::Impl +class FutureMap { - void throwError( const std::string& portName ) const +public: + + void throwPortError( const std::string& portName ) const { LBTHROW( std::runtime_error( std::string( "No futures assigned with the given port with name: ") + portName )); @@ -39,26 +41,25 @@ struct PortFutures::Impl return _futureMap.count( portName ) > 0; } - ConstFutures getFutures( const std::string& portName ) const + Futures getFutures( const std::string& portName ) const { if( portName == ALL_PORTS ) { - ConstFutures futures; + Futures futures; futures.insert( futures.end(), _futureMap.begin(), _futureMap.end( )); return futures; } if( !hasPort( portName )) - throwError( portName ); + throwPortError( portName ); - ConstFutures futures; + Futures futures; NameFutureMap::const_iterator it = _futureMap.find( portName ); futures.insert( futures.end(), it, _futureMap.end( )); return futures; } - - bool areReady() + bool isReady() const { for( const auto& future: getFutures( portName )) { @@ -68,7 +69,7 @@ struct PortFutures::Impl return true; } - void wait() + void wait( const std::string& portName ) const { for( const auto& future: getFutures( portName )) future->wait(); @@ -87,70 +88,95 @@ struct PortFutures::Impl NameFutureMap _futureMap; }; +struct OutFutures::Impl: public FutureMap +{ +public: + Impl( const Futures& futures ) + { + for( const auto& future: futures ) + { + const std::string& name = future->getName(); + if( hasPort( name )) + throwPortError( name ); + addFuture( name, future ); + } + } +}; -PortFutures::PortFutures( const ConstFutures& futures, - const lunchbox::Strings& portNames /* = lunchbox::Strings() */) - : _impl( new PortFutures::Impl( futures, portNames )) -{} - -PortFutures::~PortFutures() +OutFutures::OutFutures( const Futures& futures ) + : _impl( new OutFutures::Impl( futures )) {} -size_t PortFutures::getInputSize( const std::string& portName ) const +Futures OutFutures::getFutures() const { - return _impl->getPortSize( portName ); + return _impl->getFutures( ALL_PORTS ); } -ConstFutures PortFutures::getFutures( const std::string& portName ) const +Future OutFutures::getFuture( const std::string& portName ) const { - return _impl->getFutures( portName ); + return _impl->getFuture(); } -bool PortFutures::areReady( const std::string& portName ) const +bool OutFutures::isReady( const std::string& portName ) const { - return _impl->areReady( portName ); + return _impl->isReady( portName ); } -void PortFutures::wait( const std::string& portName ) const +void OutFutures::wait( const std::string& portName ) const { - return _impl->wait( portName ); + _impl->wait( portName ); } -void PortFutures::waitForAny( const std::string& portName ) const +void OutFutures::waitForAny( const std::string& portName ) const { return _impl->waitForAny( portName ); } -PortFutures::PortFutures() +OutFutures::~OutFutures() {} -void PortFutures::_addFuture( const std::string& name, const ConstFuturePtr& future ) +struct InFutures::Impl: public FutureMap +{ +public: + Impl( const InputPorts& inputPorts ) + { + for( const InputPortPtr& inputPort: inputPorts ) + { + const Futures& futures = inputPort->getFutures(); + for( const auto& future: futures ) + addFuture( inputPort->getName(), future ); + } + } +}; + +InFutures::InFutures( const InputPorts& inputPorts ) + : _impl( new InFutures::Impl( inputPorts )) { - _impl->addFuture( name, future ); } -OutputPortFutures::OutputPortFutures( const ConstFutures& futures ) +Futures InFutures::getFutures( const std::string& portName /* = ALL_PORTS */ ) const { - for( const auto& future: futures ) - _addFuture( future->getName(), future ); + return _impl->getFutures( portName ); +} +bool InFutures::isReady( const std::string& portName ) const +{ + return _impl->isReady( portName ); } -OutputPortFutures::~OutputPortFutures() -{} +void InFutures::wait( const std::string& portName ) const +{ + _impl->wait( portName ); +} -InputPortFutures::InputPortFutures( const InputPorts& inputPorts ) +void InFutures::waitForAny( const std::string& portName ) const { - for( const auto& inputPort: inputPorts ) - { - const ConstFutures& futures = inputPort->getFutures(); - for( const auto& future: futures ) - _addFuture( future->getName(), future ); - } + return _impl->waitForAny( portName ); } -InputPortFutures::~InputPortFutures() +InFutures::~InFutures() {} + } diff --git a/livre/core/pipeline/PortFutures.h b/livre/core/pipeline/PortFutures.h index 2fb56c85..7ea1ec1b 100644 --- a/livre/core/pipeline/PortFutures.h +++ b/livre/core/pipeline/PortFutures.h @@ -22,71 +22,20 @@ #include #include -#include namespace livre { /** - * The PortFutures class is a wrapper class to access the group of future + * The Futures classes are a wrappers to access the group of future * and execute thread-safe operations on them. With a given portName (name) * many futures can be associated. */ -class PortFutures -{ -public: - - /** - * @param portName is the port name assoicated with futures. If port name - * is ALL_PORTS, all futures are marked to return. - * @return the futures associated with port name. - */ - ConstFutures getFutures( const std::string& portName = ALL_PORTS ) const; - - /** - * Queries if port is ready - * @param portName is the port name assoicated with futures. - * @return true if all port inputs are ready. - * @throw std::runtime_error when there is no future associated with - * given port name - */ - bool isReady( const std::string& portName ) const; - - /** - * Waits all futures associated with port name - * @param portName is the port name assoicated with futures. - * @throw std::runtime_error when there is no future associated with - * given port name - */ - void wait( const std::string& portName ) const; - - /** - * Waits all futures associated with port name. - * @param portName is the port name assoicated with futures. - * @throw std::runtime_error when there is no future associated with - * given port name - */ - void waitForAny( const std::string& portName ) const; - -protected: - - PortFutures(); - - /** - * Adds a future - * @param future future to add - */ - void _addFuture( const std::string& name, const ConstFuturePtr& future ); - - - struct Impl; - std::unique_ptr _impl; -}; /** * PortFutures for managing ports with unique names. */ -class OutputPortFutures : public PortFutures +class OutFutures { public: @@ -95,15 +44,15 @@ class OutputPortFutures : public PortFutures * @param portNames is the list of port names futures to be tagged with. If not given, * future names are used for name-future association. */ - OutputPortFutures( const ConstFutures& futures ); + OutFutures( const Futures& futures ); /** * @param futures the list of futures. * @param portNames is the list of port names futures to be tagged with. If not given, * future names are used for name-future association. */ - OutputPortFutures( const ConstFutures& futures ); - ~OutputPortFutures(); + OutFutures( const Futures& futures ); + ~OutFutures(); /** * Gets the copy of value(s) with the given type T. If input @@ -117,11 +66,7 @@ class OutputPortFutures : public PortFutures template< class T > const T& get( const std::string& portName ) const { - ResultMapT< T > results; - for( const auto& future: getFutures( portName )) - results.insert( std::make_pair( future->getName(), future->get< T >( ))); - - return results[ future->getName() ]; + return getFuture( portName ).get< T >(); } /** @@ -136,19 +81,58 @@ class OutputPortFutures : public PortFutures template< class T > const T&& move( const std::string& portName ) const { - ResultMapT< T > results; - for( const auto& future: getFutures( portName )) - results.insert( std::make_pair( future->getName(), future->move< T >( ))); - - return results[ future->getName() ]; + return getFuture( portName ).move< T >(); } + /** + * @param portName is the port name assoicated with futures. If port name + * is ALL_PORTS, all futures are marked to return. + * @return the futures associated with port name. + */ + Future getFuture( const std::string& portName ) const; + + /** + * @param portName is the port name assoicated with futures. If port name + * is ALL_PORTS, all futures are marked to return. + * @return the futures associated with port name. + */ + Futures getFutures() const; + + /** + * Queries if port is ready + * @param portName is the port name assoicated with futures. + * @return true if all port inputs are ready. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + bool isReady( const std::string& portName ) const; + + /** + * Waits all futures associated with port name + * @param portName is the port name assoicated with futures. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + void wait( const std::string& portName ) const; + + /** + * Waits all futures associated with port name. + * @param portName is the port name assoicated with futures. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + void waitForAny( const std::string& portName ) const; + +private: + + struct Impl; + std::unique_ptr const _impl; }; /** * PortFutures for managing ports with non unique named ports. */ -class InputPortFutures : public PortFutures +class InFutures { public: @@ -156,8 +140,8 @@ class InputPortFutures : public PortFutures * @param inputPorts is the list of input ports * future names are used for name-future association. */ - InputPortFutures( const InputPorts& inputPorts ); - ~InputPortFutures(); + InFutures( const InputPorts& inputPorts ); + ~InFutures(); /** * Gets the copy of value(s) with the given type T. If input @@ -169,11 +153,11 @@ class InputPortFutures : public PortFutures * type T */ template< class T > - ResultMapT< T > get( const std::string& portName ) const + ResultsT< T > get( const std::string& portName ) const { - ResultMapT< T > results; + ResultsT< T > results; for( const auto& future: getFutures( portName )) - results.insert( std::make_pair( future->getName(), future->get< T >( ))); + results.push_back( future->get< T >( )); return results; } @@ -188,11 +172,11 @@ class InputPortFutures : public PortFutures * type T */ template< class T > - ResultMapT< T > move( const std::string& portName ) const + ResultsT< T > move( const std::string& portName ) const { - ResultMapT< T > results; + ResultsT< T > results; for( const auto& future: getFutures( portName )) - results.insert( std::make_pair( future->getName(), future->move< T >( ))); + results.push_back( future->move< T >( )); return results; } @@ -205,15 +189,15 @@ class InputPortFutures : public PortFutures * type T */ template< class T > - ResultMapT< T > getReady( const std::string& portName ) const + ResultsT< T > getReady( const std::string& portName ) const { - ResultMapT< T > results; + ResultsT< T > results; for( const auto& future: getFutures( portName )) { if( !future->isReady()) continue; - results.insert( std::make_pair( future->getName(), future->get< T >( ))); + results.push_back( future->get< T >( )); } return results; } @@ -226,18 +210,23 @@ class InputPortFutures : public PortFutures * type T or there is no future assigned to given port name */ template< class T > - ResultMapT< T > moveReady( const std::string& portName ) const + ResultsT< T > moveReady( const std::string& portName ) const { - ResultMapT< T > results; + ResultsT< T > results; for( const auto& future: getFutures( portName )) { if( !future->isReady()) continue; - results.insert( std::make_pair( future->getName(), future->move< T >( ))); + results.push_back( future->move< T >( )); } return results; } + +private: + + struct Impl; + std::unique_ptr const _impl; }; } diff --git a/livre/core/pipeline/PortInfo.h b/livre/core/pipeline/PortInfo.h index 986ccc38..cbad19fc 100644 --- a/livre/core/pipeline/PortInfo.h +++ b/livre/core/pipeline/PortInfo.h @@ -28,13 +28,13 @@ namespace livre { /** - * Structure that holds the port information ( name, default value ) + * PortInfo holds the port information ( name, data type ) */ struct PortInfo final : public PortType { PortInfo( const std::string& name_, - std::type_index& typeIndex ) - : PortType( typeIndex ) + std::type_index& dataType ) + : PortType( dataType ) , name( portName_ ) {} @@ -43,7 +43,7 @@ struct PortInfo final : public PortType /** * Helper function to create port info. - * @param name is the port name + * @param name is the port name with a type */ template< class T > PortInfo makePortInfo( const std::string& name ) @@ -52,13 +52,14 @@ PortInfo makePortInfo( const std::string& name ) } /** - * Helper function to create port info. + * Helper function to create port info with a known type. * @param name is the port name + * @param dataType data type for the port */ PortInfo makePortInfo( const std::string& name, - const std::type_index& typeIndex ) + const std::type_index& dataType ) { - return PortInfo( name, typeIndex ); + return PortInfo( name, dataType ); } /** diff --git a/livre/core/pipeline/PortPromises.cpp b/livre/core/pipeline/PortPromises.cpp index 850b8a55..7b24dbaf 100644 --- a/livre/core/pipeline/PortPromises.cpp +++ b/livre/core/pipeline/PortPromises.cpp @@ -35,7 +35,7 @@ struct PortPromises::Impl _promiseMap[ promise->getName( )] = promise; } - void throwError( const std::string& portName ) const + void throwPortError( const std::string& portName ) const { std::stringstream err; err << "Unknown port: " << portName << std::endl; @@ -50,7 +50,7 @@ struct PortPromises::Impl void flush( const std::string& portName ) { if( portName != ALL_PORTS && !hasPort( portName )) - throwError( portName ); + throwPortError( portName ); for( const NamePromisePair& namePromisePair: _promiseMap ) { @@ -63,7 +63,7 @@ struct PortPromises::Impl void set( const std::string& portName, ConstPortDataPtr data ) { if( !hasPort( portName )) - throwError( portName ); + throwPortError( portName ); _promiseMap[ portName ]->set( data ); } diff --git a/livre/core/pipeline/PortType.h b/livre/core/pipeline/PortType.h index 389b65ab..a763b9d4 100644 --- a/livre/core/pipeline/PortType.h +++ b/livre/core/pipeline/PortType.h @@ -37,7 +37,7 @@ class PortType * @return the type index */ const std::type_index& getDataType() const - { return _typeIndex; } + { return _dataType; } protected: @@ -46,12 +46,12 @@ class PortType * @param typeIndex type index of the data of the * derived classes data type. */ - PortType( const std::type_index& typeIndex ) - : _typeIndex( typeIndex) {} + PortType( const std::type_index& dataType ) + : _dataType( dataType) {} virtual ~PortData() {} private: - std::type_index _typeIndex; + std::type_index _dataType; }; } diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp index 9507b2c5..8823111e 100644 --- a/livre/core/pipeline/Promise.cpp +++ b/livre/core/pipeline/Promise.cpp @@ -25,30 +25,30 @@ namespace livre struct Promise::Impl { - Impl( const Connection& connection ) - : _connection( connection ) + Impl( const PipeFilter& pipeFilter, const AsyncData& data ) + : _pipeFilter( pipeFilter ) + , _data( data ) + , _future( _pipeFilter, _data ) {} const std::string& getName() const { - return _connection.getName(); + return _data.getName(); } void set( ConstPortDataPtr msg ) { - _connection.set( msg ); + _data.set( msg ); } - ConstFuturePtr getFuture() const - { - return ConstFuturePtr( new Future( _connection )); - } - - const Connection& _connection; + Future _future; + const PipeFilter& _pipeFilter; + const AsyncData& _data; }; -Promise::Promise( const Connection& connection ) - : _impl( new Promise::Impl( connection )) +Promise::Promise( const PipeFilter& pipeFilter, + const AsyncData& data ) + : _impl( new Promise::Impl( pipeFilter, data )) {} Promise::~Promise() @@ -59,14 +59,14 @@ const std::string& Promise::getName() const return _impl->getName(); } -void PortPromise::set( ConstPortDataPtr msg ) +void Promise::set( ConstPortDataPtr msg ) { _impl->getName( msg ); } -ConstFuturePtr PortPromise::getFuture() const +Future Promise::getFuture() const { - return _impl->getFuture(); + return _impl->_future; } } diff --git a/livre/core/pipeline/Promise.h b/livre/core/pipeline/Promise.h index 5c6ee242..30023d88 100644 --- a/livre/core/pipeline/Promise.h +++ b/livre/core/pipeline/Promise.h @@ -20,18 +20,18 @@ #ifndef _Promise_h_ #define _Promise_h_ +#include #include -#include namespace livre { -class PortPromise +class Promise { public: - PortPromise( const Connection& connection ); - ~PortPromise(); + Promise( const PipeFilter& pipeFilter, const AsyncData& data ); + ~Promise(); const std::string& getName() const; @@ -43,7 +43,7 @@ class PortPromise /** * @return the future, that can be queried for data retrieval */ - ConstFuturePtr getFuture() const; + Future getFuture() const; private: diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h index d5c84d97..e8cf9c42 100644 --- a/livre/core/pipeline/SimpleExecutor.h +++ b/livre/core/pipeline/SimpleExecutor.h @@ -27,14 +27,15 @@ namespace livre { /** - * SimpleExecutor class provides the simplest implementation - * for the @see Executor class. The submitted pipelines are - * pushed to the worker threads. The pipeline submission - * is thread safe. + * SimpleExecutor class provides a very basic implementation + * for the @see Executor class. The submitted executables are + * pushed to the worker threads without any real scheduling. + * The pipeline submission is thread safe. * * The scheduler implemented in this class, just pushes the * executables without re-ordering. This may mean that if - * all workers are blocked, the processing can suspend. + * all workers are blocked, the processing can suspend. This + * is a push based executor. * */ class SimpleExecutor : public Executor diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp index 23a2651e..ee5d65ac 100644 --- a/livre/core/pipeline/Workers.cpp +++ b/livre/core/pipeline/Workers.cpp @@ -99,15 +99,12 @@ Workers::Workers( size_t nThreads, : _impl( new Workers::Impl( *this, nThreads, glContext )) -{ -} +{} Workers::~Workers() -{ - -} +{} -Future Workers::execute( ExecutablePtr executable ) +void Workers::execute( ExecutablePtr executable ) { _impl->submitWork( executable ); } diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index 86fdad5a..34792cc9 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -48,7 +48,7 @@ class Workers * threads. * @param executable is executed by thread pool. */ - Future execute( ExecutablePtr executable ); + void execute( ExecutablePtr executable ); /** * @return the size of thread pool. diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index c428bcfd..14c8a3a6 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -53,10 +53,10 @@ struct OutputData class TestFilter : public livre::Filter { - void execute( const livre::InputPortFutures& input, livre::PortPromises& output ) const final + void execute( const livre::InFutures& input, livre::PortPromises& output ) const final { - const livre::ResultMapT< InputData >& result = input.get< InputData >( "InputData" ); + const livre::ResultsT< InputData >& result = input.get< InputData >( "InputData" ); OutputData outputData; for( const auto& pair: result ) @@ -86,14 +86,13 @@ class TestFilter : public livre::Filter class ConvertFilter : public livre::Filter { - void execute( const livre::InputPortFutures& input, livre::PortPromises& output ) const final + void execute( const livre::InFutures& input, livre::PortPromises& output ) const final { - - const livre::ResultMapT< OutputData >& result = input.get< OutputData >( "ConvertInputData" ); + const livre::ResultsT< OutputData >& result = input.get< OutputData >( "ConvertInputData" ); InputData inputData; inputData.meaningOfLife = result[ "TestOutputData" ].thanksForAllTheFish + addMoreFish; - pipeFilter.setOutput( "ConvertOutputData", inputData ); + output.set( "ConvertOutputData", inputData ); } livre::PortInfos getInputPorts() const final @@ -116,9 +115,9 @@ bool check_error( const std::runtime_error& ) { return true; } BOOST_AUTO_TEST_CASE( testFilterNoInput ) { livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( filter )); + livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); pipeFilter->execute(); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, defaultThanksForAllTheFish ); } @@ -126,13 +125,13 @@ BOOST_AUTO_TEST_CASE( testFilterNoInput ) BOOST_AUTO_TEST_CASE( testFilterWithInput ) { livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( filter )); + livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); const uint32_t inputValue = 90; const livre::PortPromises portPromises( pipeFilter->getPromises( )); portPromises->set( "InputData", InputData( inputValue )); pipeFilter->execute(); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 151 ); @@ -141,13 +140,13 @@ BOOST_AUTO_TEST_CASE( testFilterWithInput ) BOOST_AUTO_TEST_CASE( testSetAndGetWrongParameters ) { livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( filter )); + livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); const livre::PortPromises portPromises( pipeFilter->getPromises( )); BOOST_CHECK_EXCEPTION( portPromises.set( "TestInputData", OutputData( 0 )), std::runtime_error, check_error ); pipeFilter->execute(); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures()); + const livre::OutFutures portFutures( pipeFilter->getOutFutures()); BOOST_CHECK_EXCEPTION( portFutures.get( "TestOutputData" ), std::runtime_error, check_error ); } @@ -155,8 +154,8 @@ BOOST_AUTO_TEST_CASE( testSetAndGetWrongParameters ) BOOST_AUTO_TEST_CASE( testInvalidConnection ) { livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter1( new livre::PipeFilter( filter )); - livre::PipeFilterPtr pipeFilter2( new livre::PipeFilter( filter )); + livre::PipeFilterPtr pipeFilter1( new livre::PipeFilter( "Producer", filter )); + livre::PipeFilterPtr pipeFilter2( new livre::PipeFilter( "Consumer", filter )); BOOST_CHECK_EXCEPTION( pipeFilter1->connect( "TestOutputData", pipeFilter2, @@ -167,11 +166,11 @@ BOOST_AUTO_TEST_CASE( testInvalidConnection ) BOOST_AUTO_TEST_CASE( testConnection ) { livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeInput( new livre::PipeFilter( filter ) ); - livre::PipeFilterPtr pipeOutput( new livre::PipeFilter( filter ) ); + livre::PipeFilterPtr pipeInput( new livre::PipeFilter( "Producer", filter ) ); + livre::PipeFilterPtr pipeOutput( new livre::PipeFilter( "Consumer", filter ) ); livre::FilterPtr convertFilter( new ConvertFilter( )); - livre::PipeFilterPtr convertPipeFilter( new livre::PipeFilter( convertFilter ) ); + livre::PipeFilterPtr convertPipeFilter( new livre::PipeFilter( "Converter", convertFilter ) ); pipeInput->connectFilters( "TestOutputData", convertPipeFilter, "ConvertInputData" ); convertPipeFilter->connect( "ConvertOutputData", pipeOutput, "TestInputData" ); @@ -183,7 +182,7 @@ BOOST_AUTO_TEST_CASE( testConnection ) convertPipeFilter->execute(); pipeOutput->execute(); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); const OutputData& outputData = portFutures->get( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); @@ -195,13 +194,13 @@ livre::PipelinePtr createPipeline( livre::PipeFilterPtr& pipeOutput, { livre::FilterPtr filter( new TestFilter( )); livre::PipelinePtr pipeline( new livre::Pipeline( )); - livre::PipeFilterPtr pipeInput = pipeline->add( filter ); - pipeOutput = pipeline->add( filter ); + livre::PipeFilterPtr pipeInput = pipeline->add( "Producer", filter ); + pipeOutput = pipeline->add( "Consumer", filter ); livre::FilterPtr convertFilter( new ConvertFilter( )); for( size_t i = 0; i < nConvertFilter; ++i ) { - livre::PipeFilterPtr convertPipeFilter = pipeline->add( convertFilter ); + livre::PipeFilterPtr convertPipeFilter = pipeline->add( "Converter", convertFilter ); pipeInput->connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); convertPipeFilter->connect( "ConvertInputData", pipeOutput, "TestInputData" ); } @@ -225,7 +224,7 @@ BOOST_AUTO_TEST_CASE( testSynchronousPipeline ) livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); pipeline->execute(); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -237,10 +236,10 @@ BOOST_AUTO_TEST_CASE( testWaitPipeline ) livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); livre::ExecutorPtr executor = createExecutor(); - const livre::OutputPortFutures pipelineFutures( executor->execute( pipeline )); + const livre::OutFutures pipelineFutures( executor->execute( pipeline->getExecutables( ))); pipelineFutures->wait(); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -252,9 +251,9 @@ BOOST_AUTO_TEST_CASE( testAsynchronousPipeline ) livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); livre::ExecutorPtr executor = createExecutor(); - executor->execute( pipeline ); + executor->execute( pipeline->getExecutables( )); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -268,9 +267,9 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) inputValue, convertFilterCount ); livre::ExecutorPtr executor = createExecutor(); - executor->execute( pipeline ); + executor->execute( pipeline->getExecutables( )); - const livre::OutputPortFutures portFutures( pipeFilter->getOutputFutures( )); + const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 1761 ); } From 03d5093bec2e19685fd5c99f5aeb9b53114fb18f Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Thu, 3 Mar 2016 14:38:42 +0100 Subject: [PATCH 03/17] Fixes for the comments --- livre/core/CMakeLists.txt | 32 +++- livre/core/pipeline/Connection.h | 2 +- livre/core/pipeline/Executable.h | 26 ++-- livre/core/pipeline/Executor.h | 14 +- livre/core/pipeline/Filter.h | 11 +- livre/core/pipeline/FunctionFilter.cpp | 16 +- livre/core/pipeline/FunctionFilter.h | 6 +- livre/core/pipeline/Future.cpp | 27 ++-- livre/core/pipeline/Future.h | 6 +- .../{PortFutures.cpp => FutureMap.cpp} | 117 ++++++++++----- .../pipeline/{PortFutures.h => FutureMap.h} | 135 ++++++++++++----- livre/core/pipeline/InputPort.cpp | 14 +- livre/core/pipeline/InputPort.h | 6 +- livre/core/pipeline/OutputPort.cpp | 75 ++++++---- livre/core/pipeline/OutputPort.h | 15 +- livre/core/pipeline/PipeFilter.cpp | 95 ++++++------ livre/core/pipeline/PipeFilter.h | 9 +- livre/core/pipeline/Pipeline.cpp | 36 ++--- livre/core/pipeline/Pipeline.h | 14 +- livre/core/pipeline/PortData.h | 19 +-- livre/core/pipeline/PortInfo.h | 16 +- livre/core/pipeline/PortType.h | 7 +- livre/core/pipeline/Promise.cpp | 31 ++-- livre/core/pipeline/Promise.h | 36 ++++- .../{PortPromises.cpp => PromiseMap.cpp} | 32 ++-- .../pipeline/{PortPromises.h => PromiseMap.h} | 37 +++-- livre/core/pipeline/SimpleExecutor.cpp | 57 ++++--- livre/core/pipeline/SimpleExecutor.h | 12 +- livre/core/pipeline/Workers.cpp | 4 +- livre/core/pipeline/Workers.h | 2 +- livre/core/render/GLContext.h | 5 + livre/eq/render/EqContext.cpp | 13 +- livre/eq/render/EqContext.h | 7 +- tests/pipeline/pipeline.cpp | 139 +++++++++++------- 34 files changed, 683 insertions(+), 390 deletions(-) rename livre/core/pipeline/{PortFutures.cpp => FutureMap.cpp} (52%) rename livre/core/pipeline/{PortFutures.h => FutureMap.h} (70%) rename livre/core/pipeline/{PortPromises.cpp => PromiseMap.cpp} (70%) rename livre/core/pipeline/{PortPromises.h => PromiseMap.h} (70%) diff --git a/livre/core/CMakeLists.txt b/livre/core/CMakeLists.txt index e37f06ec..15b5b2d5 100644 --- a/livre/core/CMakeLists.txt +++ b/livre/core/CMakeLists.txt @@ -55,7 +55,23 @@ set(LIVRECORE_HEADERS util/ThreadClock.h visitor/NodeVisitor.h visitor/RenderNodeVisitor.h - visitor/VisitState.h) + visitor/VisitState.h + + pipeline/Executable.h + pipeline/Filter.h + pipeline/FunctionFilter.h + pipeline/Future.h + pipeline/FutureMap.h + pipeline/InputPort.h + pipeline/OutputPort.h + pipeline/PipeFilter.h + pipeline/Pipeline.h + pipeline/PortData.h + pipeline/PortType.h + pipeline/Promise.h + pipeline/PromiseMap.h + pipeline/SimpleExecutor.h + pipeline/Workers.h ) set(LIVRECORE_SOURCES cache/Cache.cpp @@ -93,7 +109,19 @@ set(LIVRECORE_SOURCES util/ThreadClock.cpp util/Utilities.cpp visitor/RenderNodeVisitor.cpp - visitor/VisitState.cpp) + visitor/VisitState.cpp + + pipeline/FunctionFilter.cpp + pipeline/Future.cpp + pipeline/FutureMap.cpp + pipeline/InputPort.cpp + pipeline/OutputPort.cpp + pipeline/PipeFilter.cpp + pipeline/Pipeline.cpp + pipeline/Promise.cpp + pipeline/PromiseMap.cpp + pipeline/SimpleExecutor.cpp + pipeline/Workers.cpp ) set(LIVRECORE_LINK_LIBRARIES PUBLIC ${Boost_LIBRARIES} dash Collage Lexis Lunchbox vmmlib diff --git a/livre/core/pipeline/Connection.h b/livre/core/pipeline/Connection.h index cd0f8e9b..46bf1826 100644 --- a/livre/core/pipeline/Connection.h +++ b/livre/core/pipeline/Connection.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h index eafc1253..32eeac1d 100644 --- a/livre/core/pipeline/Executable.h +++ b/livre/core/pipeline/Executable.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -27,34 +27,36 @@ namespace livre { /** - * The Executable class is the base class for objects that can be executed by workers. + * The Executable class is the base class for objects that can be executed by workers. It + * provides extra pre/post conditions as futures to retrieve the current situation. + * + * According to given futures executors can decide on scheduling algorithms. Also the + * input and are output futures can be queried for the results. @see PipeFilter and + * @see Pipeline classes are based on this class. */ class Executable { public: Executable() {} + virtual ~Executable() {} + /** * Executes the executable */ virtual void execute() = 0; /** - * @return the input futures which the executable provides to wait. The - * names of the futures are unique. + * @return the output futures for querying the outputs of the executable. */ - virtual Futures getOutFutures() const { return Futures(); } + virtual Futures getPostconditions() const { return Futures(); } /** - * @return the input futures which the executable is waiting to proceed. - * The names of the futures not necessarily unique. The inputs accepts - * multiple outputs with the same name. + * @return the input futures which the executable can be queried for the state or + * data retrieval. */ - virtual Futures getConnectedInFutures() const { return Futures(); } + virtual Futures getPreconditions() const { return Futures(); } -protected: - - virtual ~Executable() {} }; } diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h index cdbc7876..3e810281 100644 --- a/livre/core/pipeline/Executor.h +++ b/livre/core/pipeline/Executor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -20,13 +20,12 @@ #ifndef _Executor_h_ #define _Executor_h_ -#include #include +#include namespace livre { - /** * Executor class is the base class for implementing different scheduling * algorithms for submited work. i.e. The IO or CPU intensive algorithms @@ -42,9 +41,9 @@ class Executor * Executes the executable. Returns the futures that can be queried for data. * @param pipeline to be executed. */ - Futures execute( ExecutablePtr executable ) + Futures execute( const ExecutablePtr& executable ) { - const Futures& fs = _executable->getOutFutures(); + const Futures& fs = executable->getPostconditions(); _schedule( { executable } ); return fs; } @@ -58,8 +57,8 @@ class Executor Futures futures; for( const ExecutablePtr& executable: executables ) { - const Futures& fs = executable->getOutFutures(); - futures.insert( futures.back(), fs.begin(), fs.end( )); + const Futures& fs = executable->getPostconditions( ); + futures.insert( futures.end(), fs.begin(), fs.end( )); } _schedule( executables ); @@ -78,6 +77,7 @@ class Executor * Clears the executor */ virtual void clear() {} + }; } diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h index d6414743..c04d972d 100644 --- a/livre/core/pipeline/Filter.h +++ b/livre/core/pipeline/Filter.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -21,14 +21,13 @@ #define _Filter_h_ #include -#include #include namespace livre { /** - * Filters are similar to functions. Their inputs and + * Filters are similar to functions (immutable). Their inputs and * outputs are provided through ports. These ports provide * thread safe information retrieval, setting and querying. * @@ -37,9 +36,7 @@ namespace livre * have their unique names and these names are used to query, * retrieve and set data. * - * Execution part of filters can be thought as functions and - * port definitions can be thought as inputs and outputs to - * those functions. PipeFilters build the connection and execution + * PipeFilters class build the connection and execution * functionality around filter instances. */ @@ -53,7 +50,7 @@ class Filter * @param input The Future that can be read for input parameters * @param output The Promise that can be written to for output parameters */ - virtual void execute( const InFutures& input, PortPromises& output ) const = 0; + virtual void execute( const InFutureMap& input, PromiseMap& output ) const = 0; /** * @param inputPorts information is filled by the Filter class. diff --git a/livre/core/pipeline/FunctionFilter.cpp b/livre/core/pipeline/FunctionFilter.cpp index eda9e94b..53398cdc 100644 --- a/livre/core/pipeline/FunctionFilter.cpp +++ b/livre/core/pipeline/FunctionFilter.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -33,9 +33,9 @@ struct FunctionFilter::Impl , _outputPorts( outputPorts ) {} - void execute( const InFutures& input, PortPromises& output ) const + void execute( const InFutureMap& input, PromiseMap& output ) const { - _filterFunc( filter ); + _filterFunc( input, output ); } PortInfos getInputPorts() const @@ -43,7 +43,7 @@ struct FunctionFilter::Impl return _inputPorts; } - PortInfos getInputPorts() const + PortInfos getOutputPorts() const { return _outputPorts; } @@ -67,19 +67,19 @@ FunctionFilter::FunctionFilter( const FilterFunc& filterFunc, FunctionFilter::~FunctionFilter() {} -void FunctionFilter::execute( const InFutures& input, PortPromises& output ) const +void FunctionFilter::execute( const InFutureMap& input, PromiseMap& output ) const { _impl->execute( input, output ); } PortInfos FunctionFilter::getInputPorts() const { - _impl->getInputPorts(); + return _impl->getInputPorts(); } -PortInfos FunctionFilter::getOutputPorts( ) const +PortInfos FunctionFilter::getOutputPorts() const { - _impl->getOutputPorts(); + return _impl->getOutputPorts(); } } diff --git a/livre/core/pipeline/FunctionFilter.h b/livre/core/pipeline/FunctionFilter.h index d0ad23bc..896effa5 100644 --- a/livre/core/pipeline/FunctionFilter.h +++ b/livre/core/pipeline/FunctionFilter.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -47,7 +47,7 @@ struct FunctionFilter final : public Filter /** * @copydoc Filter::execute( PipeFilter& filter ) */ - void execute( const InFutures& input, PortPromises& output ) const final; + void execute( const InFutureMap& input, PromiseMap& output ) const final; /** * @copydoc Filter::getInputPorts() @@ -62,7 +62,7 @@ struct FunctionFilter final : public Filter private: struct Impl; - std::unique_ptr _impl; + std::shared_ptr _impl; }; } diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp index d91539b2..b66edf63 100644 --- a/livre/core/pipeline/Future.cpp +++ b/livre/core/pipeline/Future.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -19,6 +19,8 @@ #include +#include + namespace livre { @@ -35,14 +37,19 @@ struct Future::Impl return _data.getName(); } - void set( const ConstPortDataPtr& data ) + ConstPortDataPtr get() const { - _data.set( data ); + return _data.get(); } - ConstPortDataPtr get() const + bool isReady() const { - return _data.get(); + return _data.isReady(); + } + + void wait() const + { + return _data.wait(); } const PipeFilter& _pipeFilter; @@ -67,6 +74,11 @@ const std::string& Future::getName() const return _impl->getName(); } +void Future::wait() const +{ + return _impl->wait(); +} + bool Future::isReady() const { return _impl->isReady(); @@ -77,11 +89,6 @@ const PipeFilter& Future::getPipeFilter() const return _impl->_pipeFilter; } -void Future::_set( const ConstPortDataPtr& data ) -{ - _impl->set( data ); -} - ConstPortDataPtr Future::_get() const { return _impl->get(); diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h index 799d6355..5d609f4d 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/Future.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -20,6 +20,7 @@ #ifndef _Future_h_ #define _Future_h_ +#include #include namespace livre @@ -101,9 +102,8 @@ class Future private: - friend livre::waitForAny( const Futures& future ); + friend bool livre::waitForAny( const Futures& future ); - void _set( const ConstPortDataPtr& data ); ConstPortDataPtr _get() const; struct Impl; diff --git a/livre/core/pipeline/PortFutures.cpp b/livre/core/pipeline/FutureMap.cpp similarity index 52% rename from livre/core/pipeline/PortFutures.cpp rename to livre/core/pipeline/FutureMap.cpp index 764d1ef4..6af3a385 100644 --- a/livre/core/pipeline/PortFutures.cpp +++ b/livre/core/pipeline/FutureMap.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -17,16 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include +#include +#include +#include namespace livre { -typedef std::multimap< std::string, ConstFuturePtr > NameFutureMap; -typedef std::pair< std::string, ConstFuturePtr > NameFuturePair; +typedef std::multimap< std::string, Future > NameFutureMap; +typedef std::pair< std::string, Future > NameFuturePair; -class FutureMap +struct FutureMapImpl { public: @@ -46,7 +47,9 @@ class FutureMap if( portName == ALL_PORTS ) { Futures futures; - futures.insert( futures.end(), _futureMap.begin(), _futureMap.end( )); + futures.reserve( _futureMap.size( )); + for( const auto& pair: _futureMap ) + futures.push_back( pair.second ); return futures; } @@ -55,15 +58,21 @@ class FutureMap Futures futures; NameFutureMap::const_iterator it = _futureMap.find( portName ); - futures.insert( futures.end(), it, _futureMap.end( )); + + while( it != _futureMap.end( )) + { + futures.push_back( it->second ); + ++it; + } + return futures; } - bool isReady() const + bool isReady( const std::string& portName ) const { for( const auto& future: getFutures( portName )) { - if( !future->isReady()) + if( !future.isReady()) return false; } return true; @@ -72,30 +81,70 @@ class FutureMap void wait( const std::string& portName ) const { for( const auto& future: getFutures( portName )) - future->wait(); + future.wait(); } - void waitForAny( const std::string& portName ) const + bool waitForAny( const std::string& portName ) const { return livre::waitForAny( getFutures( portName )); } - void addFuture( const std::string& name, const ConstFuturePtr& future ) + void addFuture( const std::string& name, const Future& future ) { - _futureMap[ name ] = future; + _futureMap.insert( std::make_pair( name, future )); } NameFutureMap _futureMap; }; -struct OutFutures::Impl: public FutureMap +struct FutureMap::Impl: public FutureMapImpl { public: Impl( const Futures& futures ) { for( const auto& future: futures ) { - const std::string& name = future->getName(); + const std::string& name = future.getName(); + addFuture( name, future ); + } + } +}; + +FutureMap::FutureMap( const Futures& futures ) + : _impl( new FutureMap::Impl( futures )) +{} + +Futures FutureMap::getFutures() const +{ + return _impl->getFutures( ALL_PORTS ); +} + +bool FutureMap::isReady() const +{ + return _impl->isReady( ALL_PORTS ); +} + +void FutureMap::wait() const +{ + _impl->wait( ALL_PORTS ); +} + +bool FutureMap::waitForAny() const +{ + return _impl->waitForAny( ALL_PORTS ); +} + +FutureMap::~FutureMap() +{} + +struct OutFutureMap::Impl: public FutureMapImpl +{ +public: + Impl( const Futures& futures ) + { + for( const auto& future: futures ) + { + const std::string& name = future.getName(); if( hasPort( name )) throwPortError( name ); addFuture( name, future ); @@ -103,39 +152,39 @@ struct OutFutures::Impl: public FutureMap } }; -OutFutures::OutFutures( const Futures& futures ) - : _impl( new OutFutures::Impl( futures )) +OutFutureMap::OutFutureMap( const Futures& futures ) + : _impl( new OutFutureMap::Impl( futures )) {} -Futures OutFutures::getFutures() const +Futures OutFutureMap::getFutures() const { return _impl->getFutures( ALL_PORTS ); } -Future OutFutures::getFuture( const std::string& portName ) const +Future OutFutureMap::getFuture( const std::string& portName ) const { - return _impl->getFuture(); + return _impl->getFutures( portName )[ 0 ]; } -bool OutFutures::isReady( const std::string& portName ) const +bool OutFutureMap::isReady( const std::string& portName ) const { return _impl->isReady( portName ); } -void OutFutures::wait( const std::string& portName ) const +void OutFutureMap::wait( const std::string& portName ) const { _impl->wait( portName ); } -void OutFutures::waitForAny( const std::string& portName ) const +bool OutFutureMap::waitForAny() const { - return _impl->waitForAny( portName ); + return _impl->waitForAny( ALL_PORTS ); } -OutFutures::~OutFutures() +OutFutureMap::~OutFutureMap() {} -struct InFutures::Impl: public FutureMap +struct InFutureMap::Impl: public FutureMapImpl { public: Impl( const InputPorts& inputPorts ) @@ -149,32 +198,32 @@ struct InFutures::Impl: public FutureMap } }; -InFutures::InFutures( const InputPorts& inputPorts ) - : _impl( new InFutures::Impl( inputPorts )) +InFutureMap::InFutureMap( const InputPorts& inputPorts ) + : _impl( new InFutureMap::Impl( inputPorts )) { } -Futures InFutures::getFutures( const std::string& portName /* = ALL_PORTS */ ) const +Futures InFutureMap::getFutures( const std::string& portName ) const { return _impl->getFutures( portName ); } -bool InFutures::isReady( const std::string& portName ) const +bool InFutureMap::isReady( const std::string& portName ) const { return _impl->isReady( portName ); } -void InFutures::wait( const std::string& portName ) const +void InFutureMap::wait( const std::string& portName ) const { _impl->wait( portName ); } -void InFutures::waitForAny( const std::string& portName ) const +bool InFutureMap::waitForAny( const std::string& portName ) const { return _impl->waitForAny( portName ); } -InFutures::~InFutures() +InFutureMap::~InFutureMap() {} diff --git a/livre/core/pipeline/PortFutures.h b/livre/core/pipeline/FutureMap.h similarity index 70% rename from livre/core/pipeline/PortFutures.h rename to livre/core/pipeline/FutureMap.h index 7ea1ec1b..27976dcd 100644 --- a/livre/core/pipeline/PortFutures.h +++ b/livre/core/pipeline/FutureMap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -17,11 +17,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _PortFutures_h_ -#define _PortFutures_h_ +#ifndef _FutureMap_h_ +#define _FutureMap_h_ #include -#include +#include namespace livre { @@ -33,26 +33,59 @@ namespace livre */ /** - * PortFutures for managing ports with unique names. + * FutureMap class provides basic functionality to query state of multiple futures. */ -class OutFutures +class FutureMap { public: /** * @param futures the list of futures. - * @param portNames is the list of port names futures to be tagged with. If not given, - * future names are used for name-future association. */ - OutFutures( const Futures& futures ); + explicit FutureMap( const Futures& futures ); + ~FutureMap(); + + /** + * @return the futures associated with port name. + */ + Futures getFutures() const; + + /** + * Queries if all ports are ready + * @return true if all port inputs are ready. + */ + bool isReady() const; + + /** + * Waits all futures + */ + void wait() const; + + /** + * Waits for any futures + * @return true if any future is waited. + */ + bool waitForAny() const; + +private: + + struct Impl; + std::shared_ptr _impl; +}; + +/** + * PortFutures for managing ports with unique names. + */ +class OutFutureMap +{ +public: /** * @param futures the list of futures. - * @param portNames is the list of port names futures to be tagged with. If not given, - * future names are used for name-future association. + * @throws std::runtime_error when futures are not unique in names */ - OutFutures( const Futures& futures ); - ~OutFutures(); + explicit OutFutureMap( const Futures& futures ); + ~OutFutureMap(); /** * Gets the copy of value(s) with the given type T. If input @@ -85,7 +118,7 @@ class OutFutures } /** - * @param portName is the port name assoicated with futures. If port name + * @param portName is the port name assoicated with the future. If port name * is ALL_PORTS, all futures are marked to return. * @return the futures associated with port name. */ @@ -94,45 +127,43 @@ class OutFutures /** * @param portName is the port name assoicated with futures. If port name * is ALL_PORTS, all futures are marked to return. - * @return the futures associated with port name. + * @return the future associated with port name. */ Futures getFutures() const; /** * Queries if port is ready - * @param portName is the port name assoicated with futures. + * @param portName is the port name assoicated with the future. * @return true if all port inputs are ready. * @throw std::runtime_error when there is no future associated with * given port name */ - bool isReady( const std::string& portName ) const; + bool isReady( const std::string& portName = ALL_PORTS ) const; /** - * Waits all futures associated with port name + * Waits for the future associated with port name * @param portName is the port name assoicated with futures. * @throw std::runtime_error when there is no future associated with * given port name */ - void wait( const std::string& portName ) const; + void wait( const std::string& portName = ALL_PORTS ) const; /** - * Waits all futures associated with port name. - * @param portName is the port name assoicated with futures. - * @throw std::runtime_error when there is no future associated with - * given port name + * Waits for any futures. + * @return true if any future is waited. */ - void waitForAny( const std::string& portName ) const; + bool waitForAny() const; private: struct Impl; - std::unique_ptr const _impl; + std::shared_ptr _impl; }; /** * PortFutures for managing ports with non unique named ports. */ -class InFutures +class InFutureMap { public: @@ -140,8 +171,8 @@ class InFutures * @param inputPorts is the list of input ports * future names are used for name-future association. */ - InFutures( const InputPorts& inputPorts ); - ~InFutures(); + explicit InFutureMap( const InputPorts& inputPorts ); + ~InFutureMap(); /** * Gets the copy of value(s) with the given type T. If input @@ -157,7 +188,7 @@ class InFutures { ResultsT< T > results; for( const auto& future: getFutures( portName )) - results.push_back( future->get< T >( )); + results.push_back( future.get< T >( )); return results; } @@ -176,7 +207,7 @@ class InFutures { ResultsT< T > results; for( const auto& future: getFutures( portName )) - results.push_back( future->move< T >( )); + results.push_back( future.move< T >( )); return results; } @@ -194,10 +225,10 @@ class InFutures ResultsT< T > results; for( const auto& future: getFutures( portName )) { - if( !future->isReady()) + if( !future.isReady()) continue; - results.push_back( future->get< T >( )); + results.push_back( future.get< T >( )); } return results; } @@ -215,20 +246,52 @@ class InFutures ResultsT< T > results; for( const auto& future: getFutures( portName )) { - if( !future->isReady()) + if( !future.isReady()) continue; - results.push_back( future->move< T >( )); + results.push_back( future.move< T >( )); } return results; } + /** + * @param portName is the port name assoicated with futures. If port name + * is ALL_PORTS, all futures are marked to return. + * @return the futures associated with port name. + */ + Futures getFutures( const std::string& portName ) const; + + /** + * Queries if port is ready + * @param portName is the port name assoicated with futures. + * @return true if all port inputs are ready. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + bool isReady( const std::string& portName ) const; + + /** + * Waits all futures associated with port name + * @param portName is the port name assoicated with futures. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + void wait( const std::string& portName ) const; + + /** + * Waits all futures associated with port name. + * @param portName is the port name assoicated with futures. + * @throw std::runtime_error when there is no future associated with + * given port name + */ + bool waitForAny( const std::string& portName ) const; + private: struct Impl; - std::unique_ptr const _impl; + std::shared_ptr _impl; }; } -#endif // _PortFutures_h_ +#endif // _FutureMap_h_ diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp index fa2b807d..c43d9a8f 100644 --- a/livre/core/pipeline/InputPort.cpp +++ b/livre/core/pipeline/InputPort.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -36,7 +36,7 @@ struct InputPort::Impl const std::string& getName() const { - return _info.portName; + return _info.name; } size_t getSize() const @@ -51,10 +51,10 @@ struct InputPort::Impl void connect( const OutputPort& outputPort ) { - if( getDataType() != outputPort->getDataType( )) - LB_THROW( std::exception( "Data types does not match between ports")); + if( getDataType() != outputPort.getDataType( )) + LBTHROW( std::runtime_error( "Data types does not match between ports")); - _futures.push_back( outputPort.getPromise()-getFuture( )); + _futures.push_back( outputPort.getPromise()->getFuture( )); } Futures _futures; @@ -68,9 +68,9 @@ InputPort::InputPort( const PortInfo& portInfo ) InputPort::~InputPort() {} -Futures InputPort::getFutures() const +const Futures& InputPort::getFutures() const { - return _impl->getFutures(); + return _impl->_futures; } void InputPort::connect( const OutputPort& outputPort ) diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index 58d2bd52..9363406a 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -39,7 +39,7 @@ class InputPort * InputPort constructor based on port information * @param portInfo is the port information */ - InputPort( const PortInfo& portInfo ); + explicit InputPort( const PortInfo& portInfo ); ~InputPort(); /** @@ -60,7 +60,7 @@ class InputPort /** * @return Return all the input futures that port has. */ - Futures getFutures() const; + const Futures& getFutures() const; /** * Connects an output port to input port diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp index 8daf9a4f..314aab0b 100644 --- a/livre/core/pipeline/OutputPort.cpp +++ b/livre/core/pipeline/OutputPort.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -26,62 +27,79 @@ namespace livre { - typedef boost::shared_future< ConstPortDataPtr > ConstPortDataFuture; typedef boost::promise< ConstPortDataPtr > ConstPortDataPromise; typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; +namespace +{ + /* Boost wait_for_any implementation uses the internal locks from the futures. + Therefore, the get/set/query operations on promises/futures causes deadlocks + when used with wait_for_any( futurelist ) if futurelist is including the + future to be queried. With below implementation no locking is needed between + future operations. A higher granularity can be added for checking whet */ + + ReadWriteMutex waitForAnyLock; +} + struct AsyncData::Impl { - Impl( const std::string name ) + Impl( const std::string& name, + const std::type_index& dataType ) : _future( _promise.get_future( )) , _name( name ) + , _dataType( dataType ) {} ~Impl() { if( !isReady()) - _promise.set_value( result ); + _promise.set_value( ConstPortDataPtr( )); } - ConstPortDataPtr get() const + const ConstPortDataPtr& get() const { + ReadLock lock( waitForAnyLock ); return _future.get(); } void set( const ConstPortDataPtr& data ) { - if( result ) + if( data ) { - if( data->getDataType() != _info->getDataType( )) + if( data->getDataType() != _dataType ) LBTHROW( std::runtime_error( "Types does not match on set value")); } - if( !isReady()) - _promise.set_value( result ); + ReadLock lock( waitForAnyLock ); + if( !_future.is_ready( )) + _promise.set_value( data ); } bool isReady() const { + ReadLock lock( waitForAnyLock ); return _future.is_ready(); } void wait() const { + ReadLock lock( waitForAnyLock ); _future.wait(); } - const PipeFilter& _pipeFilter; ConstPortDataPromise _promise; mutable ConstPortDataFuture _future; const std::string _name; + const std::type_index _dataType; }; -AsyncData::AsyncData( const std::string& name ) - : _impl( new Impl( pipeFilter, name )) +AsyncData::AsyncData( const std::string& name, + const std::type_index& dataType ) + : _impl( new Impl( name, dataType )) {} -ConstPortDataPtr AsyncData::get() const +const ConstPortDataPtr& AsyncData::get() const { return _impl->get(); } @@ -111,7 +129,7 @@ struct OutputPort::Impl { Impl( const PipeFilter& pipeFilter, const PortInfo& portInfo ) : _info( portInfo ) - , _data( portInfo.name ) + , _data( portInfo.name, portInfo.getDataType( )) , _portPromise( new Promise( pipeFilter, _data )) {} @@ -127,10 +145,10 @@ struct OutputPort::Impl const std::string& getName() const { - return _info.portName; + return _info.name; } - PortInfo _info; + const PortInfo _info; AsyncData _data; PromisePtr _portPromise; }; @@ -153,11 +171,6 @@ const std::type_index& OutputPort::getDataType() const return _impl->_info.getDataType(); } -ConstFuturePtr OutputPort::getFuture() const -{ - return _impl->_portFuture; -} - PromisePtr OutputPort::getPromise() const { return _impl->_portPromise; @@ -165,22 +178,24 @@ PromisePtr OutputPort::getPromise() const void OutputPort::connect( InputPort& inputPort ) { - _inputPort->connect( *this ); + inputPort.connect( *this ); } bool waitForAny( const Futures& futures ) { - ConstPortDataFutures futures; - for( const auto& future: futures ) - { - if( !future->isReady()) - futures.push_back( future->getAsyncData()._impl->_future ); - } - if( futures.empty( )) return false; - boost::wait_for_any( futures.begin(), futures.end( )); + ConstPortDataFutures boostFutures; + boostFutures.reserve( futures.size( )); + for( const auto& future: futures ) + boostFutures.push_back( future.getAsyncData()._impl->_future ); + + WriteLock lock( waitForAnyLock, boost::try_to_lock ); + if( !lock.owns_lock( )) + return true; + + boost::wait_for_any( boostFutures.begin(), boostFutures.end( )); return true; } diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h index 74440870..dd6c5276 100644 --- a/livre/core/pipeline/OutputPort.h +++ b/livre/core/pipeline/OutputPort.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -37,8 +37,10 @@ class AsyncData * When connection is instantiated the data is not * set yet, so any get() call will block the retrieval * @param name of the connection + * @param dataType type of the data */ - AsyncData( const PipeFilter& pipeFilter, const std::string& name ); + AsyncData( const std::string& name, + const std::type_index& dataType ); /** * @return the name of the connection @@ -48,12 +50,12 @@ class AsyncData /** * @param data sets the data */ - void set( ConstPortDataPtr data ); + void set( const ConstPortDataPtr& data ); /** * @return the data. If data is not set it will block. */ - ConstPortDataPtr get() const; + const ConstPortDataPtr& get() const; /** * @return true if data is set. @@ -71,10 +73,13 @@ class AsyncData * Waits for any future to be ready. * @param futures queried to be ready. * @note this function needs internal access to the futures ( which is not exposed in the API ). - * @return true if any new futures are ready. + * @return true if any new futures are ready or futures included are not busy. */ friend bool waitForAny( const Futures& futures ); + AsyncData( const AsyncData& ) = delete; + AsyncData& operator=( const AsyncData& ) = delete; + struct Impl; std::unique_ptr _impl; }; diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index 684bbe20..9f64d5b1 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -20,8 +20,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -34,6 +34,9 @@ namespace livre struct PipeFilter::Impl { + typedef std::map< std::string, OutputPortPtr > OutputPortMap; + typedef std::map< std::string, InputPortPtr > InputPortMap; + Impl( PipeFilter& pipeFilter, const std::string& name, FilterPtr filter ) @@ -81,16 +84,17 @@ struct PipeFilter::Impl void addPorts( const PortInfos& iPortInfos, const PortInfos& oPortInfos ) { for( const PortInfo& portInfo: iPortInfos ) - _inputMap[ portInfo.name ] = new InputPort( portInfo ); + _inputMap[ portInfo.name ] = InputPortPtr( new InputPort( portInfo )); for( const PortInfo& portInfo: oPortInfos ) - _outputMap[ portInfo.name ] = new OutputPort( *this, portInfo ); + _outputMap[ portInfo.name ] = OutputPortPtr( new OutputPort( _pipeFilter, portInfo )); // Connect notification ports _inputMap[ _id.getString( )] = - new InputPort( makePortInfo< ConstPortDataPtr >( _id.getString( ))); + InputPortPtr( new InputPort( makePortInfo< ConstPortDataPtr >( _id.getString( )))); _outputMap[ _id.getString( )] = - new OutputPort( *this, makePortInfo< ConstPortDataPtr >( _id.getString( ))); + OutputPortPtr( new OutputPort( _pipeFilter, + makePortInfo< ConstPortDataPtr >( _id.getString( )))); } void execute() @@ -99,19 +103,28 @@ struct PipeFilter::Impl for( auto pair: _inputMap ) ports.push_back( pair.second ); - const InFutures futures( ports ); - PortPromises promises( getOutputPromises( )); - _filter->execute( futures, promises ); - promises.flush(); + const InFutureMap futures( ports ); + PromiseMap promises( getOutputPromises( )); + + try + { + _filter->execute( futures, promises ); + promises.flush(); + } + catch( const std::runtime_error& err ) + { + promises.flush(); + throw err; + } } - PromisePtr getInputPromise( const std::string& portName ) const + PromisePtr getInputPromise( const std::string& portName ) { if( !hasInputPort( portName )) throwPortError( portName ); - if( _outputsToInputMap.count( portName ) > 0 ) - return _outputsToInputMap[ portName ]->getPromise(); + if( _readyPortsMap.count( portName ) > 0 ) + return _readyPortsMap[ portName ]->getPromise(); InputPortPtr& inputPort = _inputMap[ portName ]; @@ -122,10 +135,11 @@ struct PipeFilter::Impl "notification port" )); } - OutputPortPtr outputPort( new OutputPort( *this, + OutputPortPtr outputPort( new OutputPort( _pipeFilter, makePortInfo( inputPort->getName(), inputPort->getDataType( )))); - _outputsToInputMap[ inputPort->getName() ] = outputPort; + _readyPortsMap[ inputPort->getName() ] = outputPort; + inputPort->connect( *outputPort ); return outputPort->getPromise(); } @@ -133,31 +147,32 @@ struct PipeFilter::Impl Promises getOutputPromises() const { Promises promises; - promises.reserve( _outputPorts.size( )); + promises.reserve( _outputMap.size( )); for( const auto& pair: _outputMap ) promises.push_back( pair.second->getPromise( )); return promises; } - Futures getOutFutures() const + Futures getPostconditions() const { - for( const auto& pair: _outputPorts ) + Futures futures; + futures.reserve(_outputMap.size( )); + for( const auto& pair: _outputMap ) { - ConstFuturePtr outputFuture = pair.second->getPromise()->getFuture(); + const Future& outputFuture = pair.second->getPromise()->getFuture(); futures.push_back( outputFuture ); } return futures; } - Futures getInputFutures( lunchbox::Strings& names ) const + Futures getPreconditions() const { Futures futures; - for( const auto& pair: _inputPorts ) + for( const auto& pair: _inputMap ) { - Futures inputFutures = port->getFutures(); + const Futures& inputFutures = pair.second->getFutures(); futures.insert( futures.end(), inputFutures.begin(), inputFutures.end( )); - names.push_back( pair.second->getName( )); } return futures; } @@ -169,19 +184,19 @@ struct PipeFilter::Impl if( !hasOutputPort( srcPortName )) throwPortError( srcPortName ); - if( !dst->_impl.hasInputPort( dstPortName )) + if( !dst->_impl->hasInputPort( dstPortName )) throwPortError( dstPortName ); // The value on the output port may already be set - if( !dst->_impl._outputsToInputMap.count( dstPortName )) + if( !dst->_impl->_readyPortsMap.count( dstPortName )) std::runtime_error( std::string( "The value on port: ") - + portName + + dstPortName + "is already set" ); - _outputMap[ srcPortName ]->connect( *dst->_impl->inputMap[ dstPortName ] ); + _outputMap[ srcPortName ]->connect( *dst->_impl->_inputMap[ dstPortName ] ); } - void PipeFilter::connect( PipeFilterPtr dst ) + void connect( PipeFilterPtr dst ) { OutputPortPtr outputPort = _outputMap[ _id.getString() ]; InputPortPtr inputPort = dst->_impl->_inputMap[ dst->_impl->_id.getString() ]; @@ -194,13 +209,12 @@ struct PipeFilter::Impl FilterPtr _filter; InputPortMap _inputMap; OutputPortMap _outputMap; - OutputPortMap _outputsToInputMap; + OutputPortMap _readyPortsMap; }; PipeFilter::PipeFilter( const std::string& name, FilterPtr filter ) : _impl( new PipeFilter::Impl( *this, name, filter )) - , Executable( _impl->_promise ) {} PipeFilter::PipeFilter( const std::string& name, @@ -212,7 +226,6 @@ PipeFilter::PipeFilter( const std::string& name, func, inputPorts, outputPorts )) - , Executable( _filterOutput.getPorts( )) {} PipeFilter::~PipeFilter() @@ -233,27 +246,27 @@ const std::string& PipeFilter::getName() const return _impl->_name; } -Futures PipeFilter::getConnectedInFutures() const +Futures PipeFilter::getPreconditions() const { - lunchbox::Strings& names; - return _impl->getInputFutures( names ); + return _impl->getPreconditions(); } -PromisePtr PipeFilter::getPromise( const std::string& portName ) +Futures PipeFilter::getPostconditions() const { - return _impl->getInputPromise( portName ); + return _impl->getPostconditions(); } -Futures PipeFilter::getOutFutures() const + +PromisePtr PipeFilter::getPromise( const std::string& portName ) { - return _impl->getOutFutures(); + return _impl->getInputPromise( portName ); } void PipeFilter::connect( const std::string& srcPortName, PipeFilterPtr dst, - const std::string& dst ) + const std::string& dstPortName ) { - _impl->connect( srcPortName, dst, dst ); + _impl->connect( srcPortName, dst, dstPortName ); } void PipeFilter::connect( PipeFilterPtr dst ) diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index 40c37693..996b87e4 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -21,9 +21,6 @@ #define _PipeFilter_h_ #include -#include -#include -#include #include namespace livre @@ -99,13 +96,13 @@ class PipeFilter : public Executable /** * @copydoc Executable::getOutFutures() */ - Futures getOutFutures() const final; + Futures getPostconditions() const final; /** * @copydoc Executable::getInputFutures() * @note PipeFilter guarantees that only connected input futures are returned. */ - Futures getConnectedInFutures() const final; + Futures getPreconditions() const final; /** * @return return promise for the given input port. If there is no connection to the diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp index fabb79a6..d58c336c 100644 --- a/livre/core/pipeline/Pipeline.cpp +++ b/livre/core/pipeline/Pipeline.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include @@ -52,7 +52,7 @@ struct Pipeline::Impl } PipeFilterPtr add( const std::string& name, - FilterPtr filter, + const FilterPtr& filter, bool wait ) { if( _executableMap.count( name ) > 0 ) @@ -63,16 +63,18 @@ struct Pipeline::Impl if( wait ) { - const OutFutures portFutures( pipefilter->getOutFutures( )); + const OutFutureMap portFutures( pipefilter->getPostconditions( )); _waitFutures.push_back( portFutures.getFuture( pipefilter->getId().getString( ))); } + + return pipefilter; } void add( const std::string& name, - const ConstPipelinePtr& pipeline, + const PipelinePtr& pipeline, bool wait ) { - if( pipeline.get() == _pipeline ) + if( pipeline.get() == &_pipeline ) return; if( _executableMap.count( name ) > 0 ) @@ -82,7 +84,7 @@ struct Pipeline::Impl if( wait ) { - const Futures& futures = pipeline->getOutFutures(); + const Futures& futures = pipeline->getPostconditions(); _waitFutures.insert( _waitFutures.end(), futures.begin(), futures.end( )); } } @@ -94,8 +96,8 @@ struct Pipeline::Impl while( !executables.empty()) { ExecutablePtr executable = *it; - const FutureMap portFutures( executable->getConnectedInFutures( )); - if( portFutures.isReady( )) + const FutureMap futureMap( executable->getPreconditions( )); + if( futureMap.isReady( )) { executable->execute(); executables.erase( it ); @@ -120,7 +122,7 @@ struct Pipeline::Impl return executables; } - Futures getConnectedInFutures() const + Futures getConnectedInFutureMap() const { return Futures(); } @@ -139,7 +141,7 @@ struct Pipeline::Impl }; Pipeline::Pipeline() - : _impl( new Pipeline::Impl( this )) + : _impl( new Pipeline::Impl( *this )) { } @@ -147,14 +149,14 @@ Pipeline::~Pipeline() {} void Pipeline::add( const std::string& name, - PipelinePtr pipeline, + const PipelinePtr& pipeline, bool wait ) { - return _impl->addPipeline( name, pipeline, wait ); + return _impl->add( name, pipeline, wait ); } PipeFilterPtr Pipeline::add( const std::string& name, - FilterPtr filter, + const FilterPtr& filter, bool wait ) { return _impl->add( name, filter, wait ); @@ -183,12 +185,12 @@ void Pipeline::execute() return _impl->execute(); } -Futures Pipeline::getConnectedInFutures() const +Futures Pipeline::getPreconditions() const { - return _impl->getConnectedInFutures(); + return _impl->getConnectedInFutureMap(); } -Futures Pipeline::getOutFutures() const +Futures Pipeline::getPostconditions() const { return _impl->getOutFutures(); } diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index ff346814..d5f147e6 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -48,7 +48,7 @@ class Pipeline : public Executable * can wait on given pipeline. */ void add( const std::string& name, - PipelinePtr pipeline, + const PipelinePtr& pipeline, bool wait = true ); /** @@ -61,7 +61,7 @@ class Pipeline : public Executable * @return returns the generated pipe filter. */ PipeFilterPtr add( const std::string& name, - FilterPtr filter, + const FilterPtr& filter, bool wait = true ); /** @@ -87,23 +87,23 @@ class Pipeline : public Executable */ Executables getExecutables() const; -private: - /** * Executes each executable element in the graph * synchronously. */ void execute() final; +private: + /** * @return Returns the writable future */ - Futures getConnectedInFutures() const final; + Futures getPreconditions() const final; /** * @return Returns the writable future */ - Futures getOutFutures() const final; + Futures getPostconditions() const final; struct Impl; std::unique_ptr _impl; diff --git a/livre/core/pipeline/PortData.h b/livre/core/pipeline/PortData.h index ea652aa1..7b634819 100644 --- a/livre/core/pipeline/PortData.h +++ b/livre/core/pipeline/PortData.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -34,8 +34,8 @@ namespace livre class PortData : public PortType { protected: - PortData( const std::type_index& typeIndex ) - : PortType( typeIndex) {} + explicit PortData( const std::type_index& dataType ) + : PortType( dataType) {} virtual ~PortData() {} }; @@ -57,6 +57,9 @@ struct PortDataT final : public PortData ~PortDataT() {} const T data; + + PortDataT( const PortDataT< T >& ) = delete; + PortDataT< T >& operator=( const PortDataT< T >& ) = delete; }; template @@ -65,17 +68,11 @@ using PortDataTPtr = boost::shared_ptr< PortDataT< T >>; template using ConstPortDataTPtr = boost::shared_ptr< PortDataT< T >>; -template -using PortDataTPtrs = std::vector< PortDataTPtr< T >>; - -template -using ConstPortDataTPtrs = std::vector< ConstPortDataTPtr< T >>; - /** * Constructs a PortDataTPtr object from type T */ template< class T > -PortDataTPtr< T > makePortDataPtr( const T& data ) +inline PortDataTPtr< T > makePortDataPtr( const T& data ) { return boost::make_shared< PortDataT< T >>( data ); } @@ -85,7 +82,7 @@ PortDataTPtr< T > makePortDataPtr( const T& data ) * Moves the to the port data. */ template< class T > -PortDataTPtr< T > makePortDataPtr( const T&& data ) +inline PortDataTPtr< T > makePortDataPtr( const T&& data ) { return boost::make_shared< PortDataT< T >>( data ); } diff --git a/livre/core/pipeline/PortInfo.h b/livre/core/pipeline/PortInfo.h index cbad19fc..d19489fb 100644 --- a/livre/core/pipeline/PortInfo.h +++ b/livre/core/pipeline/PortInfo.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -20,9 +20,9 @@ #ifndef _PortInfo_h_ #define _PortInfo_h_ -#include +#include -#include "PortType.h" +#include namespace livre { @@ -33,9 +33,9 @@ namespace livre struct PortInfo final : public PortType { PortInfo( const std::string& name_, - std::type_index& dataType ) + const std::type_index& dataType ) : PortType( dataType ) - , name( portName_ ) + , name( name_ ) {} const std::string name; @@ -46,7 +46,7 @@ struct PortInfo final : public PortType * @param name is the port name with a type */ template< class T > -PortInfo makePortInfo( const std::string& name ) +inline PortInfo makePortInfo( const std::string& name ) { return PortInfo( name, std::type_index( typeid( T ))); } @@ -56,7 +56,7 @@ PortInfo makePortInfo( const std::string& name ) * @param name is the port name * @param dataType data type for the port */ -PortInfo makePortInfo( const std::string& name, +inline PortInfo makePortInfo( const std::string& name, const std::type_index& dataType ) { return PortInfo( name, dataType ); @@ -68,7 +68,7 @@ PortInfo makePortInfo( const std::string& name, * @param portName is the port name */ template< class T > -void addPortInfo( PortInfos& portInfos, +inline void addPortInfo( PortInfos& portInfos, const std::string& portname ) { portInfos.push_back( makePortInfo< T >( portname )); diff --git a/livre/core/pipeline/PortType.h b/livre/core/pipeline/PortType.h index a763b9d4..6f21ad5d 100644 --- a/livre/core/pipeline/PortType.h +++ b/livre/core/pipeline/PortType.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -46,12 +46,11 @@ class PortType * @param typeIndex type index of the data of the * derived classes data type. */ - PortType( const std::type_index& dataType ) + explicit PortType( const std::type_index& dataType ) : _dataType( dataType) {} - virtual ~PortData() {} private: - std::type_index _dataType; + const std::type_index _dataType; }; } diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp index 8823111e..e1208a28 100644 --- a/livre/core/pipeline/Promise.cpp +++ b/livre/core/pipeline/Promise.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -19,13 +19,14 @@ #include #include +#include namespace livre { struct Promise::Impl { - Impl( const PipeFilter& pipeFilter, const AsyncData& data ) + Impl( const PipeFilter& pipeFilter, AsyncData& data ) : _pipeFilter( pipeFilter ) , _data( data ) , _future( _pipeFilter, _data ) @@ -36,18 +37,23 @@ struct Promise::Impl return _data.getName(); } - void set( ConstPortDataPtr msg ) + void set( const ConstPortDataPtr& data ) { - _data.set( msg ); + _data.set( data ); + } + + void flush() + { + _data.set( ConstPortDataPtr( )); } - Future _future; const PipeFilter& _pipeFilter; - const AsyncData& _data; + AsyncData& _data; + const Future _future; }; Promise::Promise( const PipeFilter& pipeFilter, - const AsyncData& data ) + AsyncData& data ) : _impl( new Promise::Impl( pipeFilter, data )) {} @@ -59,14 +65,19 @@ const std::string& Promise::getName() const return _impl->getName(); } -void Promise::set( ConstPortDataPtr msg ) +void Promise::flush() { - _impl->getName( msg ); + _impl->flush(); } -Future Promise::getFuture() const +const Future& Promise::getFuture() const { return _impl->_future; } +void Promise::_set( const ConstPortDataPtr& data ) +{ + _impl->set( data ); +} + } diff --git a/livre/core/pipeline/Promise.h b/livre/core/pipeline/Promise.h index 30023d88..a93dc882 100644 --- a/livre/core/pipeline/Promise.h +++ b/livre/core/pipeline/Promise.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -30,23 +30,49 @@ class Promise { public: - Promise( const PipeFilter& pipeFilter, const AsyncData& data ); + Promise( const PipeFilter& pipeFilter, AsyncData& data ); ~Promise(); const std::string& getName() const; /** - * @return sets the promise with data + * Sets the port with the value. + * @param value to be set + * @throw std::runtime_error when the port data is not exact + * type T or there is no such port name. */ - void set( ConstPortDataPtr msg ); + template< class T > + void set( const T& value ) + { + _set( makePortDataPtr( value )); + } + + /** + * Sets the port with the value. + * @param value to be set + * @throw std::runtime_error when the port data is not exact + * type T or there is no such port name. + */ + template< class T > + void set( const T&& value ) + { + _set( makePortDataPtr( value )); + } + + /** + * Sets the promise with empty data if it is not set already + */ + void flush(); /** * @return the future, that can be queried for data retrieval */ - Future getFuture() const; + const Future& getFuture() const; private: + void _set( const ConstPortDataPtr& data ); + struct Impl; std::unique_ptr _impl; }; diff --git a/livre/core/pipeline/PortPromises.cpp b/livre/core/pipeline/PromiseMap.cpp similarity index 70% rename from livre/core/pipeline/PortPromises.cpp rename to livre/core/pipeline/PromiseMap.cpp index 7b24dbaf..0dfb083b 100644 --- a/livre/core/pipeline/PortPromises.cpp +++ b/livre/core/pipeline/PromiseMap.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -17,7 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include +#include #include #include @@ -27,11 +27,11 @@ namespace livre typedef std::pair< std::string, PromisePtr > NamePromisePair; typedef std::map< std::string, PromisePtr > NamePromiseMap; -struct PortPromises::Impl +struct PromiseMap::Impl { Impl( const Promises& promises ) { - for( PromisePtr& promise: promises ) + for( const PromisePtr& promise: promises ) _promiseMap[ promise->getName( )] = promise; } @@ -39,7 +39,7 @@ struct PortPromises::Impl { std::stringstream err; err << "Unknown port: " << portName << std::endl; - _promiseMap( std::runtime_error( err.str( ))); + LBTHROW( std::runtime_error( err.str( ))); } bool hasPort( const std::string& portName ) const @@ -52,42 +52,40 @@ struct PortPromises::Impl if( portName != ALL_PORTS && !hasPort( portName )) throwPortError( portName ); - for( const NamePromisePair& namePromisePair: _promiseMap ) + for( const auto& pair: _promiseMap ) { - PromisePtr& promise = namePromisePair.second; + const PromisePtr& promise = pair.second; if( portName == ALL_PORTS || promise->getName() == portName ) promise->flush(); } } - void set( const std::string& portName, ConstPortDataPtr data ) + PromisePtr getPromise( const std::string& portName ) { if( !hasPort( portName )) throwPortError( portName ); - _promiseMap[ portName ]->set( data ); + return _promiseMap[ portName ]; } NamePromiseMap _promiseMap; }; -PortPromises::PortPromises( const Promises& promises ) - : _impl( new PortPromises::Impl( promises )) +PromiseMap::PromiseMap( const Promises& promises ) + : _impl( new PromiseMap::Impl( promises )) {} -PortPromises::~PipeFilterOutput() +PromiseMap::~PromiseMap() {} -void PortPromises::flush( const std::string& portName /* = ALL_PORTS */ ) +void PromiseMap::flush( const std::string& portName /* = ALL_PORTS */ ) { _impl->flush( portName ); } -void PortPromises::_set( const std::string& name, - ConstPortDataPtr data ) +PromisePtr PromiseMap::getPromise( const std::string& portName ) { - _impl->set( name, data ); + return _impl->getPromise( portName ); } - } diff --git a/livre/core/pipeline/PortPromises.h b/livre/core/pipeline/PromiseMap.h similarity index 70% rename from livre/core/pipeline/PortPromises.h rename to livre/core/pipeline/PromiseMap.h index e9ec3908..a1af0810 100644 --- a/livre/core/pipeline/PortPromises.h +++ b/livre/core/pipeline/PromiseMap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -17,11 +17,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _PortPromises_h_ -#define _PortPromises_h_ +#ifndef _PromiseMap_h_ +#define _PromiseMap_h_ #include -#include +#include namespace livre { @@ -36,53 +36,60 @@ namespace livre * * It also provides thread safe functions to query the state of the port. */ -class PortPromises +class PromiseMap { public: - PortPromises( const Promises& promises ); - ~PortPromises(); + explicit PromiseMap( const Promises& promises ); + ~PromiseMap(); + + /** + * @param portName is the port name. + * @return the promise related to the port name. + */ + PromisePtr getPromise( const std::string& portName ); /** * Sets the port with the value. + * @param portName is the port name. * @param value to be set * @throw std::runtime_error when the port data is not exact - * type T + * type T or there is no such port name. */ template< class T > void set( const std::string& portName, const T& value ) { - _set( portName, makePortDataPtr( value )); + getPromise( portName )->set( value ); } /** * Sets the port with the value. + * @param portName is the port name. * @param value to be set * @throw std::runtime_error when the port data is not exact - * type T + * type T or there is no such port name. */ template< class T > void set( const std::string& portName, const T&& value ) { - _set( portName, makePortDataPtr( value )); + getPromise( portName )->set( value ); } /** - * Writes empty values to promises + * Writes empty values to promises which are not set already. * @param portName is the port name. If ALL_PORTS is given, * all promises will be flushed + * @throw std::runtime_error there is no such port name. */ void flush( const std::string& portName = ALL_PORTS ); private: - void _set( const std::string& portName, ConstPortDataPtr data ); - struct Impl; std::unique_ptr _impl; }; } -#endif // _PortPromises_h_ +#endif // _PromiseMap_h_ diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp index 1e055ccd..661098bc 100644 --- a/livre/core/pipeline/SimpleExecutor.cpp +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -22,21 +22,16 @@ #include #include -#include -#include +#include +#include #include #include #include #include -#include - -#define BOOST_THREAD_PROVIDES_FUTURE -#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION #include -#include namespace livre { @@ -44,9 +39,9 @@ namespace livre struct SimpleExecutor::Impl { - Impl( WorkersPtr workers ) - : _workThread( boost::thread( boost::bind( &Impl::execute, this ))) - , _workers( workers ) + Impl( const size_t threadCount ) + : _workThread( boost::thread( boost::bind( &Impl::schedule, this ))) + , _workers( threadCount ) {} ~Impl() @@ -61,11 +56,39 @@ struct SimpleExecutor::Impl while( true ) { Executables executables = _mtWorkQueue.pop(); - if( !executable.empty() ) + if( executables.empty() ) break; - for( ExecutablePtr& executable: executables ) - _workers->execute( executable ); + Futures futures; + + do + { + futures.clear(); + for( const ExecutablePtr& executable: executables ) + { + const Futures& inputFutures = executable->getPreconditions(); + for( const Future& future: inputFutures ) + { + if( !future.isReady( )) + futures.push_back( future ); + } + } + + Executables::iterator it = executables.begin(); + while( it != executables.end( )) + { + ExecutablePtr executable = *it; + const FutureMap futureMap( executable->getPreconditions( )); + if( futureMap.isReady( )) + { + _workers.execute( executable ); + it = executables.erase( it ); + } + else + ++it; + } + + } while( FutureMap( futures ).waitForAny( )); } } @@ -81,11 +104,11 @@ struct SimpleExecutor::Impl lunchbox::MTQueue< Executables > _mtWorkQueue; boost::thread _workThread; - WorkersPtr _workers; + Workers _workers; }; -SimpleExecutor::SimpleExecutor( WorkersPtr workers ) - : _impl( new Impl( workers )) +SimpleExecutor::SimpleExecutor( const size_t threadCount ) + : _impl( new Impl( threadCount )) { } diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h index e8cf9c42..6413675d 100644 --- a/livre/core/pipeline/SimpleExecutor.h +++ b/livre/core/pipeline/SimpleExecutor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -34,19 +34,20 @@ namespace livre * * The scheduler implemented in this class, just pushes the * executables without re-ordering. This may mean that if - * all workers are blocked, the processing can suspend. This - * is a push based executor. + * all workers are blocked, the processing can suspend. * + * SimpleExecutor executes executables in a push based flow. */ + class SimpleExecutor : public Executor { public: /** - * @param workers are thread pools that executes individual + * @param threadCount number of workers are thread pools that executes individual * executables ( PipeFilter, Pipeline ) */ - explicit SimpleExecutor( WorkersPtr workers ); + explicit SimpleExecutor( size_t threadCount ); virtual ~SimpleExecutor(); /** @@ -61,7 +62,6 @@ class SimpleExecutor : public Executor */ void _schedule( const Executables& executables ) final; - struct Impl; std::unique_ptr _impl; }; diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp index ee5d65ac..6d760a98 100644 --- a/livre/core/pipeline/Workers.cpp +++ b/livre/core/pipeline/Workers.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index 34792cc9..89cdff90 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre diff --git a/livre/core/render/GLContext.h b/livre/core/render/GLContext.h index 2b0da5b4..a616e60a 100644 --- a/livre/core/render/GLContext.h +++ b/livre/core/render/GLContext.h @@ -47,6 +47,11 @@ class GLContext */ virtual GLContextPtr clone() const = 0; + /** + * @return a similar context. + */ + virtual GLContextPtr createContext() const = 0; + /** * Makes the context current. */ diff --git a/livre/eq/render/EqContext.cpp b/livre/eq/render/EqContext.cpp index db769667..11d1ad92 100644 --- a/livre/eq/render/EqContext.cpp +++ b/livre/eq/render/EqContext.cpp @@ -37,7 +37,18 @@ EqContext::~EqContext() delete _systemWindow; } -void EqContext::share( const GLContext& src ) +GLContextPtr EqContext::createContext() const +{ + return GLContextPtr( new EqContext( window_ )); +} + +void EqContext::makeCurrent() +{ + if( systemWindow_ ) + systemWindow_->makeCurrent(); +} + +void EqContext::doneCurrent() { LBASSERT( _window ); diff --git a/livre/eq/render/EqContext.h b/livre/eq/render/EqContext.h index 34983e59..fca62e01 100644 --- a/livre/eq/render/EqContext.h +++ b/livre/eq/render/EqContext.h @@ -42,7 +42,12 @@ class EqContext : public GLContext ~EqContext(); /** - * @copydoc GLContext::share + * @return a similar context + */ + GLContextPtr createContext() const final; + + /** + * Makes the context, current. */ void share( const GLContext& src ) final; diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index 14c8a3a6..eb54d812 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -35,7 +39,7 @@ const uint32_t addMoreFish = 10; struct InputData { - InputData( uint32_t value = defaultMeaningOfLife ) + explicit InputData( uint32_t value = defaultMeaningOfLife ) : meaningOfLife( value ) {} @@ -44,7 +48,7 @@ struct InputData struct OutputData { - OutputData( uint32_t value = defaultThanksForAllTheFish ) + explicit OutputData( uint32_t value = defaultThanksForAllTheFish ) : thanksForAllTheFish( value ) {} @@ -53,19 +57,19 @@ struct OutputData class TestFilter : public livre::Filter { - void execute( const livre::InFutures& input, livre::PortPromises& output ) const final + void execute( const livre::InFutureMap& input, livre::PromiseMap& output ) const final { - const livre::ResultsT< InputData >& result = input.get< InputData >( "InputData" ); + const livre::ResultsT< InputData >& results = input.get< InputData >( "TestInputData" ); OutputData outputData; - for( const auto& pair: result ) + for( const auto& data: results ) { - const InputData& inputData = pair.second; + const InputData& inputData = data; outputData.thanksForAllTheFish += inputData.meaningOfLife + addMoreFish; } - output.set( "OutputData", outputData ); + output.set( "TestOutputData", outputData ); } @@ -86,12 +90,16 @@ class TestFilter : public livre::Filter class ConvertFilter : public livre::Filter { - void execute( const livre::InFutures& input, livre::PortPromises& output ) const final + void execute( const livre::InFutureMap& input, livre::PromiseMap& output ) const final { - const livre::ResultsT< OutputData >& result = input.get< OutputData >( "ConvertInputData" ); + const livre::ResultsT< OutputData >& results = input.get< OutputData >( "ConvertInputData" ); InputData inputData; - inputData.meaningOfLife = result[ "TestOutputData" ].thanksForAllTheFish + addMoreFish; + for( const auto& data: results ) + { + inputData.meaningOfLife = data.thanksForAllTheFish + addMoreFish; + } + output.set( "ConvertOutputData", inputData ); } @@ -116,10 +124,14 @@ BOOST_AUTO_TEST_CASE( testFilterNoInput ) { livre::FilterPtr filter( new TestFilter( )); livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); - pipeFilter->execute(); - const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); - const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); - BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, defaultThanksForAllTheFish ); + + // Execute will fail because there are no inputs where data is retrieved + BOOST_CHECK_EXCEPTION( pipeFilter->execute(), std::runtime_error, check_error ); + const livre::OutFutureMap portFutures( pipeFilter->getPostconditions( )); + + // Results of the filter will be empty. + BOOST_CHECK_EXCEPTION( portFutures.get< OutputData >( "TestOutputData" ), + std::runtime_error, check_error ); } BOOST_AUTO_TEST_CASE( testFilterWithInput ) @@ -128,10 +140,9 @@ BOOST_AUTO_TEST_CASE( testFilterWithInput ) livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); const uint32_t inputValue = 90; - const livre::PortPromises portPromises( pipeFilter->getPromises( )); - portPromises->set( "InputData", InputData( inputValue )); + pipeFilter->getPromise( "TestInputData" )->set( InputData( inputValue )); pipeFilter->execute(); - const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); + const livre::OutFutureMap portFutures( pipeFilter->getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 151 ); @@ -141,12 +152,12 @@ BOOST_AUTO_TEST_CASE( testSetAndGetWrongParameters ) { livre::FilterPtr filter( new TestFilter( )); livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); - const livre::PortPromises portPromises( pipeFilter->getPromises( )); + pipeFilter->getPromise( "TestInputData" )->set( InputData()); - BOOST_CHECK_EXCEPTION( portPromises.set( "TestInputData", OutputData( 0 )), + BOOST_CHECK_EXCEPTION( pipeFilter->getPromise( "InputData" )->set( OutputData( 0 )), std::runtime_error, check_error ); pipeFilter->execute(); - const livre::OutFutures portFutures( pipeFilter->getOutFutures()); + const livre::OutFutureMap portFutures( pipeFilter->getPostconditions()); BOOST_CHECK_EXCEPTION( portFutures.get( "TestOutputData" ), std::runtime_error, check_error ); } @@ -172,19 +183,18 @@ BOOST_AUTO_TEST_CASE( testConnection ) livre::FilterPtr convertFilter( new ConvertFilter( )); livre::PipeFilterPtr convertPipeFilter( new livre::PipeFilter( "Converter", convertFilter ) ); - pipeInput->connectFilters( "TestOutputData", convertPipeFilter, "ConvertInputData" ); + pipeInput->connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); convertPipeFilter->connect( "ConvertOutputData", pipeOutput, "TestInputData" ); const uint32_t inputValue = 90; - livre::PortPromises portPromises( pipeFilter->getPromises( )); - portPromises->set( "InputData", InputData( inputValue )); + pipeInput->getPromise( "TestInputData" )->set( InputData( inputValue )); pipeInput->execute(); convertPipeFilter->execute(); pipeOutput->execute(); - const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); + const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); const OutputData& outputData = - portFutures->get( "TestOutputData" ); + portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -200,20 +210,20 @@ livre::PipelinePtr createPipeline( livre::PipeFilterPtr& pipeOutput, livre::FilterPtr convertFilter( new ConvertFilter( )); for( size_t i = 0; i < nConvertFilter; ++i ) { - livre::PipeFilterPtr convertPipeFilter = pipeline->add( "Converter", convertFilter ); + std::stringstream name; + name << "Converter" << i; + livre::PipeFilterPtr convertPipeFilter = pipeline->add( name.str(), convertFilter ); pipeInput->connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); - convertPipeFilter->connect( "ConvertInputData", pipeOutput, "TestInputData" ); + convertPipeFilter->connect( "ConvertOutputData", pipeOutput, "TestInputData" ); } - livre::PortPromises portPromises( pipeFilter->getPromises( )); - portPromises->set( "InputData", InputData( inputValue )); + pipeInput->getPromise( "TestInputData" )->set( InputData( inputValue )); return pipeline; } -livre::ExecutorPtr createExecutor() +livre::ExecutorPtr createExecutor(const size_t nbOfWorkerThreads ) { - livre::WorkersPtr workers( new livre::Workers( 2 )); - livre::ExecutorPtr executor( new livre::SimpleExecutor( workers )); + livre::ExecutorPtr executor( new livre::SimpleExecutor( nbOfWorkerThreads )); return executor; } @@ -224,8 +234,8 @@ BOOST_AUTO_TEST_CASE( testSynchronousPipeline ) livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); pipeline->execute(); - const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); - const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); + const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -234,13 +244,13 @@ BOOST_AUTO_TEST_CASE( testWaitPipeline ) livre::PipeFilterPtr pipeOutput; const uint32_t inputValue = 90; livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); - livre::ExecutorPtr executor = createExecutor(); + livre::ExecutorPtr executor = createExecutor( 2 ); - const livre::OutFutures pipelineFutures( executor->execute( pipeline->getExecutables( ))); - pipelineFutures->wait(); + const livre::FutureMap pipelineFutures( executor->execute( pipeline->getExecutables( ))); + pipelineFutures.wait(); - const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); - const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); + const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -249,28 +259,51 @@ BOOST_AUTO_TEST_CASE( testAsynchronousPipeline ) livre::PipeFilterPtr pipeOutput; const uint32_t inputValue = 90; livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); - livre::ExecutorPtr executor = createExecutor(); + livre::ExecutorPtr executor = createExecutor( 2 ); executor->execute( pipeline->getExecutables( )); - const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); - const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); + const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) { - const size_t convertFilterCount = 10; - const uint32_t inputValue = 90; - livre::PipeFilterPtr pipeOutput; - livre::PipelinePtr pipeline = createPipeline( pipeOutput, - inputValue, - convertFilterCount ); - livre::ExecutorPtr executor = createExecutor(); - executor->execute( pipeline->getExecutables( )); + // Try using 1 execution thread, output result should not change + { + const size_t convertFilterCount = 10; + const uint32_t inputValue = 90; + livre::PipeFilterPtr pipeOutput; + + livre::PipelinePtr pipeline = createPipeline( pipeOutput, + inputValue, + convertFilterCount ); + livre::ExecutorPtr executor = createExecutor( 1 ); + executor->execute( pipeline->getExecutables( )); + + const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 1761 ); + } + + // Try using 8 execution thread, output result should not change + { + const size_t convertFilterCount = 10; + const uint32_t inputValue = 90; + livre::PipeFilterPtr pipeOutput; + + livre::PipelinePtr pipeline = createPipeline( pipeOutput, + inputValue, + convertFilterCount ); + livre::ExecutorPtr executor = createExecutor( 8 ); + executor->execute( pipeline->getExecutables( )); + + const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); + BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 1761 ); + } + - const livre::OutFutures portFutures( pipeFilter->getOutFutures( )); - const OutputData& outputData = portFutures->get< OutputData >( "OutputData" ); - BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 1761 ); } From 768f81593088a736fe9ba5fb39bbf5915fd54457 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Fri, 4 Mar 2016 15:28:44 +0100 Subject: [PATCH 04/17] Pipeline and Pipefilters can be reset for re-use --- livre/core/pipeline/Executable.h | 5 +++ livre/core/pipeline/Future.h | 6 +++ livre/core/pipeline/FutureMap.cpp | 3 +- livre/core/pipeline/InputPort.cpp | 19 +++++++++ livre/core/pipeline/InputPort.h | 6 +++ livre/core/pipeline/OutputPort.cpp | 26 +++++++++++- livre/core/pipeline/OutputPort.h | 10 +++++ livre/core/pipeline/PipeFilter.cpp | 16 +++++++- livre/core/pipeline/PipeFilter.h | 5 +++ livre/core/pipeline/Pipeline.cpp | 11 +++++ livre/core/pipeline/Pipeline.h | 5 +++ tests/pipeline/pipeline.cpp | 64 +++++++++++++++++++++++------- 12 files changed, 158 insertions(+), 18 deletions(-) diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h index 32eeac1d..7153a24f 100644 --- a/livre/core/pipeline/Executable.h +++ b/livre/core/pipeline/Executable.h @@ -57,6 +57,11 @@ class Executable */ virtual Futures getPreconditions() const { return Futures(); } + /** + * Resets the executable + */ + virtual void reset() {} + }; } diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h index 5d609f4d..32130c5b 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/Future.h @@ -100,6 +100,12 @@ class Future */ const AsyncData& getAsyncData() const; + /** + * @param future is the future to be checked with + * @return true if both futures are same + */ + bool operator==( const Future& future ) const { return _impl == future._impl; } + private: friend bool livre::waitForAny( const Futures& future ); diff --git a/livre/core/pipeline/FutureMap.cpp b/livre/core/pipeline/FutureMap.cpp index 6af3a385..774886ed 100644 --- a/livre/core/pipeline/FutureMap.cpp +++ b/livre/core/pipeline/FutureMap.cpp @@ -47,7 +47,6 @@ struct FutureMapImpl if( portName == ALL_PORTS ) { Futures futures; - futures.reserve( _futureMap.size( )); for( const auto& pair: _futureMap ) futures.push_back( pair.second ); return futures; @@ -163,7 +162,7 @@ Futures OutFutureMap::getFutures() const Future OutFutureMap::getFuture( const std::string& portName ) const { - return _impl->getFutures( portName )[ 0 ]; + return _impl->getFutures( portName ).front(); } bool OutFutureMap::isReady( const std::string& portName ) const diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp index c43d9a8f..280e6744 100644 --- a/livre/core/pipeline/InputPort.cpp +++ b/livre/core/pipeline/InputPort.cpp @@ -57,6 +57,20 @@ struct InputPort::Impl _futures.push_back( outputPort.getPromise()->getFuture( )); } + void disconnect( const OutputPort& outputPort ) + { + Futures::iterator it = _futures.begin(); + while( it != _futures.end()) + { + if( *it == outputPort.getPromise()->getFuture( )) + { + _futures.erase( it ); + return; + } + ++it; + } + } + Futures _futures; const PortInfo _info; }; @@ -78,6 +92,11 @@ void InputPort::connect( const OutputPort& outputPort ) _impl->connect( outputPort ); } +void InputPort::disconnect( const OutputPort& outputPort ) +{ + _impl->disconnect( outputPort ); +} + const std::string& InputPort::getName() const { return _impl->getName(); diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index 9363406a..9985ea0f 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -68,6 +68,12 @@ class InputPort */ void connect( const OutputPort& inputPort ); + /** + * Disconnects an output port from input port + * @param inputPort input port + */ + void disconnect( const OutputPort& inputPort ); + private: struct Impl; diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp index 314aab0b..857ef96e 100644 --- a/livre/core/pipeline/OutputPort.cpp +++ b/livre/core/pipeline/OutputPort.cpp @@ -37,7 +37,10 @@ namespace Therefore, the get/set/query operations on promises/futures causes deadlocks when used with wait_for_any( futurelist ) if futurelist is including the future to be queried. With below implementation no locking is needed between - future operations. A higher granularity can be added for checking whet */ + future operations. A higher granularity can be added for checking whether + the list includes the future or not, but simply exiting the wait_for_any + operation when lock is owned is simpler. + */ ReadWriteMutex waitForAnyLock; } @@ -88,6 +91,13 @@ struct AsyncData::Impl _future.wait(); } + void reset() + { + ConstPortDataPromise newPromise; + _promise.swap( newPromise ); + _future = _promise.get_future(); + } + ConstPortDataPromise _promise; mutable ConstPortDataFuture _future; const std::string _name; @@ -124,6 +134,10 @@ void AsyncData::wait() const _impl->wait(); } +void AsyncData::reset() +{ + _impl->reset(); +} struct OutputPort::Impl { @@ -148,6 +162,11 @@ struct OutputPort::Impl return _info.name; } + void reset() + { + _data.reset(); + } + const PortInfo _info; AsyncData _data; PromisePtr _portPromise; @@ -181,6 +200,11 @@ void OutputPort::connect( InputPort& inputPort ) inputPort.connect( *this ); } +void OutputPort::reset() +{ + _impl->reset(); +} + bool waitForAny( const Futures& futures ) { if( futures.empty( )) diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h index dd6c5276..d4970d12 100644 --- a/livre/core/pipeline/OutputPort.h +++ b/livre/core/pipeline/OutputPort.h @@ -67,6 +67,11 @@ class AsyncData */ void wait() const; + /** + * Resets the promise/future + */ + void reset(); + private: /** @@ -113,6 +118,11 @@ class OutputPort */ void connect( InputPort& inputPort ); + /** + * Resets the promise/future + */ + void reset(); + private: struct Impl; diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index 9f64d5b1..42ea6dbc 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -157,7 +157,6 @@ struct PipeFilter::Impl Futures getPostconditions() const { Futures futures; - futures.reserve(_outputMap.size( )); for( const auto& pair: _outputMap ) { const Future& outputFuture = pair.second->getPromise()->getFuture(); @@ -203,6 +202,16 @@ struct PipeFilter::Impl inputPort->connect( *outputPort ); } + void reset() + { + for( auto& pair: _readyPortsMap ) + _inputMap[ pair.first ]->disconnect( *pair.second ); + + _readyPortsMap.clear(); + for( const auto& pair: _outputMap ) + pair.second->reset(); + } + PipeFilter& _pipeFilter; const std::string _name; const servus::uint128_t _id; @@ -241,6 +250,11 @@ const servus::uint128_t& PipeFilter::getId() const return _impl->_id; } +void PipeFilter::reset() +{ + _impl->reset(); +} + const std::string& PipeFilter::getName() const { return _impl->_name; diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index 996b87e4..16ccaf47 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -118,6 +118,11 @@ class PipeFilter : public Executable */ const servus::uint128_t& getId() const; + /** + * Resets the filter. At this point pipe filter execution should be complete. + */ + void reset(); + private: friend class Pipeline; diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp index d58c336c..a81acb1c 100644 --- a/livre/core/pipeline/Pipeline.cpp +++ b/livre/core/pipeline/Pipeline.cpp @@ -132,6 +132,12 @@ struct Pipeline::Impl return _waitFutures; } + void reset() + { + for( auto pair: _executableMap ) + pair.second->reset(); + } + ~Impl() {} @@ -185,6 +191,11 @@ void Pipeline::execute() return _impl->execute(); } +void Pipeline::reset() +{ + _impl->reset(); +} + Futures Pipeline::getPreconditions() const { return _impl->getConnectedInFutureMap(); diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index d5f147e6..aab0c985 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -93,6 +93,11 @@ class Pipeline : public Executable */ void execute() final; + /** + * Resets the pipeline. At this point pipeline execution should be complete. + */ + void reset() final; + private: /** diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index eb54d812..71338775 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -198,13 +198,14 @@ BOOST_AUTO_TEST_CASE( testConnection ) BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } -livre::PipelinePtr createPipeline( livre::PipeFilterPtr& pipeOutput, +livre::PipelinePtr createPipeline( livre::PipeFilterPtr& pipeInput, + livre::PipeFilterPtr& pipeOutput, uint32_t inputValue, size_t nConvertFilter = 1 ) { livre::FilterPtr filter( new TestFilter( )); livre::PipelinePtr pipeline( new livre::Pipeline( )); - livre::PipeFilterPtr pipeInput = pipeline->add( "Producer", filter ); + pipeInput = pipeline->add( "Producer", filter ); pipeOutput = pipeline->add( "Consumer", filter ); livre::FilterPtr convertFilter( new ConvertFilter( )); @@ -229,9 +230,15 @@ livre::ExecutorPtr createExecutor(const size_t nbOfWorkerThreads ) BOOST_AUTO_TEST_CASE( testSynchronousPipeline ) { - livre::PipeFilterPtr pipeOutput; const uint32_t inputValue = 90; - livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); + livre::PipeFilterPtr pipeInput; + livre::PipeFilterPtr pipeOutput; + + livre::PipelinePtr pipeline = createPipeline( pipeInput, + pipeOutput, + inputValue, + 1 ); + pipeline->execute(); const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); @@ -241,9 +248,15 @@ BOOST_AUTO_TEST_CASE( testSynchronousPipeline ) BOOST_AUTO_TEST_CASE( testWaitPipeline ) { - livre::PipeFilterPtr pipeOutput; const uint32_t inputValue = 90; - livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); + livre::PipeFilterPtr pipeInput; + livre::PipeFilterPtr pipeOutput; + + livre::PipelinePtr pipeline = createPipeline( pipeInput, + pipeOutput, + inputValue, + 1 ); + livre::ExecutorPtr executor = createExecutor( 2 ); const livre::FutureMap pipelineFutures( executor->execute( pipeline->getExecutables( ))); @@ -256,9 +269,15 @@ BOOST_AUTO_TEST_CASE( testWaitPipeline ) BOOST_AUTO_TEST_CASE( testAsynchronousPipeline ) { - livre::PipeFilterPtr pipeOutput; const uint32_t inputValue = 90; - livre::PipelinePtr pipeline = createPipeline( pipeOutput, inputValue ); + livre::PipeFilterPtr pipeInput; + livre::PipeFilterPtr pipeOutput; + + livre::PipelinePtr pipeline = createPipeline( pipeInput, + pipeOutput, + inputValue, + 1 ); + livre::ExecutorPtr executor = createExecutor( 2 ); executor->execute( pipeline->getExecutables( )); @@ -274,11 +293,14 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) { const size_t convertFilterCount = 10; const uint32_t inputValue = 90; + livre::PipeFilterPtr pipeInput; livre::PipeFilterPtr pipeOutput; - livre::PipelinePtr pipeline = createPipeline( pipeOutput, + livre::PipelinePtr pipeline = createPipeline( pipeInput, + pipeOutput, inputValue, convertFilterCount ); + livre::ExecutorPtr executor = createExecutor( 1 ); executor->execute( pipeline->getExecutables( )); @@ -291,17 +313,31 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) { const size_t convertFilterCount = 10; const uint32_t inputValue = 90; + livre::PipeFilterPtr pipeInput; livre::PipeFilterPtr pipeOutput; - livre::PipelinePtr pipeline = createPipeline( pipeOutput, + livre::PipelinePtr pipeline = createPipeline( pipeInput, + pipeOutput, inputValue, convertFilterCount ); livre::ExecutorPtr executor = createExecutor( 8 ); + const livre::Futures& futures = executor->execute( pipeline->getExecutables( )); + + const livre::OutFutureMap portFutures1( pipeOutput->getPostconditions( )); + const OutputData& outputData1 = portFutures1.get< OutputData >( "TestOutputData" ); + BOOST_CHECK_EQUAL( outputData1.thanksForAllTheFish, 1761 ); + + // Reset the pipeline but wait pipeline execution before + const livre::FutureMap futureMap( futures ); + futureMap.wait(); + + pipeline->reset(); executor->execute( pipeline->getExecutables( )); + pipeInput->getPromise( "TestInputData" )->set( InputData( inputValue )); - const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); - const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); - BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 1761 ); + const livre::OutFutureMap portFutures2( pipeOutput->getPostconditions( )); + const OutputData& outputData2 = portFutures2.get< OutputData >( "TestOutputData" ); + BOOST_CHECK_EQUAL( outputData2.thanksForAllTheFish, 1761 ); } From 113dcafdb21220cc11c9619a4d2fe92cc7faf02e Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Tue, 15 Mar 2016 14:43:41 +0100 Subject: [PATCH 05/17] Improving according to comments --- livre/core/CMakeLists.txt | 6 +- livre/core/pipeline/AsyncData.cpp | 171 ++++++++++++ livre/core/pipeline/AsyncData.h | 113 ++++++++ livre/core/pipeline/Executable.h | 84 +++++- .../pipeline/{PortType.h => Executor.cpp} | 52 ++-- livre/core/pipeline/Executor.h | 30 +-- livre/core/pipeline/Filter.h | 33 +-- livre/core/pipeline/FunctionFilter.cpp | 88 ------- livre/core/pipeline/FunctionFilter.h | 72 ----- livre/core/pipeline/Future.cpp | 37 ++- livre/core/pipeline/Future.h | 63 ++--- livre/core/pipeline/FutureMap.cpp | 144 ++++------ livre/core/pipeline/FutureMap.h | 245 +++++------------- livre/core/pipeline/InputPort.cpp | 33 +-- livre/core/pipeline/InputPort.h | 16 +- livre/core/pipeline/OutputPort.cpp | 172 ++---------- livre/core/pipeline/OutputPort.h | 79 +----- livre/core/pipeline/PipeFilter.cpp | 190 +++++--------- livre/core/pipeline/PipeFilter.h | 103 ++++---- livre/core/pipeline/Pipeline.cpp | 136 ++++------ livre/core/pipeline/Pipeline.h | 85 +++--- livre/core/pipeline/PortData.h | 40 +-- livre/core/pipeline/PortInfo.h | 81 ------ livre/core/pipeline/Promise.cpp | 39 ++- livre/core/pipeline/Promise.h | 37 ++- livre/core/pipeline/PromiseMap.cpp | 47 ++-- livre/core/pipeline/PromiseMap.h | 22 +- livre/core/pipeline/SimpleExecutor.cpp | 12 +- livre/core/pipeline/SimpleExecutor.h | 18 +- livre/core/pipeline/Workers.cpp | 44 ++-- livre/core/pipeline/Workers.h | 2 +- livre/core/types.h | 48 +++- tests/pipeline/pipeline.cpp | 231 ++++++++--------- 33 files changed, 1136 insertions(+), 1437 deletions(-) create mode 100644 livre/core/pipeline/AsyncData.cpp create mode 100644 livre/core/pipeline/AsyncData.h rename livre/core/pipeline/{PortType.h => Executor.cpp} (58%) delete mode 100644 livre/core/pipeline/FunctionFilter.cpp delete mode 100644 livre/core/pipeline/FunctionFilter.h delete mode 100644 livre/core/pipeline/PortInfo.h diff --git a/livre/core/CMakeLists.txt b/livre/core/CMakeLists.txt index 15b5b2d5..ca67536f 100644 --- a/livre/core/CMakeLists.txt +++ b/livre/core/CMakeLists.txt @@ -57,9 +57,9 @@ set(LIVRECORE_HEADERS visitor/RenderNodeVisitor.h visitor/VisitState.h + pipeline/AsyncData.h pipeline/Executable.h pipeline/Filter.h - pipeline/FunctionFilter.h pipeline/Future.h pipeline/FutureMap.h pipeline/InputPort.h @@ -67,7 +67,6 @@ set(LIVRECORE_HEADERS pipeline/PipeFilter.h pipeline/Pipeline.h pipeline/PortData.h - pipeline/PortType.h pipeline/Promise.h pipeline/PromiseMap.h pipeline/SimpleExecutor.h @@ -111,7 +110,8 @@ set(LIVRECORE_SOURCES visitor/RenderNodeVisitor.cpp visitor/VisitState.cpp - pipeline/FunctionFilter.cpp + pipeline/AsyncData.cpp + pipeline/Executor.cpp pipeline/Future.cpp pipeline/FutureMap.cpp pipeline/InputPort.cpp diff --git a/livre/core/pipeline/AsyncData.cpp b/livre/core/pipeline/AsyncData.cpp new file mode 100644 index 00000000..287af623 --- /dev/null +++ b/livre/core/pipeline/AsyncData.cpp @@ -0,0 +1,171 @@ +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include + +namespace livre +{ + +typedef boost::shared_future< PortDataPtr > ConstPortDataFuture; +typedef boost::promise< PortDataPtr > ConstPortDataPromise; +typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; + +namespace +{ + /* Boost wait_for_any implementation uses the internal locks from the futures. + Therefore, the get/set/query operations on promises/futures causes deadlocks + when used with wait_for_any( futurelist ) if futurelist is including the + future to be queried. With below implementation no locking is needed between + future operations. A higher granularity can be added for checking whether + the list includes the future or not, but simply exiting the wait_for_any + operation when lock is owned is simpler. + */ + ReadWriteMutex waitForAnyLock; +} + +struct AsyncData::Impl +{ + Impl( const DataInfo& dataInfo ) + : _future( _promise.get_future( )) + , _dataInfo( dataInfo ) + {} + + ~Impl() + { + if( !isReady()) + _promise.set_value( PortDataPtr( )); + } + + const PortDataPtr& get( const std::type_index& dataType ) const + { + ReadLock lock( waitForAnyLock ); + + const PortDataPtr& data = _future.get(); + + if( !data ) + LBTHROW( std::runtime_error( "Returns empty data" )); + + if( data->dataType != dataType ) + LBTHROW( std::runtime_error( "Types does not match on get value")); + + return data; + } + + void set( const PortDataPtr& data ) + { + if( data ) + { + if( _dataInfo.second != data->dataType ) + LBTHROW( std::runtime_error( "Types does not match on set value")); + } + + ReadLock lock( waitForAnyLock ); + if( !_future.is_ready( )) + _promise.set_value( data ); + } + + bool isReady() const + { + ReadLock lock( waitForAnyLock ); + return _future.is_ready(); + } + + void wait() const + { + ReadLock lock( waitForAnyLock ); + _future.wait(); + } + + void reset() + { + ConstPortDataPromise newPromise; + _promise.swap( newPromise ); + _future = _promise.get_future(); + } + + ConstPortDataPromise _promise; + mutable ConstPortDataFuture _future; + const DataInfo _dataInfo; +}; + +AsyncData::AsyncData( const DataInfo& dataInfo ) + : _impl( new Impl( dataInfo )) +{} + +const PortDataPtr& AsyncData::get( const std::type_index& dataType ) const +{ + return _impl->get( dataType ); +} + +AsyncData::~AsyncData() +{} + +const std::type_index& AsyncData::getDataType() const +{ + return _impl->_dataInfo.second; +} + +const std::string& AsyncData::getName() const +{ + return _impl->_dataInfo.first; +} + +void AsyncData::set( const PortDataPtr& data ) +{ + _impl->set( data ); +} + +bool AsyncData::isReady() const +{ + return _impl->isReady(); +} + +void AsyncData::wait() const +{ + _impl->wait(); +} + +void AsyncData::reset() +{ + _impl->reset(); +} + +bool waitForAny( const Futures& futures ) +{ + if( futures.empty( )) + return false; + + ConstPortDataFutures boostFutures; + boostFutures.reserve( futures.size( )); + for( const auto& future: futures ) + boostFutures.push_back( future._getAsyncData()._impl->_future ); + + WriteLock lock( waitForAnyLock, boost::try_to_lock ); + if( !lock.owns_lock( )) + return true; + + boost::wait_for_any( boostFutures.begin(), boostFutures.end( )); + return true; +} + +} diff --git a/livre/core/pipeline/AsyncData.h b/livre/core/pipeline/AsyncData.h new file mode 100644 index 00000000..32ce8a6b --- /dev/null +++ b/livre/core/pipeline/AsyncData.h @@ -0,0 +1,113 @@ +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _AsyncData_h_ +#define _AsyncData_h_ + +#include + +namespace livre +{ + +/** + * The AsyncData class provides thread safe operations for setting/retrieving/querying + * the data. The internal data has a name and data type. + */ +class AsyncData +{ +public: + + /** + * When connection is instantiated the data is not + * set yet, so any get() call will block the retrieval + * @param name of the connection + * @param dataType type of the data + */ + explicit AsyncData( const DataInfo& dataInfo ); + ~AsyncData(); + + /** + * @return the name of the connection + */ + const std::type_index& getDataType() const; + + /** + * @return the name of the connection + */ + const std::string& getName() const; + + /** + * @param data sets the data + * @throws std::runtime_error if data types does not match between data + * and current async data + */ + void set( const PortDataPtr& data ); + + /** + * @param dataType is the requested data type. + * @return the data. If data is not set it will block. + * @throws std::runtime_error if data types does not match between dataType + * and current async data type + */ + const PortDataPtr& get( const std::type_index& dataType ) const; + + /** + * @return true if data is set. + */ + bool isReady() const; + + /** + * Waits until data is set + */ + void wait() const; + + /** + * Resets the promise/future + */ + void reset(); + +private: + + /** + * Waits for any future to be ready. + * @param futures queried to be ready. + * @note this function needs internal access to the futures ( which is not exposed in the API ). + * @return true if any new futures are ready or futures included are not busy. + */ + friend bool waitForAny( const Futures& futures ); + + AsyncData( const AsyncData& ) = delete; + AsyncData& operator=( const AsyncData& ) = delete; + + struct Impl; + std::unique_ptr _impl; +}; + +/** + * Waits for any futures to be ready. If there are already ready futures the function returns + * imeediately. + * @param futures that is waited to be ready + * @return true if there are still not ready futures. + */ +bool waitForAny( const Futures& futures ); + +} + +#endif // _AsyncData_h_ + diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h index 7153a24f..af6b6b3e 100644 --- a/livre/core/pipeline/Executable.h +++ b/livre/core/pipeline/Executable.h @@ -27,41 +27,99 @@ namespace livre { /** - * The Executable class is the base class for objects that can be executed by workers. It - * provides extra pre/post conditions as futures to retrieve the current situation. + * The Executable class is constructed using ExecutableImpl + * classes. It wraps the methods for execution of ExecutableImpl. + * a ExecutableImpl. It provides extra pre/post + * conditions as futures to retrieve the current situation. * - * According to given futures executors can decide on scheduling algorithms. Also the - * input and are output futures can be queried for the results. @see PipeFilter and - * @see Pipeline classes are based on this class. + * According to the preconditions or postconditions, + * executors can decide on scheduling algorithms. */ class Executable { public: - Executable() {} - virtual ~Executable() {} + struct ExecutableImpl; + + /** + * @param impl Executable implementation. T class must be + * derived from ExecutableImpl and must be copy constructible + */ + template< class T > + Executable( const T& impl ) + : _impl( ExecutableImplPtr( new T( impl ))) + {} + + /** + * @return the implementation + */ + const ExecutableImpl& getImpl() const { return *_impl; } /** * Executes the executable */ - virtual void execute() = 0; + void execute() + { + _impl->execute(); + } /** - * @return the output futures for querying the outputs of the executable. + * @return the output futures for getting the outputs of the executable. The post + * conditions has to be fullfilled by the execute() implementation ( at the end of + * execution all futures should be ready ) */ - virtual Futures getPostconditions() const { return Futures(); } + Futures getPostconditions() const + { + return _impl->getPostconditions(); + } /** * @return the input futures which the executable can be queried for the state or * data retrieval. */ - virtual Futures getPreconditions() const { return Futures(); } + Futures getPreconditions() const + { + return _impl->getPreconditions(); + } + + /** + * Resets the executable by setting all pre and post conditions to an clean state + * ( The futures are not ready ) + */ + void reset() { _impl->reset(); } /** - * Resets the executable + * Executable implementation */ - virtual void reset() {} + struct ExecutableImpl + { + /** + * @copydoc Executable::execute + */ + virtual void execute() = 0; + + /** + * @copydoc Executable::getPostconditions + */ + virtual Futures getPostconditions() const = 0; + + /** + * @copydoc Executable::getPreconditions + */ + virtual Futures getPreconditions() const = 0; + + /** + * @copydoc Executable::reset + */ + virtual void reset() {} + + virtual ~ExecutableImpl() {} + }; + +private: + typedef std::shared_ptr< ExecutableImpl > ExecutableImplPtr; + ExecutableImplPtr _impl; }; } diff --git a/livre/core/pipeline/PortType.h b/livre/core/pipeline/Executor.cpp similarity index 58% rename from livre/core/pipeline/PortType.h rename to livre/core/pipeline/Executor.cpp index 6f21ad5d..5fe902dd 100644 --- a/livre/core/pipeline/PortType.h +++ b/livre/core/pipeline/Executor.cpp @@ -17,43 +17,33 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _PortType_h_ -#define _PortType_h_ - -#include +#include +#include namespace livre { -/** - * PortType class is base class for keeping the track for types - * by using the std::type_index. - */ -class PortType +Futures Executor::execute( const Executable& executable ) { -public: - - /** - * @return the type index - */ - const std::type_index& getDataType() const - { return _dataType; } - -protected: - - /** - * PortType constructor - * @param typeIndex type index of the data of the - * derived classes data type. - */ - explicit PortType( const std::type_index& dataType ) - : _dataType( dataType) {} - -private: - const std::type_index _dataType; -}; + const Futures& fs = executable.getPostconditions(); + _schedule({ executable }); + return fs; +} +Futures Executor::execute( const Executables& executables ) +{ + Futures futures; + for( const Executable& executable: executables ) + { + const Futures& fs = executable.getPostconditions( ); + futures.insert( futures.end(), fs.begin(), fs.end( )); + } + + _schedule( executables ); + return futures; } -#endif // _PortData_h_ +Executor::~Executor() +{} +} diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h index 3e810281..a66b26f1 100644 --- a/livre/core/pipeline/Executor.h +++ b/livre/core/pipeline/Executor.h @@ -21,7 +21,6 @@ #define _Executor_h_ #include -#include namespace livre { @@ -35,46 +34,33 @@ class Executor { public: - virtual ~Executor() {} + virtual ~Executor(); /** * Executes the executable. Returns the futures that can be queried for data. * @param pipeline to be executed. */ - Futures execute( const ExecutablePtr& executable ) - { - const Futures& fs = executable->getPostconditions(); - _schedule( { executable } ); - return fs; - } + Futures execute( const Executable& executable ); /** * Executes the executable. Returns the futures that can be queried for data. * @param pipeline to be executed. */ - Futures execute( const Executables& executables ) - { - Futures futures; - for( const ExecutablePtr& executable: executables ) - { - const Futures& fs = executable->getPostconditions( ); - futures.insert( futures.end(), fs.begin(), fs.end( )); - } - - _schedule( executables ); - return futures; - } + Futures execute( const Executables& executables ); protected: /** - * Schedules the executables for execution. + * Schedules the executables for execution. The deriving class should implement a + * scheduling algorithm for the execution. ( i.e. there may be a work queue and + * executables are selected from the work queue according to their pre-post + * conditions * @param executables are the executables to schedule. */ virtual void _schedule( const Executables& executables ) = 0; /** - * Clears the executor + * Clears the executor ( i.e : Implementation can empty the work queue ) */ virtual void clear() {} diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h index c04d972d..4443e913 100644 --- a/livre/core/pipeline/Filter.h +++ b/livre/core/pipeline/Filter.h @@ -21,25 +21,16 @@ #define _Filter_h_ #include -#include namespace livre { /** - * Filters are similar to functions (immutable). Their inputs and - * outputs are provided through ports. These ports provide - * thread safe information retrieval, setting and querying. - * - * One input port may have many incoming connections and one output - * port can be connected to many other input connections. The ports - * have their unique names and these names are used to query, - * retrieve and set data. - * - * PipeFilters class build the connection and execution - * functionality around filter instances. + * Filters are similar to functions ( immutable ). Their inputs and + * outputs are provided with given name and data types. In execution time + * values can be queried from the map of futures ( name - future pairs ) + * and can be set through the map of promises ( name - promise maps ) */ - class Filter { public: @@ -50,19 +41,21 @@ class Filter * @param input The Future that can be read for input parameters * @param output The Promise that can be written to for output parameters */ - virtual void execute( const InFutureMap& input, PromiseMap& output ) const = 0; + virtual void execute( const FutureMap& input, PromiseMap& output ) const = 0; /** - * @param inputPorts information is filled by the Filter class. - * These ports are constructed by the @PipeFilter. + * @return information for the name and data types for the filter + * communication. In execution time using these names and types, + * data can be retrieved. */ - virtual PortInfos getInputPorts() const { return PortInfos(); } + virtual DataInfos getInputDataInfos() const { return DataInfos(); } /** - * @param outputPorts information is filled by the Filter class. - * Afterwards, these ports are instantiated by the @PipeFilter. + * @return information for the name and data types for the filter + * communication. In execution time using these names and types, + * data can be set. */ - virtual PortInfos getOutputPorts() const { return PortInfos(); } + virtual DataInfos getOutputDataInfos() const { return DataInfos(); } virtual ~Filter() {} }; diff --git a/livre/core/pipeline/FunctionFilter.cpp b/livre/core/pipeline/FunctionFilter.cpp deleted file mode 100644 index 53398cdc..00000000 --- a/livre/core/pipeline/FunctionFilter.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include - -namespace livre -{ - -struct FunctionFilter::Impl -{ - Impl( const FilterFunc& filterFunc, - const PortInfos& inputPorts, - const PortInfos& outputPorts ) - : _filterFunc( filterFunc ) - , _inputPorts( inputPorts ) - , _outputPorts( outputPorts ) - {} - - void execute( const InFutureMap& input, PromiseMap& output ) const - { - _filterFunc( input, output ); - } - - PortInfos getInputPorts() const - { - return _inputPorts; - } - - PortInfos getOutputPorts() const - { - return _outputPorts; - } - -private: - - - FilterFunc _filterFunc; - const PortInfos _inputPorts; - const PortInfos _outputPorts; -}; - -FunctionFilter::FunctionFilter( const FilterFunc& filterFunc, - const PortInfos& inputPorts, - const PortInfos& outputPorts ) - : _impl( new FunctionFilter::Impl( filterFunc, - inputPorts, - outputPorts )) -{} - -FunctionFilter::~FunctionFilter() -{} - -void FunctionFilter::execute( const InFutureMap& input, PromiseMap& output ) const -{ - _impl->execute( input, output ); -} - -PortInfos FunctionFilter::getInputPorts() const -{ - return _impl->getInputPorts(); -} - -PortInfos FunctionFilter::getOutputPorts() const -{ - return _impl->getOutputPorts(); -} - -} - - - diff --git a/livre/core/pipeline/FunctionFilter.h b/livre/core/pipeline/FunctionFilter.h deleted file mode 100644 index 896effa5..00000000 --- a/livre/core/pipeline/FunctionFilter.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _FunctionFilter_h_ -#define _FunctionFilter_h_ - -#include -#include - -namespace livre -{ - -/** - * The FunctionFilter class is used to create filters based - * on filter function definitions. i.e. A class can implement - * a filter by using a function. - */ -struct FunctionFilter final : public Filter -{ - /** - * Constructs a filter based on function object. - * @param filterFunc The filter function object. - * @param inputPorts are the input ports information. - * @param outputPorts are the output ports information. - */ - FunctionFilter( const FilterFunc& filterFunc, - const PortInfos& inputPorts, - const PortInfos& outputPorts ); - ~FunctionFilter(); - - /** - * @copydoc Filter::execute( PipeFilter& filter ) - */ - void execute( const InFutureMap& input, PromiseMap& output ) const final; - - /** - * @copydoc Filter::getInputPorts() - */ - PortInfos getInputPorts() const final; - - /** - * @copydoc Filter::getOutputPorts() - */ - PortInfos getOutputPorts() const final; - -private: - - struct Impl; - std::shared_ptr _impl; -}; - -} - -#endif // _FunctionFilter_h_ - - diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp index b66edf63..d27835cf 100644 --- a/livre/core/pipeline/Future.cpp +++ b/livre/core/pipeline/Future.cpp @@ -18,8 +18,7 @@ */ #include - -#include +#include namespace livre { @@ -28,18 +27,26 @@ struct Future::Impl { Impl( const PipeFilter& pipeFilter, const AsyncData& data ) - : _pipeFilter( pipeFilter ) + : _name( data.getName( )) + , _pipeFilter( pipeFilter ) , _data( data ) {} + Future rename( const std::string& name ) const + { + Future ret( _pipeFilter, _data ); + ret._impl->_name = name; + return ret; + } + const std::string& getName() const { - return _data.getName(); + return _name; } - ConstPortDataPtr get() const + PortDataPtr get( const std::type_index& dataType ) const { - return _data.get(); + return _data.get( dataType ); } bool isReady() const @@ -52,6 +59,7 @@ struct Future::Impl return _data.wait(); } + std::string _name; const PipeFilter& _pipeFilter; const AsyncData& _data; }; @@ -64,14 +72,14 @@ Future::Future( const PipeFilter& pipeFilter, Future::~Future() {} -const AsyncData& Future::getAsyncData() const +const std::string& Future::getName() const { - return _impl->_data; + return _impl->getName(); } -const std::string& Future::getName() const +Future Future::rename( const std::string& name ) const { - return _impl->getName(); + return _impl->rename( name ); } void Future::wait() const @@ -89,9 +97,14 @@ const PipeFilter& Future::getPipeFilter() const return _impl->_pipeFilter; } -ConstPortDataPtr Future::_get() const +const AsyncData& Future::_getAsyncData() const +{ + return _impl->_data; +} + +PortDataPtr Future::_getPtr( const std::type_index& dataType ) const { - return _impl->get(); + return _impl->get( dataType ); } } diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h index 32130c5b..77ca5c90 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/Future.h @@ -26,10 +26,20 @@ namespace livre { +/** + * The Future class is similar to the std::future classes in functionality and it has additional + * information for the name and data type. It provides thread safe methods to query and get the + * data. Futures are retrieved from the @see Promise class. + */ class Future { public: + /** + * @param pipeFilter is the reference to @Pipefilter class which + * instantiates the @see Promise that Future belongs to. + * @param data holds the thread safe data (query/retrieve). + */ Future( const PipeFilter& pipeFilter, const AsyncData& data ); ~Future(); @@ -40,44 +50,19 @@ class Future const std::string& getName() const; /** - * Gets the value with the given type T. If output is not set - * this function will block. - * @return the value. - * @throw std::runtime_error when the port data is not exact - * type T + * Gets a copy future with the given name */ - template< class T > - const T& get() const - { - typedef typename std::remove_const::type UnconstT; - const auto& dataPtr = - boost::dynamic_pointer_cast< const PortDataT< UnconstT >>( _get( )); - - if( !dataPtr ) - LBTHROW( std::runtime_error( "Invalid data type" )); - - return dataPtr->data; - } + Future rename( const std::string& name ) const; /** - * Moves the value with the given type T. If output is not set + * Gets the value with the given type T. If output is not set * this function will block. * @return the value. - * @throw std::runtime_error when the port data is not exact + * @throw std::runtime_error when the data is not exact * type T */ template< class T > - const T&& move() const - { - typedef typename std::remove_const::type UnconstT; - const auto& dataPtr = - boost::dynamic_pointer_cast< const PortDataT< UnconstT >>( _get( )); - - if( !dataPtr ) - LBTHROW( std::runtime_error( "Invalid data type" )); - - return std::move( dataPtr->data ); - } + const T& get() const { return _get(); } /** * Waits until the data is ready. @@ -95,11 +80,6 @@ class Future */ const PipeFilter& getPipeFilter() const; - /** - * @return the async data implementation - */ - const AsyncData& getAsyncData() const; - /** * @param future is the future to be checked with * @return true if both futures are same @@ -110,7 +90,18 @@ class Future friend bool livre::waitForAny( const Futures& future ); - ConstPortDataPtr _get() const; + const AsyncData& _getAsyncData() const; + + template< class T > + const T& _get() const + { + const auto& dataPtr = + std::static_pointer_cast< const PortDataT< T >>( _getPtr( getType< T >( ))); + + return dataPtr->data; + } + + PortDataPtr _getPtr( const std::type_index& dataType ) const; struct Impl; std::shared_ptr _impl; diff --git a/livre/core/pipeline/FutureMap.cpp b/livre/core/pipeline/FutureMap.cpp index 774886ed..10d4b667 100644 --- a/livre/core/pipeline/FutureMap.cpp +++ b/livre/core/pipeline/FutureMap.cpp @@ -18,8 +18,8 @@ */ #include -#include -#include +#include +#include namespace livre { @@ -31,20 +31,20 @@ struct FutureMapImpl { public: - void throwPortError( const std::string& portName ) const + void throwError( const std::string& name ) const { - LBTHROW( std::runtime_error( std::string( "No futures assigned with the given port with name: ") - + portName )); + LBTHROW( std::runtime_error( std::string( "Unknown future name: ") + + name )); } - bool hasPort( const std::string& portName ) const + bool hasFuture( const std::string& name ) const { - return _futureMap.count( portName ) > 0; + return _futureMap.count( name ) > 0; } - Futures getFutures( const std::string& portName ) const + Futures getFutures( const std::string& name ) const { - if( portName == ALL_PORTS ) + if( name == ALL_FUTURES ) { Futures futures; for( const auto& pair: _futureMap ) @@ -52,11 +52,11 @@ struct FutureMapImpl return futures; } - if( !hasPort( portName )) - throwPortError( portName ); + if( !hasFuture( name )) + throwError( name ); Futures futures; - NameFutureMap::const_iterator it = _futureMap.find( portName ); + NameFutureMap::const_iterator it = _futureMap.find( name ); while( it != _futureMap.end( )) { @@ -67,9 +67,9 @@ struct FutureMapImpl return futures; } - bool isReady( const std::string& portName ) const + bool isReady( const std::string& name ) const { - for( const auto& future: getFutures( portName )) + for( const auto& future: getFutures( name )) { if( !future.isReady()) return false; @@ -77,15 +77,15 @@ struct FutureMapImpl return true; } - void wait( const std::string& portName ) const + void wait( const std::string& name ) const { - for( const auto& future: getFutures( portName )) + for( const auto& future: getFutures( name )) future.wait(); } - bool waitForAny( const std::string& portName ) const + bool waitForAny( const std::string& name ) const { - return livre::waitForAny( getFutures( portName )); + return livre::waitForAny( getFutures( name )); } void addFuture( const std::string& name, const Future& future ) @@ -96,7 +96,7 @@ struct FutureMapImpl NameFutureMap _futureMap; }; -struct FutureMap::Impl: public FutureMapImpl +struct UniqueFutureMap::Impl: public FutureMapImpl { public: Impl( const Futures& futures ) @@ -104,125 +104,85 @@ struct FutureMap::Impl: public FutureMapImpl for( const auto& future: futures ) { const std::string& name = future.getName(); + if( hasFuture( name )) + throwError( name ); addFuture( name, future ); } } }; -FutureMap::FutureMap( const Futures& futures ) - : _impl( new FutureMap::Impl( futures )) +UniqueFutureMap::UniqueFutureMap( const Futures& futures ) + : _impl( new UniqueFutureMap::Impl( futures )) {} -Futures FutureMap::getFutures() const -{ - return _impl->getFutures( ALL_PORTS ); -} - -bool FutureMap::isReady() const -{ - return _impl->isReady( ALL_PORTS ); -} - -void FutureMap::wait() const -{ - _impl->wait( ALL_PORTS ); -} - -bool FutureMap::waitForAny() const +Futures UniqueFutureMap::getFutures() const { - return _impl->waitForAny( ALL_PORTS ); + return _impl->getFutures( ALL_FUTURES ); } -FutureMap::~FutureMap() -{} - -struct OutFutureMap::Impl: public FutureMapImpl -{ -public: - Impl( const Futures& futures ) - { - for( const auto& future: futures ) - { - const std::string& name = future.getName(); - if( hasPort( name )) - throwPortError( name ); - addFuture( name, future ); - } - } -}; - -OutFutureMap::OutFutureMap( const Futures& futures ) - : _impl( new OutFutureMap::Impl( futures )) -{} - -Futures OutFutureMap::getFutures() const +Future UniqueFutureMap::getFuture( const std::string& name ) const { - return _impl->getFutures( ALL_PORTS ); -} + if( name == ALL_FUTURES ) + LBTHROW( std::runtime_error( "All futures cannot be retrieved with this function")) -Future OutFutureMap::getFuture( const std::string& portName ) const -{ - return _impl->getFutures( portName ).front(); + return _impl->getFutures( name ).front(); } -bool OutFutureMap::isReady( const std::string& portName ) const +bool UniqueFutureMap::isReady( const std::string& name ) const { - return _impl->isReady( portName ); + return _impl->isReady( name ); } -void OutFutureMap::wait( const std::string& portName ) const +void UniqueFutureMap::wait( const std::string& name ) const { - _impl->wait( portName ); + _impl->wait( name ); } -bool OutFutureMap::waitForAny() const +bool UniqueFutureMap::waitForAny() const { - return _impl->waitForAny( ALL_PORTS ); + return _impl->waitForAny( ALL_FUTURES ); } -OutFutureMap::~OutFutureMap() +UniqueFutureMap::~UniqueFutureMap() {} -struct InFutureMap::Impl: public FutureMapImpl +struct FutureMap::Impl: public FutureMapImpl { public: - Impl( const InputPorts& inputPorts ) + Impl( const Futures& futures ) { - for( const InputPortPtr& inputPort: inputPorts ) - { - const Futures& futures = inputPort->getFutures(); - for( const auto& future: futures ) - addFuture( inputPort->getName(), future ); - } + for( const auto& future: futures ) + addFuture( future.getName(), future ); + } }; -InFutureMap::InFutureMap( const InputPorts& inputPorts ) - : _impl( new InFutureMap::Impl( inputPorts )) +FutureMap::FutureMap( const Futures& futures ) + : _impl( new FutureMap::Impl( futures )) { } -Futures InFutureMap::getFutures( const std::string& portName ) const +Futures FutureMap::getFutures( const std::string& name ) const { - return _impl->getFutures( portName ); + return _impl->getFutures( name ); } -bool InFutureMap::isReady( const std::string& portName ) const +bool FutureMap::isReady( const std::string& name ) const { - return _impl->isReady( portName ); + return _impl->isReady( name ); } -void InFutureMap::wait( const std::string& portName ) const +void FutureMap::wait( const std::string& name ) const { - _impl->wait( portName ); + _impl->wait( name ); } -bool InFutureMap::waitForAny( const std::string& portName ) const +bool FutureMap::waitForAny( const std::string& name ) const { - return _impl->waitForAny( portName ); + return _impl->waitForAny( name ); } -InFutureMap::~InFutureMap() +FutureMap::~FutureMap() {} diff --git a/livre/core/pipeline/FutureMap.h b/livre/core/pipeline/FutureMap.h index 27976dcd..cb2610f2 100644 --- a/livre/core/pipeline/FutureMap.h +++ b/livre/core/pipeline/FutureMap.h @@ -27,132 +27,89 @@ namespace livre { /** - * The Futures classes are a wrappers to access the group of future - * and execute thread-safe operations on them. With a given portName (name) - * many futures can be associated. - */ - -/** - * FutureMap class provides basic functionality to query state of multiple futures. + * FutureMap is a wrapper class to query multiple futures with same names for data and data state. */ class FutureMap { public: /** - * @param futures the list of futures. + * @param futures is the list of futures + * future names are used for name-future association. */ explicit FutureMap( const Futures& futures ); ~FutureMap(); - /** - * @return the futures associated with port name. - */ - Futures getFutures() const; - - /** - * Queries if all ports are ready - * @return true if all port inputs are ready. - */ - bool isReady() const; - - /** - * Waits all futures - */ - void wait() const; - - /** - * Waits for any futures - * @return true if any future is waited. - */ - bool waitForAny() const; - -private: - - struct Impl; - std::shared_ptr _impl; -}; - -/** - * PortFutures for managing ports with unique names. - */ -class OutFutureMap -{ -public: - - /** - * @param futures the list of futures. - * @throws std::runtime_error when futures are not unique in names - */ - explicit OutFutureMap( const Futures& futures ); - ~OutFutureMap(); - /** * Gets the copy of value(s) with the given type T. If input * is connected and values are not provided this function will * block. - * @param portName is the port name assoicated with futures. - * @return the values port, value map. + * @param name of the future. + * @return the values of the futures. * @throw std::runtime_error when the port data is not exact * type T */ template< class T > - const T& get( const std::string& portName ) const + ResultsT< T > get( const std::string& name ) const { - return getFuture( portName ).get< T >(); + ResultsT< T > results; + for( const auto& future: getFutures( name )) + results.push_back( future.get< T >( )); + + return results; } /** - * Moves the value(s) with the given type T. If input - * is connected and values are not provided this function will - * block. - * @param portName is the port name assoicated with futures. - * @return the values vector. + * Gets the copy of ready value(s) with the given type T. + * @param name of the future. + * @return the values of the futures. * @throw std::runtime_error when the port data is not exact * type T */ template< class T > - const T&& move( const std::string& portName ) const + ResultsT< T > getReady( const std::string& name ) const { - return getFuture( portName ).move< T >(); - } + ResultsT< T > results; + for( const auto& future: getFutures( name )) + { + if( !future.isReady()) + continue; - /** - * @param portName is the port name assoicated with the future. If port name - * is ALL_PORTS, all futures are marked to return. - * @return the futures associated with port name. - */ - Future getFuture( const std::string& portName ) const; + results.push_back( future.get< T >( )); + } + return results; + } /** - * @param portName is the port name assoicated with futures. If port name - * is ALL_PORTS, all futures are marked to return. - * @return the future associated with port name. + * @param name of the future. If name is ALL_FUTURES, all futures are marked to return. + * @return the futures associated with the name. */ - Futures getFutures() const; + Futures getFutures( const std::string& portName = ALL_FUTURES ) const; /** * Queries if port is ready - * @param portName is the port name assoicated with the future. + * @param name of the future. If name is ALL_FUTURES, all futures are queried * @return true if all port inputs are ready. - * @throw std::runtime_error when there is no future associated with - * given port name + * @throw std::runtime_error when there is no future associated with the + * given name */ - bool isReady( const std::string& portName = ALL_PORTS ) const; + bool isReady( const std::string& portName = ALL_FUTURES ) const; /** - * Waits for the future associated with port name - * @param portName is the port name assoicated with futures. - * @throw std::runtime_error when there is no future associated with - * given port name + * Waits all futures associated with port name + * @param name of the future. If name is ALL_FUTURES, all futures are waited. + * @throw std::runtime_error when there is no future associated with the + * given name */ - void wait( const std::string& portName = ALL_PORTS ) const; + void wait( const std::string& portName = ALL_FUTURES ) const; /** - * Waits for any futures. - * @return true if any future is waited. + * Waits all futures associated with port name. + * @param name of the future. If name is ALL_FUTURES, all futures are waited. + * @throw std::runtime_error when there is no future associated with the + * given name */ - bool waitForAny() const; + bool waitForAny( const std::string& portName = ALL_FUTURES ) const; private: @@ -161,130 +118,68 @@ class OutFutureMap }; /** - * PortFutures for managing ports with non unique named ports. + * UniqueFutureMap is a wrapper class to query futures with unique names for data and data state. */ -class InFutureMap +class UniqueFutureMap { public: /** - * @param inputPorts is the list of input ports - * future names are used for name-future association. + * @param futures the list of futures. + * @throws std::runtime_error when futures are not unique in names */ - explicit InFutureMap( const InputPorts& inputPorts ); - ~InFutureMap(); + explicit UniqueFutureMap( const Futures& futures ); + ~UniqueFutureMap(); /** * Gets the copy of value(s) with the given type T. If input * is connected and values are not provided this function will * block. - * @param portName is the port name assoicated with futures. - * @return the values port, value map. - * @throw std::runtime_error when the port data is not exact - * type T - */ - template< class T > - ResultsT< T > get( const std::string& portName ) const - { - ResultsT< T > results; - for( const auto& future: getFutures( portName )) - results.push_back( future.get< T >( )); - - return results; - } - - /** - * Moves the value(s) with the given type T. If input - * is connected and values are not provided this function will - * block. - * @param portName is the port name assoicated with futures. - * @return the values vector. - * @throw std::runtime_error when the port data is not exact - * type T - */ - template< class T > - ResultsT< T > move( const std::string& portName ) const - { - ResultsT< T > results; - for( const auto& future: getFutures( portName )) - results.push_back( future.move< T >( )); - - return results; - } - - /** - * Gets the copy of ready value(s) with the given type T. - * @param portName is the port name assoicated with futures. - * @return the values vector. + * @param name of the future. + * @return the value for the future. * @throw std::runtime_error when the port data is not exact * type T */ template< class T > - ResultsT< T > getReady( const std::string& portName ) const + const T& get( const std::string& name ) const { - ResultsT< T > results; - for( const auto& future: getFutures( portName )) - { - if( !future.isReady()) - continue; - - results.push_back( future.get< T >( )); - } - return results; + return getFuture( name ).get< T >(); } /** - * Moves the ready value(s) with the given type T - * @param portName is the port name assoicated with futures. - * @return the values vector. - * @throw std::runtime_error when the port data is not exact - * type T or there is no future assigned to given port name + * @param name of the future + * @return the future associated with the name. + * @throw std::runtime_error when the name is ALL_FUTURES */ - template< class T > - ResultsT< T > moveReady( const std::string& portName ) const - { - ResultsT< T > results; - for( const auto& future: getFutures( portName )) - { - if( !future.isReady()) - continue; - - results.push_back( future.move< T >( )); - } - return results; - } + Future getFuture( const std::string& name ) const; /** - * @param portName is the port name assoicated with futures. If port name - * is ALL_PORTS, all futures are marked to return. - * @return the futures associated with port name. + * @return all the futures. */ - Futures getFutures( const std::string& portName ) const; + Futures getFutures() const; /** * Queries if port is ready - * @param portName is the port name assoicated with futures. - * @return true if all port inputs are ready. - * @throw std::runtime_error when there is no future associated with - * given port name + * @param name of the future + * @return true if all futures are ready. + * @throw std::runtime_error when there is no future associated with the + * given name */ - bool isReady( const std::string& portName ) const; + bool isReady( const std::string& name = ALL_FUTURES ) const; /** - * Waits all futures associated with port name - * @param portName is the port name assoicated with futures. - * @throw std::runtime_error when there is no future associated with - * given port name + * Waits for the future associated with port name + * @param name is the port name assoicated with futures. + * @throw std::runtime_error when there is no future associated with the + * given name */ - void wait( const std::string& portName ) const; + void wait( const std::string& name = ALL_FUTURES ) const; /** - * Waits all futures associated with port name. - * @param portName is the port name assoicated with futures. - * @throw std::runtime_error when there is no future associated with - * given port name + * Waits for any future to be ready. + * @return true if there are still futures which are not ready. */ - bool waitForAny( const std::string& portName ) const; + bool waitForAny() const; private: diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp index 280e6744..f99024fb 100644 --- a/livre/core/pipeline/InputPort.cpp +++ b/livre/core/pipeline/InputPort.cpp @@ -27,7 +27,7 @@ namespace livre struct InputPort::Impl { - Impl( const PortInfo& info ) + Impl( const DataInfo& info ) : _info( info ) {} @@ -36,7 +36,7 @@ struct InputPort::Impl const std::string& getName() const { - return _info.name; + return _info.first; } size_t getSize() const @@ -46,37 +46,38 @@ struct InputPort::Impl const std::type_index& getDataType() const { - return _info.getDataType(); + return _info.second; } - void connect( const OutputPort& outputPort ) + void connect( const OutputPort& port ) { - if( getDataType() != outputPort.getDataType( )) + if( getDataType() != port.getDataType( )) LBTHROW( std::runtime_error( "Data types does not match between ports")); - _futures.push_back( outputPort.getPromise()->getFuture( )); + _futures.push_back( port.getPromise().getFuture( )); } - void disconnect( const OutputPort& outputPort ) + bool disconnect( const OutputPort& port ) { Futures::iterator it = _futures.begin(); while( it != _futures.end()) { - if( *it == outputPort.getPromise()->getFuture( )) + if( *it == port.getPromise().getFuture( )) { _futures.erase( it ); - return; + return true; } ++it; } + return false; } Futures _futures; - const PortInfo _info; + const DataInfo _info; }; -InputPort::InputPort( const PortInfo& portInfo ) - : _impl( new InputPort::Impl( portInfo )) +InputPort::InputPort( const DataInfo& dataInfo ) + : _impl( new InputPort::Impl( dataInfo )) {} InputPort::~InputPort() @@ -87,14 +88,14 @@ const Futures& InputPort::getFutures() const return _impl->_futures; } -void InputPort::connect( const OutputPort& outputPort ) +void InputPort::connect( const OutputPort& port ) { - _impl->connect( outputPort ); + _impl->connect( port ); } -void InputPort::disconnect( const OutputPort& outputPort ) +bool InputPort::disconnect( const OutputPort& port ) { - _impl->disconnect( outputPort ); + return _impl->disconnect( port ); } const std::string& InputPort::getName() const diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index 9985ea0f..94824e82 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -21,8 +21,6 @@ #define _InputPort_h_ #include -#include -#include namespace livre { @@ -37,9 +35,9 @@ class InputPort /** * InputPort constructor based on port information - * @param portInfo is the port information + * @param dataInfo is the port information */ - explicit InputPort( const PortInfo& portInfo ); + explicit InputPort( const DataInfo& dataInfo ); ~InputPort(); /** @@ -64,15 +62,17 @@ class InputPort /** * Connects an output port to input port - * @param inputPort input port + * @param port is the connected output port. */ - void connect( const OutputPort& inputPort ); + void connect( const OutputPort& port ); /** * Disconnects an output port from input port - * @param inputPort input port + * @param port is the disconnected output port. + * @return true if output port is found as a connection and removed + * for the connections */ - void disconnect( const OutputPort& inputPort ); + bool disconnect( const OutputPort& port ); private: diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp index 857ef96e..6169fe67 100644 --- a/livre/core/pipeline/OutputPort.cpp +++ b/livre/core/pipeline/OutputPort.cpp @@ -19,132 +19,15 @@ #include #include -#include #include -#include - namespace livre { -typedef boost::shared_future< ConstPortDataPtr > ConstPortDataFuture; -typedef boost::promise< ConstPortDataPtr > ConstPortDataPromise; -typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; - -namespace -{ - /* Boost wait_for_any implementation uses the internal locks from the futures. - Therefore, the get/set/query operations on promises/futures causes deadlocks - when used with wait_for_any( futurelist ) if futurelist is including the - future to be queried. With below implementation no locking is needed between - future operations. A higher granularity can be added for checking whether - the list includes the future or not, but simply exiting the wait_for_any - operation when lock is owned is simpler. - */ - - ReadWriteMutex waitForAnyLock; -} - -struct AsyncData::Impl -{ - Impl( const std::string& name, - const std::type_index& dataType ) - : _future( _promise.get_future( )) - , _name( name ) - , _dataType( dataType ) - {} - - ~Impl() - { - if( !isReady()) - _promise.set_value( ConstPortDataPtr( )); - } - - const ConstPortDataPtr& get() const - { - ReadLock lock( waitForAnyLock ); - return _future.get(); - } - - void set( const ConstPortDataPtr& data ) - { - if( data ) - { - if( data->getDataType() != _dataType ) - LBTHROW( std::runtime_error( "Types does not match on set value")); - } - - ReadLock lock( waitForAnyLock ); - if( !_future.is_ready( )) - _promise.set_value( data ); - } - - bool isReady() const - { - ReadLock lock( waitForAnyLock ); - return _future.is_ready(); - } - - void wait() const - { - ReadLock lock( waitForAnyLock ); - _future.wait(); - } - - void reset() - { - ConstPortDataPromise newPromise; - _promise.swap( newPromise ); - _future = _promise.get_future(); - } - - ConstPortDataPromise _promise; - mutable ConstPortDataFuture _future; - const std::string _name; - const std::type_index _dataType; -}; - -AsyncData::AsyncData( const std::string& name, - const std::type_index& dataType ) - : _impl( new Impl( name, dataType )) -{} - -const ConstPortDataPtr& AsyncData::get() const -{ - return _impl->get(); -} - -const std::string& AsyncData::getName() const -{ - return _impl->_name; -} - -void AsyncData::set( const ConstPortDataPtr& data ) -{ - _impl->set( data ); -} - -bool AsyncData::isReady() const -{ - return _impl->isReady(); -} - -void AsyncData::wait() const -{ - _impl->wait(); -} - -void AsyncData::reset() -{ - _impl->reset(); -} - struct OutputPort::Impl { - Impl( const PipeFilter& pipeFilter, const PortInfo& portInfo ) - : _info( portInfo ) - , _data( portInfo.name, portInfo.getDataType( )) - , _portPromise( new Promise( pipeFilter, _data )) + Impl( const PipeFilter& pipeFilter, const DataInfo& dataInfo ) + : _promise( pipeFilter, dataInfo ) {} ~Impl() @@ -154,32 +37,39 @@ struct OutputPort::Impl void flush() { - _data.set( ConstPortDataPtr( )); + _promise.flush(); + } + + const std::type_index& getDataType() const + { + return _promise.getDataType(); } const std::string& getName() const { - return _info.name; + return _promise.getName(); } void reset() { - _data.reset(); + _promise.reset(); } - const PortInfo _info; - AsyncData _data; - PromisePtr _portPromise; + Promise _promise; }; -OutputPort::OutputPort( const PipeFilter& pipeFilter, const PortInfo& portInfo ) - : _impl( new OutputPort::Impl( pipeFilter, portInfo )) +OutputPort::OutputPort( const PipeFilter& pipeFilter, const DataInfo& dataInfo ) + : _impl( new OutputPort::Impl( pipeFilter, dataInfo )) {} OutputPort::~OutputPort() {} +OutputPort::OutputPort( OutputPort&& port ) + : _impl( std::move( port._impl )) +{} + const std::string& OutputPort::getName() const { return _impl->getName(); @@ -187,17 +77,17 @@ const std::string& OutputPort::getName() const const std::type_index& OutputPort::getDataType() const { - return _impl->_info.getDataType(); + return _impl->getDataType(); } -PromisePtr OutputPort::getPromise() const +Promise OutputPort::getPromise() const { - return _impl->_portPromise; + return _impl->_promise; } -void OutputPort::connect( InputPort& inputPort ) +void OutputPort::connect( InputPort& port ) { - inputPort.connect( *this ); + port.connect( *this ); } void OutputPort::reset() @@ -205,22 +95,4 @@ void OutputPort::reset() _impl->reset(); } -bool waitForAny( const Futures& futures ) -{ - if( futures.empty( )) - return false; - - ConstPortDataFutures boostFutures; - boostFutures.reserve( futures.size( )); - for( const auto& future: futures ) - boostFutures.push_back( future.getAsyncData()._impl->_future ); - - WriteLock lock( waitForAnyLock, boost::try_to_lock ); - if( !lock.owns_lock( )) - return true; - - boost::wait_for_any( boostFutures.begin(), boostFutures.end( )); - return true; -} - } diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h index d4970d12..3ee102b0 100644 --- a/livre/core/pipeline/OutputPort.h +++ b/livre/core/pipeline/OutputPort.h @@ -25,78 +25,21 @@ namespace livre { -/** - * The AsyncData class provides thread safe operations on data setting/retrieval/querying - * based on boost::shared_future ( boost::wait_for_any is not supported by std yet ). - */ -class AsyncData -{ -public: - - /** - * When connection is instantiated the data is not - * set yet, so any get() call will block the retrieval - * @param name of the connection - * @param dataType type of the data - */ - AsyncData( const std::string& name, - const std::type_index& dataType ); - - /** - * @return the name of the connection - */ - const std::string& getName() const; - - /** - * @param data sets the data - */ - void set( const ConstPortDataPtr& data ); - - /** - * @return the data. If data is not set it will block. - */ - const ConstPortDataPtr& get() const; - - /** - * @return true if data is set. - */ - bool isReady() const; - - /** - * Waits until data is set - */ - void wait() const; - - /** - * Resets the promise/future - */ - void reset(); - -private: - - /** - * Waits for any future to be ready. - * @param futures queried to be ready. - * @note this function needs internal access to the futures ( which is not exposed in the API ). - * @return true if any new futures are ready or futures included are not busy. - */ - friend bool waitForAny( const Futures& futures ); - - AsyncData( const AsyncData& ) = delete; - AsyncData& operator=( const AsyncData& ) = delete; - - struct Impl; - std::unique_ptr _impl; -}; - class OutputPort { public: - OutputPort( const PipeFilter& pipeFilter, const PortInfo& portInfo ); + /** + * @param dataInfo is the name and type information for the data. + * @param pipeFilter is the reference to the pipefilter class which instantiates the + * Promise. + */ + OutputPort( const PipeFilter& pipeFilter, + const DataInfo& dataInfo ); ~OutputPort(); + OutputPort( OutputPort&& port ); /** * @return name of the port */ @@ -110,13 +53,13 @@ class OutputPort /** * @return the promise, that data can be written to */ - PromisePtr getPromise() const; + Promise getPromise() const; /** * Connects an output port to input port - * @param inputPort input port + * @param port input port */ - void connect( InputPort& inputPort ); + void connect( InputPort& port ); /** * Resets the promise/future diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index 42ea6dbc..96f6b73d 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -23,48 +23,40 @@ #include #include #include -#include -#include -#include #include #include +#include namespace livre { struct PipeFilter::Impl { - typedef std::map< std::string, OutputPortPtr > OutputPortMap; - typedef std::map< std::string, InputPortPtr > InputPortMap; + typedef std::map< std::string, OutputPort > OutputPortMap; + typedef std::map< std::string, InputPort > InputPortMap; Impl( PipeFilter& pipeFilter, - const std::string& name, - FilterPtr filter ) + const std::string& name, + FilterPtr&& filter ) : _pipeFilter( pipeFilter ) , _name( name ) - , _id( servus::make_UUID( )) - , _filter( filter ) + , _filter( std::move( filter )) { - addPorts( filter->getInputPorts(), - filter->getOutputPorts( )); - } + for( const DataInfo& dataInfo: _filter->getInputDataInfos( )) + { + _inputMap.emplace( std::piecewise_construct, + std::forward_as_tuple( dataInfo.first ), + std::forward_as_tuple( dataInfo )); + } - Impl( PipeFilter& pipeFilter, - const std::string& name, - const FilterFunc& filterFunc, - const PortInfos& inputPorts, - const PortInfos& outputPorts ) - : _pipeFilter( pipeFilter ) - , _name( name ) - , _id( servus::make_UUID( )) - , _filter( new FunctionFilter( filterFunc, - inputPorts, - outputPorts )) - { - addPorts( inputPorts, outputPorts ); + for( const DataInfo& dataInfo: _filter->getOutputDataInfos( )) + { + _outputMap.emplace( std::piecewise_construct, + std::forward_as_tuple( dataInfo.first ), + std::forward_as_tuple( _pipeFilter, dataInfo )); + } } - bool hasInputPort( const std::string& portName ) const { return _inputMap.count( portName ) > 0; @@ -81,29 +73,17 @@ struct PipeFilter::Impl + portName )); } - void addPorts( const PortInfos& iPortInfos, const PortInfos& oPortInfos ) - { - for( const PortInfo& portInfo: iPortInfos ) - _inputMap[ portInfo.name ] = InputPortPtr( new InputPort( portInfo )); - - for( const PortInfo& portInfo: oPortInfos ) - _outputMap[ portInfo.name ] = OutputPortPtr( new OutputPort( _pipeFilter, portInfo )); - - // Connect notification ports - _inputMap[ _id.getString( )] = - InputPortPtr( new InputPort( makePortInfo< ConstPortDataPtr >( _id.getString( )))); - _outputMap[ _id.getString( )] = - OutputPortPtr( new OutputPort( _pipeFilter, - makePortInfo< ConstPortDataPtr >( _id.getString( )))); - } - void execute() { - InputPorts ports; - for( auto pair: _inputMap ) - ports.push_back( pair.second ); + Futures inputFutures; + for( const auto& pair: _inputMap ) + { + const Futures& futures = pair.second.getFutures(); + for( const auto& future: futures ) + inputFutures.push_back( future.rename( pair.second.getName( ))); + } - const InFutureMap futures( ports ); + const FutureMap futures( inputFutures ); PromiseMap promises( getOutputPromises( )); try @@ -118,38 +98,32 @@ struct PipeFilter::Impl } } - PromisePtr getInputPromise( const std::string& portName ) + Promise getInputPromise( const std::string& portName ) { - if( !hasInputPort( portName )) + if( !hasInputPort( portName )) throwPortError( portName ); - if( _readyPortsMap.count( portName ) > 0 ) - return _readyPortsMap[ portName ]->getPromise(); + if( _manuallySetPortsMap.count( portName ) > 0 ) + return _manuallySetPortsMap.find( portName )->second.getPromise(); - InputPortPtr& inputPort = _inputMap[ portName ]; - - if( inputPort->getSize() != 0 || // If there is another connection - inputPort->getName() == _id.getString( )) // If this is an notification port - { - LBTHROW( std::runtime_error( "The port is already connected or this is a" - "notification port" )); - } + InputPort& inputPort = _inputMap.find( portName )->second; - OutputPortPtr outputPort( new OutputPort( _pipeFilter, - makePortInfo( inputPort->getName(), - inputPort->getDataType( )))); - _readyPortsMap[ inputPort->getName() ] = outputPort; - inputPort->connect( *outputPort ); + _manuallySetPortsMap.emplace( std::piecewise_construct, + std::forward_as_tuple( inputPort.getName( )), + std::forward_as_tuple( _pipeFilter, + DataInfo( inputPort.getName(), + inputPort.getDataType( )))); + OutputPort& outputPort = _manuallySetPortsMap.find( inputPort.getName( ))->second; - return outputPort->getPromise(); + inputPort.connect( outputPort ); + return _manuallySetPortsMap.find( portName )->second.getPromise(); } Promises getOutputPromises() const { Promises promises; - promises.reserve( _outputMap.size( )); for( const auto& pair: _outputMap ) - promises.push_back( pair.second->getPromise( )); + promises.push_back( pair.second.getPromise( )); return promises; } @@ -159,7 +133,7 @@ struct PipeFilter::Impl Futures futures; for( const auto& pair: _outputMap ) { - const Future& outputFuture = pair.second->getPromise()->getFuture(); + const Future& outputFuture = pair.second.getPromise().getFuture(); futures.push_back( outputFuture ); } return futures; @@ -170,94 +144,76 @@ struct PipeFilter::Impl Futures futures; for( const auto& pair: _inputMap ) { - const Futures& inputFutures = pair.second->getFutures(); + const Futures& inputFutures = pair.second.getFutures(); futures.insert( futures.end(), inputFutures.begin(), inputFutures.end( )); } return futures; } void connect( const std::string& srcPortName, - PipeFilterPtr dst, + Impl& dstImpl, const std::string& dstPortName ) { if( !hasOutputPort( srcPortName )) throwPortError( srcPortName ); - if( !dst->_impl->hasInputPort( dstPortName )) + if( !dstImpl.hasInputPort( dstPortName )) throwPortError( dstPortName ); // The value on the output port may already be set - if( !dst->_impl->_readyPortsMap.count( dstPortName )) + if( !dstImpl._manuallySetPortsMap.count( dstPortName )) std::runtime_error( std::string( "The value on port: ") + dstPortName + "is already set" ); - _outputMap[ srcPortName ]->connect( *dst->_impl->_inputMap[ dstPortName ] ); - } - - void connect( PipeFilterPtr dst ) - { - OutputPortPtr outputPort = _outputMap[ _id.getString() ]; - InputPortPtr inputPort = dst->_impl->_inputMap[ dst->_impl->_id.getString() ]; - inputPort->connect( *outputPort ); + _outputMap.find( srcPortName )->second.connect( + dstImpl._inputMap.find( dstPortName )->second ); } void reset() { - for( auto& pair: _readyPortsMap ) - _inputMap[ pair.first ]->disconnect( *pair.second ); + for( auto& pair: _manuallySetPortsMap ) + _inputMap.find( pair.first )->second.disconnect( pair.second ); - _readyPortsMap.clear(); - for( const auto& pair: _outputMap ) - pair.second->reset(); + _manuallySetPortsMap.clear(); + for( auto& pair: _outputMap ) + pair.second.reset(); } PipeFilter& _pipeFilter; const std::string _name; - const servus::uint128_t _id; - FilterPtr _filter; + const FilterPtr _filter; InputPortMap _inputMap; OutputPortMap _outputMap; - OutputPortMap _readyPortsMap; + OutputPortMap _manuallySetPortsMap; }; PipeFilter::PipeFilter( const std::string& name, - FilterPtr filter ) - : _impl( new PipeFilter::Impl( *this, name, filter )) -{} - -PipeFilter::PipeFilter( const std::string& name, - const FilterFunc& func, - const PortInfos& inputPorts, - const PortInfos& outputPorts ) - : _impl( new PipeFilter::Impl( *this, - name, - func, - inputPorts, - outputPorts )) + FilterPtr&& filter ) + : _impl( new Impl( *this, name, std::move( filter ))) {} PipeFilter::~PipeFilter() {} -void PipeFilter::execute() +const std::string& PipeFilter::getName() const { - _impl->execute(); + return _impl->_name; } -const servus::uint128_t& PipeFilter::getId() const +Promise PipeFilter::getPromise( const std::string& portName ) { - return _impl->_id; + return _impl->getInputPromise( portName ); } -void PipeFilter::reset() +void PipeFilter::execute() { - _impl->reset(); + _impl->execute(); } -const std::string& PipeFilter::getName() const +Futures PipeFilter::getPostconditions() const { - return _impl->_name; + return _impl->getPostconditions(); } Futures PipeFilter::getPreconditions() const @@ -265,27 +221,17 @@ Futures PipeFilter::getPreconditions() const return _impl->getPreconditions(); } -Futures PipeFilter::getPostconditions() const -{ - return _impl->getPostconditions(); -} - - -PromisePtr PipeFilter::getPromise( const std::string& portName ) +void PipeFilter::reset() { - return _impl->getInputPromise( portName ); + _impl->reset(); } void PipeFilter::connect( const std::string& srcPortName, - PipeFilterPtr dst, + PipeFilter& dst, const std::string& dstPortName ) { - _impl->connect( srcPortName, dst, dstPortName ); + _impl->connect( srcPortName, *dst._impl, dstPortName ); } -void PipeFilter::connect( PipeFilterPtr dst ) -{ - _impl->connect( dst ); -} } diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index 16ccaf47..beb49d32 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -28,44 +28,14 @@ namespace livre /** * PipeFilter class instantiates the @Filter classes by constructing - * the communication layer around the filter. While adding the ports, - * it add its name as prefix to port name. i.e. if the name of the - * pipefilter is "Rescale" and output port name for the filter is "Volume" - * the port will be named as + * the communication layer around the filter. */ -class PipeFilter : public Executable +class PipeFilter : public Executable::ExecutableImpl { public: - /** - * Constructs a PipeFilter with a given filter - * @param name of the pipefilter - * @param filter the filter object - */ - PipeFilter( const std::string& name, - FilterPtr filter ); - - /** - * Constructs a PipeFilter with a given filter function - * @param name of the pipefilter - * @param func is the filter function object - * @param inputPorts input ports - * @param outputPorts output ports - */ - PipeFilter( const std::string& name, - const FilterFunc& func, - const PortInfos& inputPorts, - const PortInfos& outputPorts ); - ~PipeFilter(); - /** - * Executes the filter. If a filter input port is - * connected and no input is provided to the port - * the execution will block. - */ - void execute() final; - /** * @return the unique name of the filter. */ @@ -80,55 +50,72 @@ class PipeFilter : public Executable * @throws std::runtime_error if connection can not be established */ void connect( const std::string& srcPortName, - PipeFilterPtr dst, + PipeFilter& dst, const std::string& dstPortName ); /** - * Connect to given pipe filter for notification when source filter execution - * is complete. - * @param dst is the destination pipe filter. - * @return true if connection is successful. - * @throws std::runtime_error if connection can not be established or if the - * port already is set from outside. + * @return return promise for the given input port. If there is no connection to the + * input port, a new promise is created for the port and no further connections are allowed, + * if there is a connection getting a promise is not allowed. + * @throws std::runtime_error if there is already a connection or if there is + * no inputport or it is a noification port. */ - void connect( PipeFilterPtr dst ); + Promise getPromise( const std::string& portName ); /** - * @copydoc Executable::getOutFutures() + * @copydoc Executable::execute */ - Futures getPostconditions() const final; + void execute() final; /** - * @copydoc Executable::getInputFutures() - * @note PipeFilter guarantees that only connected input futures are returned. + * @copydoc Executable::getPostconditions */ - Futures getPreconditions() const final; + Futures getPostconditions() const final; /** - * @return return promise for the given input port. If there is no connection to the - * input port, a new promise is created for the port and no further connections are allowed, - * if there is a connection getting a promise is not allowed. - * @throws std::runtime_error if there is already a connection or if there is - * no inputport or it is a noification port. + * @copydoc Executable::getPreconditions */ - PromisePtr getPromise( const std::string& portName ); + Futures getPreconditions() const final; /** - * @return the unique id of the filter. + * @copydoc Executable::reset */ - const servus::uint128_t& getId() const; + void reset() final; + +protected: /** - * Resets the filter. At this point pipe filter execution should be complete. + * Constructs a PipeFilter with a given filter + * @param name of the pipefilter + * @param filter the filter object. */ - void reset(); + PipeFilter( const std::string& name, + FilterPtr&& filter ); private: - friend class Pipeline; - struct Impl; - std::unique_ptr _impl; + std::shared_ptr< Impl > _impl; +}; + +/** + * Creates a PipeFiter class instance with a given filter type + */ +template< class FilterT > +class PipeFilterT : public PipeFilter +{ +public: + + /** + * Constructs a PipeFilter with a given filter type FilterT + * @param name of the pipefilter + * @param args are the arguments for construction of FilterT + */ + template< class... Args > + PipeFilterT( const std::string& name, + Args&&... args ) + : PipeFilter( name, FilterPtr( new FilterT( args... ))) + {} }; } diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp index a81acb1c..927b00b1 100644 --- a/livre/core/pipeline/Pipeline.cpp +++ b/livre/core/pipeline/Pipeline.cpp @@ -18,74 +18,35 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include #include #include -#include -#include -#include namespace livre { struct Pipeline::Impl { - typedef std::map< std::string, ConstPipelinePtr > PipelineMap; - typedef std::map< std::string, ConstPipeFilterPtr > PipeFilterMap; - typedef std::map< std::string, ExecutablePtr > ExecutableMap; + typedef std::map< std::string, const Pipeline > PipelineMap; + typedef std::map< std::string, const PipeFilter > PipeFilterMap; + typedef std::map< std::string, Executable > ExecutableMap; Impl( Pipeline& pipeline ) : _pipeline( pipeline ) {} - PipeFilterPtr add( const std::string& name, - const FilterFunc& filterFunc, - const PortInfos& inputPorts, - const PortInfos& outputPorts, - bool wait ) -{ - FilterPtr filter( new FunctionFilter( filterFunc, - inputPorts, - outputPorts )); - return add( name, filter, wait ); - } - - PipeFilterPtr add( const std::string& name, - const FilterPtr& filter, - bool wait ) - { - if( _executableMap.count( name ) > 0 ) - LBTHROW( std::runtime_error( name + " already exists")); - - PipeFilterPtr pipefilter( new PipeFilter( name, filter )); - _executableMap[ name ] = pipefilter; - - if( wait ) - { - const OutFutureMap portFutures( pipefilter->getPostconditions( )); - _waitFutures.push_back( portFutures.getFuture( pipefilter->getId().getString( ))); - } - - return pipefilter; - } - void add( const std::string& name, - const PipelinePtr& pipeline, + const Executable& executable, bool wait ) { - if( pipeline.get() == &_pipeline ) - return; - if( _executableMap.count( name ) > 0 ) LBTHROW( std::runtime_error( name + " already exists")); - _executableMap[ name ] = pipeline; + _executableMap.insert({ name, executable }); if( wait ) { - const Futures& futures = pipeline->getPostconditions(); - _waitFutures.insert( _waitFutures.end(), futures.begin(), futures.end( )); + const Futures& futures = executable.getPostconditions(); + _outFutures.insert( _outFutures.end(), futures.begin(), futures.end( )); } } @@ -93,13 +54,13 @@ struct Pipeline::Impl { Executables executables = getExecutables(); Executables::iterator it = executables.begin(); - while( !executables.empty()) + while( !executables.empty( )) { - ExecutablePtr executable = *it; - const FutureMap futureMap( executable->getPreconditions( )); + Executable& executable = *it; + const FutureMap futureMap( executable.getPreconditions( )); if( futureMap.isReady( )) { - executable->execute(); + executable.execute(); executables.erase( it ); it = executables.begin(); } @@ -122,88 +83,85 @@ struct Pipeline::Impl return executables; } - Futures getConnectedInFutureMap() const + const Executable& getExecutable( const std::string& name ) const { - return Futures(); + if( _executableMap.count( name ) == 0 ) + LBTHROW( std::runtime_error( name + " executable does not exist")); + + return _executableMap.find( name )->second; } - Futures getOutFutures() const + Futures getPreconditions() const { - return _waitFutures; + Futures inFutures; + for( auto pair: _executableMap ) + { + const Futures& futures = pair.second.getPreconditions(); + inFutures.insert( inFutures.end(), futures.begin(), futures.end( )); + } + return inFutures; } - void reset() + Futures getPostconditions() const { - for( auto pair: _executableMap ) - pair.second->reset(); + return _outFutures; } - ~Impl() - {} + void reset() + { + for( auto& pair: _executableMap ) + pair.second.reset(); + } Pipeline& _pipeline; ExecutableMap _executableMap; - Futures _waitFutures; + Futures _outFutures; }; Pipeline::Pipeline() - : _impl( new Pipeline::Impl( *this )) + : _impl( new Impl( *this )) { } Pipeline::~Pipeline() {} -void Pipeline::add( const std::string& name, - const PipelinePtr& pipeline, - bool wait ) +void Pipeline::_add( const std::string& name, + const Executable& executable, + bool wait ) { - return _impl->add( name, pipeline, wait ); + _impl->add( name, executable, wait ); } -PipeFilterPtr Pipeline::add( const std::string& name, - const FilterPtr& filter, - bool wait ) +Executables Pipeline::getExecutables() const { - return _impl->add( name, filter, wait ); + return _impl->getExecutables(); } -PipeFilterPtr Pipeline::add( const std::string& name, - const FilterFunc& filterFunc, - const PortInfos& inputPorts, - const PortInfos& outputPorts, - bool wait ) +const Executable& Pipeline::getExecutable( const std::string& name ) const { - return _impl->add( name, - filterFunc, - inputPorts, - outputPorts, - wait ); + return _impl->getExecutable( name ); } -Executables Pipeline::getExecutables() const -{ - return _impl->getExecutables(); -} void Pipeline::execute() { - return _impl->execute(); + _impl->execute(); } -void Pipeline::reset() +Futures Pipeline::getPostconditions() const { - _impl->reset(); + return _impl->getPostconditions(); } Futures Pipeline::getPreconditions() const { - return _impl->getConnectedInFutureMap(); + return _impl->getPreconditions(); } -Futures Pipeline::getPostconditions() const +void Pipeline::reset() { - return _impl->getOutFutures(); + _impl->reset(); } } diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index aab0c985..d499cc5e 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -21,7 +21,7 @@ #define _Pipeline_h_ #include -#include +#include #include namespace livre @@ -31,9 +31,9 @@ namespace livre * Pipeline represents a filter graph. On asynchronous * execution through the Executor, the status of the * execution can be queried whether the execution is - * complete or not. + * complete or not through the post conditions. */ -class Pipeline : public Executable +class Pipeline : public Executable::ExecutableImpl { public: @@ -48,38 +48,35 @@ class Pipeline : public Executable * can wait on given pipeline. */ void add( const std::string& name, - const PipelinePtr& pipeline, - bool wait = true ); + const Pipeline& pipeline, + bool wait = true ) + { + _add( name, + Executable( pipeline ), + wait ); + } /** - * Creates and adds a pipefilter around a filter to be executed. The - * notification of completion of execution is connected to the pipeline - * if user wants to wait on execution of whole pipeline. - * @param filter is added to list of executables. + * Creates and adds a pipefilter ( given the FilterT type of filter ) + * @param FilterT is the type of filter to be added to list of executables. + * @name name the name of the filter instance. + * @param args for the FilterT construction * @param wait If true, on asynchronous execution, pipeline * can wait on the added filter. * @return returns the generated pipe filter. + * @throws std::runtime_error if an executable with same name is present */ - PipeFilterPtr add( const std::string& name, - const FilterPtr& filter, - bool wait = true ); - /** - * Adds a filter function to be executed. The - * notification of completion of execution is connected to the pipeline - * if user wants to wait on execution of whole pipeline. - * @param filterFunc is the filter function object. - * @param inputPorts are the input ports information. - * @param outputPorts are the output ports information. - * @param wait If true, on asynchronous execution, pipeline - * can wait on the added filter function. - * @return returns the generated pipe filter. - */ - PipeFilterPtr add( const std::string& name, - const FilterFunc& filterFunc, - const PortInfos& inputPorts, - const PortInfos& outputPorts, - bool wait = true ); + template< class FilterT, class... Args, bool wait = true > + PipeFilter add( const std::string& name, + Args&&... args ) + { + PipeFilterT< FilterT > pipeFilter( name, args... ); + _add( name, + Executable( pipeFilter ), + wait ); + return pipeFilter; + } /** * @return the list of all executables ( pipe filters and @@ -88,30 +85,42 @@ class Pipeline : public Executable Executables getExecutables() const; /** - * Executes each executable element in the graph - * synchronously. + * @param name of the executable + * @return the executable + * @throws std::runtime_error if a pipe filter or pipeline does not exist */ - void execute() final; + const Executable& getExecutable( const std::string& name ) const; /** - * Resets the pipeline. At this point pipeline execution should be complete. + * @copydoc Executable::execute */ - void reset() final; + void execute() final; -private: + /** + * @copydoc Executable::getPostconditions + */ + Futures getPostconditions() const final; /** - * @return Returns the writable future + * @copydoc Executable::getPreconditions */ Futures getPreconditions() const final; /** - * @return Returns the writable future + * @copydoc Executable::reset */ - Futures getPostconditions() const final; + void reset() final; + +private: + + void _add( const std::string& name, + const Executable& filter, + bool wait ); +private: struct Impl; - std::unique_ptr _impl; + std::shared_ptr< Impl > _impl; + }; } diff --git a/livre/core/pipeline/PortData.h b/livre/core/pipeline/PortData.h index 7b634819..996596c0 100644 --- a/livre/core/pipeline/PortData.h +++ b/livre/core/pipeline/PortData.h @@ -22,8 +22,6 @@ #include -#include "PortType.h" - namespace livre { @@ -31,11 +29,14 @@ namespace livre * PortData class is base class for keeping the track for types * by using the std::type_index. */ -class PortData : public PortType +class PortData { +public: + const std::type_index dataType; + protected: - explicit PortData( const std::type_index& dataType ) - : PortType( dataType) {} + explicit PortData( const std::type_index& dataType_ ) + : dataType( dataType_ ) {} virtual ~PortData() {} }; @@ -46,12 +47,12 @@ template< class T> struct PortDataT final : public PortData { explicit PortDataT( const T& data_ ) - : PortData( std::type_index( typeid( T ))) + : PortData( getType< T >()) , data( data_ ) {} explicit PortDataT( const T&& data_ ) - : PortData( std::type_index( typeid( T ))) + : PortData( getType< T >( )) , data( std::move( data_ )) {} @@ -62,31 +63,6 @@ struct PortDataT final : public PortData PortDataT< T >& operator=( const PortDataT< T >& ) = delete; }; -template -using PortDataTPtr = boost::shared_ptr< PortDataT< T >>; - -template -using ConstPortDataTPtr = boost::shared_ptr< PortDataT< T >>; - -/** - * Constructs a PortDataTPtr object from type T - */ -template< class T > -inline PortDataTPtr< T > makePortDataPtr( const T& data ) -{ - return boost::make_shared< PortDataT< T >>( data ); -} - -/** - * Constructs a PortDataTPtr object from type T. - * Moves the to the port data. - */ -template< class T > -inline PortDataTPtr< T > makePortDataPtr( const T&& data ) -{ - return boost::make_shared< PortDataT< T >>( data ); -} - } #endif // _PortData_h_ diff --git a/livre/core/pipeline/PortInfo.h b/livre/core/pipeline/PortInfo.h deleted file mode 100644 index d19489fb..00000000 --- a/livre/core/pipeline/PortInfo.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _PortInfo_h_ -#define _PortInfo_h_ - -#include - -#include - -namespace livre -{ - -/** - * PortInfo holds the port information ( name, data type ) - */ -struct PortInfo final : public PortType -{ - PortInfo( const std::string& name_, - const std::type_index& dataType ) - : PortType( dataType ) - , name( name_ ) - {} - - const std::string name; -}; - -/** - * Helper function to create port info. - * @param name is the port name with a type - */ -template< class T > -inline PortInfo makePortInfo( const std::string& name ) -{ - return PortInfo( name, std::type_index( typeid( T ))); -} - -/** - * Helper function to create port info with a known type. - * @param name is the port name - * @param dataType data type for the port - */ -inline PortInfo makePortInfo( const std::string& name, - const std::type_index& dataType ) -{ - return PortInfo( name, dataType ); -} - -/** - * Helper function to add port info to the list of port infos. - * @param portInfos is the list of port infos. - * @param portName is the port name - */ -template< class T > -inline void addPortInfo( PortInfos& portInfos, - const std::string& portname ) -{ - portInfos.push_back( makePortInfo< T >( portname )); -} - - -} - -#endif // _PortInfo_h_ - diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp index e1208a28..77ba4642 100644 --- a/livre/core/pipeline/Promise.cpp +++ b/livre/core/pipeline/Promise.cpp @@ -19,16 +19,17 @@ #include #include -#include +#include namespace livre { struct Promise::Impl { - Impl( const PipeFilter& pipeFilter, AsyncData& data ) + Impl( const PipeFilter& pipeFilter, + const DataInfo& dataInfo ) : _pipeFilter( pipeFilter ) - , _data( data ) + , _data( dataInfo ) , _future( _pipeFilter, _data ) {} @@ -37,29 +38,44 @@ struct Promise::Impl return _data.getName(); } - void set( const ConstPortDataPtr& data ) + const std::type_index& getDataType() const + { + return _data.getDataType(); + } + + void set( const PortDataPtr& data ) { _data.set( data ); } + void reset() + { + _data.reset(); + } + void flush() { - _data.set( ConstPortDataPtr( )); + _data.set( PortDataPtr( )); } const PipeFilter& _pipeFilter; - AsyncData& _data; + AsyncData _data; const Future _future; }; Promise::Promise( const PipeFilter& pipeFilter, - AsyncData& data ) - : _impl( new Promise::Impl( pipeFilter, data )) + const DataInfo& dataInfo ) + : _impl( new Promise::Impl( pipeFilter, dataInfo )) {} Promise::~Promise() {} +const std::type_index& Promise::getDataType() const +{ + return _impl->getDataType(); +} + const std::string& Promise::getName() const { return _impl->getName(); @@ -75,7 +91,12 @@ const Future& Promise::getFuture() const return _impl->_future; } -void Promise::_set( const ConstPortDataPtr& data ) +void Promise::reset() +{ + _impl->reset(); +} + +void Promise::_set( const PortDataPtr& data ) { _impl->set( data ); } diff --git a/livre/core/pipeline/Promise.h b/livre/core/pipeline/Promise.h index a93dc882..2083c5d6 100644 --- a/livre/core/pipeline/Promise.h +++ b/livre/core/pipeline/Promise.h @@ -21,18 +21,38 @@ #define _Promise_h_ #include +#include #include namespace livre { + +/** + * The Promise class is similar to the std::promise classes in functionality and it has additional + * information for the name and data type. It provides methods to set the data. + */ class Promise { public: - Promise( const PipeFilter& pipeFilter, AsyncData& data ); + /** + * @param pipeFilter is the reference to the pipefilter class which instantiates the + * Promise. + * @param dataInfo is the name and type information for the data. + */ + Promise( const PipeFilter& pipeFilter, + const DataInfo& dataInfo ); ~Promise(); + /** + * @return the name of the connection + */ + const std::type_index& getDataType() const; + + /** + * @return the name of the connection + */ const std::string& getName() const; /** @@ -44,7 +64,7 @@ class Promise template< class T > void set( const T& value ) { - _set( makePortDataPtr( value )); + _set( std::make_shared< PortDataT< T >>( value )); } /** @@ -56,7 +76,7 @@ class Promise template< class T > void set( const T&& value ) { - _set( makePortDataPtr( value )); + _set( std::make_shared< PortDataT< T >>( value )); } /** @@ -69,12 +89,19 @@ class Promise */ const Future& getFuture() const; + /** + * @resets the promise. ( Future is reset and value can be set again ) + * The behavior of the function is undefined when multiple threads + * execute query/get from future. + */ + void reset(); + private: - void _set( const ConstPortDataPtr& data ); + void _set( const PortDataPtr& data ); struct Impl; - std::unique_ptr _impl; + std::shared_ptr _impl; }; } diff --git a/livre/core/pipeline/PromiseMap.cpp b/livre/core/pipeline/PromiseMap.cpp index 0dfb083b..ce0b5928 100644 --- a/livre/core/pipeline/PromiseMap.cpp +++ b/livre/core/pipeline/PromiseMap.cpp @@ -18,54 +18,53 @@ */ #include -#include #include namespace livre { -typedef std::pair< std::string, PromisePtr > NamePromisePair; -typedef std::map< std::string, PromisePtr > NamePromiseMap; +typedef std::map< std::string, Promise > NamePromiseMap; +typedef NamePromiseMap::value_type NamePromisePair; struct PromiseMap::Impl { Impl( const Promises& promises ) { - for( const PromisePtr& promise: promises ) - _promiseMap[ promise->getName( )] = promise; + for( const auto& promise: promises ) + _promiseMap.insert({ promise.getName(), promise }); } - void throwPortError( const std::string& portName ) const + void throwError( const std::string& name ) const { std::stringstream err; - err << "Unknown port: " << portName << std::endl; + err << "Unknown promise name: " << name << std::endl; LBTHROW( std::runtime_error( err.str( ))); } - bool hasPort( const std::string& portName ) const + bool hasPromise( const std::string& name ) const { - return _promiseMap.count( portName ) > 0; + return _promiseMap.count( name ) > 0; } - void flush( const std::string& portName ) + void flush( const std::string& name ) const { - if( portName != ALL_PORTS && !hasPort( portName )) - throwPortError( portName ); + if( name != ALL_PROMISES && !hasPromise( name )) + throwError( name ); - for( const auto& pair: _promiseMap ) + for( const NamePromisePair& pair: _promiseMap ) { - const PromisePtr& promise = pair.second; - if( portName == ALL_PORTS || promise->getName() == portName ) - promise->flush(); + Promise promise = pair.second; + if( name == ALL_PROMISES || promise.getName() == name ) + promise.flush(); } } - PromisePtr getPromise( const std::string& portName ) + Promise getPromise( const std::string& name ) const { - if( !hasPort( portName )) - throwPortError( portName ); + if( !hasPromise( name )) + throwError( name ); - return _promiseMap[ portName ]; + return _promiseMap.find( name )->second; } NamePromiseMap _promiseMap; @@ -78,14 +77,14 @@ PromiseMap::PromiseMap( const Promises& promises ) PromiseMap::~PromiseMap() {} -void PromiseMap::flush( const std::string& portName /* = ALL_PORTS */ ) +void PromiseMap::flush( const std::string& name /* = ALL_PROMISES */ ) const { - _impl->flush( portName ); + _impl->flush( name ); } -PromisePtr PromiseMap::getPromise( const std::string& portName ) +Promise PromiseMap::getPromise( const std::string& name ) const { - return _impl->getPromise( portName ); + return _impl->getPromise( name ); } } diff --git a/livre/core/pipeline/PromiseMap.h b/livre/core/pipeline/PromiseMap.h index a1af0810..85310e7b 100644 --- a/livre/core/pipeline/PromiseMap.h +++ b/livre/core/pipeline/PromiseMap.h @@ -20,8 +20,8 @@ #ifndef _PromiseMap_h_ #define _PromiseMap_h_ -#include #include +#include namespace livre { @@ -45,44 +45,44 @@ class PromiseMap ~PromiseMap(); /** - * @param portName is the port name. + * @param name of the promise * @return the promise related to the port name. */ - PromisePtr getPromise( const std::string& portName ); + Promise getPromise( const std::string& name ) const; /** * Sets the port with the value. - * @param portName is the port name. + * @param name of the promise * @param value to be set * @throw std::runtime_error when the port data is not exact * type T or there is no such port name. */ template< class T > - void set( const std::string& portName, const T& value ) + void set( const std::string& name, const T& value ) const { - getPromise( portName )->set( value ); + getPromise( name ).set( value ); } /** * Sets the port with the value. - * @param portName is the port name. + * @param name of the promise * @param value to be set * @throw std::runtime_error when the port data is not exact * type T or there is no such port name. */ template< class T > - void set( const std::string& portName, const T&& value ) + void set( const std::string& name, const T&& value ) const { - getPromise( portName )->set( value ); + getPromise( name ).set( value ); } /** * Writes empty values to promises which are not set already. - * @param portName is the port name. If ALL_PORTS is given, + * @param name of the promise. If ALL_PROMISES is given, * all promises will be flushed * @throw std::runtime_error there is no such port name. */ - void flush( const std::string& portName = ALL_PORTS ); + void flush( const std::string& name = ALL_PROMISES ) const; private: diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp index 661098bc..023279ce 100644 --- a/livre/core/pipeline/SimpleExecutor.cpp +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -64,9 +64,9 @@ struct SimpleExecutor::Impl do { futures.clear(); - for( const ExecutablePtr& executable: executables ) + for( const Executable& executable: executables ) { - const Futures& inputFutures = executable->getPreconditions(); + const Futures& inputFutures = executable.getPreconditions(); for( const Future& future: inputFutures ) { if( !future.isReady( )) @@ -77,8 +77,8 @@ struct SimpleExecutor::Impl Executables::iterator it = executables.begin(); while( it != executables.end( )) { - ExecutablePtr executable = *it; - const FutureMap futureMap( executable->getPreconditions( )); + Executable& executable = *it; + const FutureMap futureMap( executable.getPreconditions( )); if( futureMap.isReady( )) { _workers.execute( executable ); @@ -113,9 +113,7 @@ SimpleExecutor::SimpleExecutor( const size_t threadCount ) } SimpleExecutor::~SimpleExecutor( ) -{ - -} +{} void SimpleExecutor::clear() { diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h index 6413675d..26fa1762 100644 --- a/livre/core/pipeline/SimpleExecutor.h +++ b/livre/core/pipeline/SimpleExecutor.h @@ -20,21 +20,25 @@ #ifndef _SimpleExecutor_h_ #define _SimpleExecutor_h_ -#include #include +#include namespace livre { /** * SimpleExecutor class provides a very basic implementation - * for the @see Executor class. The submitted executables are - * pushed to the worker threads without any real scheduling. - * The pipeline submission is thread safe. + * for the @see Executor class. It has a thread pool for + * executing multiple executables asynchronously. + * + * The submitted executables are queued for the worker threads. + * without any real scheduling.The pipeline submission is + * thread safe. * - * The scheduler implemented in this class, just pushes the - * executables without re-ordering. This may mean that if - * all workers are blocked, the processing can suspend. + * The scheduler implemented in this class, pushes the + * executables without re-ordering. The executable whose + * preconditions are satisfied is marked for execution + * in the thread pool. * * SimpleExecutor executes executables in a push based flow. */ diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp index 6d760a98..66aa6db2 100644 --- a/livre/core/pipeline/Workers.cpp +++ b/livre/core/pipeline/Workers.cpp @@ -18,9 +18,6 @@ */ #include -#include -#include -#include #include #include @@ -35,8 +32,8 @@ struct Workers::Impl Impl( Workers& workers, - size_t nThreads, - GLContextPtr glContext ) + const size_t nThreads, + const GLContextPtr& glContext ) : _workers( workers ) , _glContext( glContext ) { @@ -46,6 +43,16 @@ struct Workers::Impl } + struct Work + { + Work( const Executable& executable_ ) + : executable( executable_ ) + {} + Executable executable; + }; + + typedef std::shared_ptr< Work > WorkPtr; + void execute() { if( _glContext ) @@ -57,24 +64,25 @@ struct Workers::Impl while( true ) { - ExecutablePtr executable = _workQueue.pop(); - if( !executable ) + WorkPtr work = _workQueue.pop(); + if( !work ) break; - executable->execute(); + work->executable.execute(); } } ~Impl() { for( size_t i = 0; i < getSize(); ++i ) - _workQueue.push( ExecutablePtr()); + _workQueue.push( WorkPtr()); _threadGroup.join_all(); } - void submitWork( ExecutablePtr executable ) + + void submitWork( const Executable& executable ) { - _workQueue.push( executable ); + _workQueue.push( WorkPtr( new Work( executable ))); } size_t getSize() const @@ -82,19 +90,13 @@ struct Workers::Impl return _threadGroup.size(); } - struct Work - { - - - }; - Workers& _workers; - lunchbox::MTQueue< ExecutablePtr > _workQueue; + lunchbox::MTQueue< WorkPtr > _workQueue; boost::thread_group _threadGroup; - GLContextPtr _glContext; + const GLContextPtr _glContext; }; -Workers::Workers( size_t nThreads, +Workers::Workers( const size_t nThreads, GLContextPtr glContext ) : _impl( new Workers::Impl( *this, nThreads, @@ -104,7 +106,7 @@ Workers::Workers( size_t nThreads, Workers::~Workers() {} -void Workers::execute( ExecutablePtr executable ) +void Workers::execute( const Executable& executable ) { _impl->submitWork( executable ); } diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index 89cdff90..ec173d55 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -48,7 +48,7 @@ class Workers * threads. * @param executable is executed by thread pool. */ - void execute( ExecutablePtr executable ); + void execute( const Executable& executable ); /** * @return the size of thread pool. diff --git a/livre/core/types.h b/livre/core/types.h index 59d31546..f6d89346 100644 --- a/livre/core/types.h +++ b/livre/core/types.h @@ -45,6 +45,9 @@ #include #include +#include +#include + namespace livre { @@ -82,6 +85,27 @@ class DataSource; class DataSourcePlugin; class DataSourcePluginData; +/** + * Pipeline + */ +class AsyncData; +class Executor; +class Executable; +class Filter; +class Future; +class FutureMap; +class FutureMap; +class InputPort; +class PortData; +class Promise; +class PromiseMap; +class OutputPort; +class OutFutures; +class UniqueFutureMap; +class Pipeline; +class PipeFilter; +class Workers; + struct FrameInfo; struct TextureState; struct VolumeInformation; @@ -116,6 +140,9 @@ typedef std::shared_ptr< CacheObject > CacheObjectPtr; typedef std::shared_ptr< const CacheObject > ConstCacheObjectPtr; typedef std::shared_ptr< CacheObject > CacheObjectPtr; typedef std::shared_ptr< const CacheObject > ConstCacheObjectPtr; +typedef std::shared_ptr< PortData > PortDataPtr; + +typedef std::unique_ptr< Filter > FilterPtr; /** * Helper classes for shared_ptr objects @@ -160,11 +187,18 @@ typedef std::vector< NodeId > NodeIds; typedef std::vector< CacheId > CacheIds; /** - * Vector definitions for complex types + * Vector/list definitions for complex types */ typedef std::vector< CacheObjectPtr > CacheObjects; typedef std::vector< ConstCacheObjectPtr > ConstCacheObjects; +typedef std::list< Executable > Executables; +typedef std::list< Future > Futures; +typedef std::list< Promise > Promises; + +template < class T > +using ResultsT = std::vector< T >; + /** * Map definitions */ @@ -174,6 +208,16 @@ typedef std::unordered_map< uint32_t, bool > BoolMap; typedef std::unordered_map< uint32_t, EventHandlerPtr > EventHandlerMap; typedef std::unordered_map< uint32_t, DashConnectionPtr > DashConnectionMap; +template < class T > +inline std::type_index getType() +{ + typedef typename std::remove_const::type UnconstT; + return std::type_index( typeid( UnconstT )); +} + +typedef std::map< std::string, std::type_index > DataInfos; +typedef DataInfos::value_type DataInfo; + /** * Set definitions */ @@ -222,6 +266,8 @@ typedef std::map< std::string, // Const definitions static const std::string HIDDEN_PROGRAMDESCRIPTION_STR("_HIDDEN_"); static const std::string NO_PREFIX = ""; +static const std::string ALL_FUTURES = ""; +static const std::string ALL_PROMISES = ""; } diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index 71338775..52ccbdac 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -57,9 +57,8 @@ struct OutputData class TestFilter : public livre::Filter { - void execute( const livre::InFutureMap& input, livre::PromiseMap& output ) const final + void execute( const livre::FutureMap& input, livre::PromiseMap& output ) const final { - const livre::ResultsT< InputData >& results = input.get< InputData >( "TestInputData" ); OutputData outputData; @@ -70,27 +69,28 @@ class TestFilter : public livre::Filter } output.set( "TestOutputData", outputData ); - } - livre::PortInfos getInputPorts() const final + livre::DataInfos getInputDataInfos() const final { - livre::PortInfos inputPorts; - livre::addPortInfo< InputData >( inputPorts, "TestInputData" ); - return inputPorts; + return + { + { "TestInputData", livre::getType< InputData >( )} + }; } - livre::PortInfos getOutputPorts() const final + livre::DataInfos getOutputDataInfos() const final { - livre::PortInfos outputPorts; - livre::addPortInfo< OutputData >( outputPorts, "TestOutputData"); - return outputPorts; + return + { + { "TestOutputData", livre::getType< OutputData >( )} + }; } }; class ConvertFilter : public livre::Filter { - void execute( const livre::InFutureMap& input, livre::PromiseMap& output ) const final + void execute( const livre::FutureMap& input, livre::PromiseMap& output ) const final { const livre::ResultsT< OutputData >& results = input.get< OutputData >( "ConvertInputData" ); @@ -103,18 +103,21 @@ class ConvertFilter : public livre::Filter output.set( "ConvertOutputData", inputData ); } - livre::PortInfos getInputPorts() const final + livre::DataInfos getInputDataInfos() const final { - livre::PortInfos outputPorts; - livre::addPortInfo< OutputData >( outputPorts, "ConvertInputData"); - return outputPorts; + return + { + { "ConvertInputData", livre::getType< OutputData >( )} + }; + } - livre::PortInfos getOutputPorts() const final + livre::DataInfos getOutputDataInfos() const final { - livre::PortInfos inputPorts; - livre::addPortInfo< InputData >( inputPorts, "ConvertOutputData" ); - return inputPorts; + return + { + { "ConvertOutputData", livre::getType< InputData >( )} + }; } }; @@ -122,12 +125,11 @@ bool check_error( const std::runtime_error& ) { return true; } BOOST_AUTO_TEST_CASE( testFilterNoInput ) { - livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); + livre::PipeFilterT< TestFilter > pipeFilter( "Producer" ); // Execute will fail because there are no inputs where data is retrieved - BOOST_CHECK_EXCEPTION( pipeFilter->execute(), std::runtime_error, check_error ); - const livre::OutFutureMap portFutures( pipeFilter->getPostconditions( )); + BOOST_CHECK_EXCEPTION( pipeFilter.execute(), std::runtime_error, check_error ); + const livre::UniqueFutureMap portFutures( pipeFilter.getPostconditions( )); // Results of the filter will be empty. BOOST_CHECK_EXCEPTION( portFutures.get< OutputData >( "TestOutputData" ), @@ -136,13 +138,13 @@ BOOST_AUTO_TEST_CASE( testFilterNoInput ) BOOST_AUTO_TEST_CASE( testFilterWithInput ) { - livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); + livre::PipeFilterT< TestFilter > pipeFilter( "Producer" ); const uint32_t inputValue = 90; - pipeFilter->getPromise( "TestInputData" )->set( InputData( inputValue )); - pipeFilter->execute(); - const livre::OutFutureMap portFutures( pipeFilter->getPostconditions( )); + pipeFilter.getPromise( "TestInputData" ).set( InputData( inputValue )); + pipeFilter.execute(); + + const livre::UniqueFutureMap portFutures( pipeFilter.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 151 ); @@ -150,25 +152,24 @@ BOOST_AUTO_TEST_CASE( testFilterWithInput ) BOOST_AUTO_TEST_CASE( testSetAndGetWrongParameters ) { - livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter( new livre::PipeFilter( "Producer", filter )); - pipeFilter->getPromise( "TestInputData" )->set( InputData()); + TestFilter filter; + livre::PipeFilterT< TestFilter > pipeFilter( "Producer" ); + pipeFilter.getPromise( "TestInputData" ).set( InputData()); - BOOST_CHECK_EXCEPTION( pipeFilter->getPromise( "InputData" )->set( OutputData( 0 )), + BOOST_CHECK_EXCEPTION( pipeFilter.getPromise( "InputData" ).set( OutputData( 0 )), std::runtime_error, check_error ); - pipeFilter->execute(); - const livre::OutFutureMap portFutures( pipeFilter->getPostconditions()); + pipeFilter.execute(); + const livre::UniqueFutureMap portFutures( pipeFilter.getPostconditions()); BOOST_CHECK_EXCEPTION( portFutures.get( "TestOutputData" ), std::runtime_error, check_error ); } BOOST_AUTO_TEST_CASE( testInvalidConnection ) { - livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeFilter1( new livre::PipeFilter( "Producer", filter )); - livre::PipeFilterPtr pipeFilter2( new livre::PipeFilter( "Consumer", filter )); + livre::PipeFilterT< TestFilter > pipeFilter1( "Producer" ); + livre::PipeFilterT< TestFilter > pipeFilter2( "Consumer" ); - BOOST_CHECK_EXCEPTION( pipeFilter1->connect( "TestOutputData", + BOOST_CHECK_EXCEPTION( pipeFilter1.connect( "TestOutputData", pipeFilter2, "Helloworld" ), std::runtime_error, check_error ); @@ -176,72 +177,56 @@ BOOST_AUTO_TEST_CASE( testInvalidConnection ) BOOST_AUTO_TEST_CASE( testConnection ) { - livre::FilterPtr filter( new TestFilter( )); - livre::PipeFilterPtr pipeInput( new livre::PipeFilter( "Producer", filter ) ); - livre::PipeFilterPtr pipeOutput( new livre::PipeFilter( "Consumer", filter ) ); + livre::PipeFilterT< TestFilter > pipeInput( "Producer" ); + livre::PipeFilterT< TestFilter > pipeOutput( "Consumer" ); - livre::FilterPtr convertFilter( new ConvertFilter( )); - livre::PipeFilterPtr convertPipeFilter( new livre::PipeFilter( "Converter", convertFilter ) ); + livre::PipeFilterT< ConvertFilter > convertPipeFilter( "Converter" ); - pipeInput->connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); - convertPipeFilter->connect( "ConvertOutputData", pipeOutput, "TestInputData" ); + pipeInput.connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); + convertPipeFilter.connect( "ConvertOutputData", pipeOutput, "TestInputData" ); const uint32_t inputValue = 90; - pipeInput->getPromise( "TestInputData" )->set( InputData( inputValue )); - pipeInput->execute(); - convertPipeFilter->execute(); - pipeOutput->execute(); + pipeInput.getPromise( "TestInputData" ).set( InputData( inputValue )); + pipeInput.execute(); + convertPipeFilter.execute(); + pipeOutput.execute(); - const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } -livre::PipelinePtr createPipeline( livre::PipeFilterPtr& pipeInput, - livre::PipeFilterPtr& pipeOutput, - uint32_t inputValue, - size_t nConvertFilter = 1 ) +livre::Pipeline createPipeline( const uint32_t inputValue, + size_t nConvertFilter = 1 ) { - livre::FilterPtr filter( new TestFilter( )); - livre::PipelinePtr pipeline( new livre::Pipeline( )); - pipeInput = pipeline->add( "Producer", filter ); - pipeOutput = pipeline->add( "Consumer", filter ); + livre::Pipeline pipeline; + livre::PipeFilter pipeInput = pipeline.add< TestFilter >( "Producer" ); + livre::PipeFilter pipeOutput = pipeline.add< TestFilter >( "Consumer" ); - livre::FilterPtr convertFilter( new ConvertFilter( )); for( size_t i = 0; i < nConvertFilter; ++i ) { std::stringstream name; name << "Converter" << i; - livre::PipeFilterPtr convertPipeFilter = pipeline->add( name.str(), convertFilter ); - pipeInput->connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); - convertPipeFilter->connect( "ConvertOutputData", pipeOutput, "TestInputData" ); + livre::PipeFilter convertPipeFilter = + pipeline.add< ConvertFilter >( name.str( )); + pipeInput.connect( "TestOutputData", convertPipeFilter, "ConvertInputData" ); + convertPipeFilter.connect( "ConvertOutputData", pipeOutput, "TestInputData" ); } - pipeInput->getPromise( "TestInputData" )->set( InputData( inputValue )); + pipeInput.getPromise( "TestInputData" ).set( InputData( inputValue )); return pipeline; } -livre::ExecutorPtr createExecutor(const size_t nbOfWorkerThreads ) -{ - livre::ExecutorPtr executor( new livre::SimpleExecutor( nbOfWorkerThreads )); - return executor; -} - BOOST_AUTO_TEST_CASE( testSynchronousPipeline ) { const uint32_t inputValue = 90; - livre::PipeFilterPtr pipeInput; - livre::PipeFilterPtr pipeOutput; - - livre::PipelinePtr pipeline = createPipeline( pipeInput, - pipeOutput, - inputValue, - 1 ); - pipeline->execute(); + livre::Pipeline pipeline = createPipeline( inputValue, 1 ); + pipeline.execute(); - const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); + const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -249,20 +234,14 @@ BOOST_AUTO_TEST_CASE( testSynchronousPipeline ) BOOST_AUTO_TEST_CASE( testWaitPipeline ) { const uint32_t inputValue = 90; - livre::PipeFilterPtr pipeInput; - livre::PipeFilterPtr pipeOutput; + livre::Pipeline pipeline = createPipeline( inputValue, 1 ); - livre::PipelinePtr pipeline = createPipeline( pipeInput, - pipeOutput, - inputValue, - 1 ); - - livre::ExecutorPtr executor = createExecutor( 2 ); - - const livre::FutureMap pipelineFutures( executor->execute( pipeline->getExecutables( ))); + livre::SimpleExecutor executor( 2 ); + const livre::FutureMap pipelineFutures( executor.execute( pipeline.getExecutables( ))); pipelineFutures.wait(); - const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); + const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -270,19 +249,13 @@ BOOST_AUTO_TEST_CASE( testWaitPipeline ) BOOST_AUTO_TEST_CASE( testAsynchronousPipeline ) { const uint32_t inputValue = 90; - livre::PipeFilterPtr pipeInput; - livre::PipeFilterPtr pipeOutput; - - livre::PipelinePtr pipeline = createPipeline( pipeInput, - pipeOutput, - inputValue, - 1 ); - livre::ExecutorPtr executor = createExecutor( 2 ); + livre::Pipeline pipeline = createPipeline( inputValue, 1 ); + livre::SimpleExecutor executor( 2 ); - executor->execute( pipeline->getExecutables( )); - - const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + const livre::FutureMap pipelineFutures( executor.execute( pipeline.getExecutables( ))); + const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); + const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 222 ); } @@ -293,18 +266,13 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) { const size_t convertFilterCount = 10; const uint32_t inputValue = 90; - livre::PipeFilterPtr pipeInput; - livre::PipeFilterPtr pipeOutput; - - livre::PipelinePtr pipeline = createPipeline( pipeInput, - pipeOutput, - inputValue, - convertFilterCount ); - livre::ExecutorPtr executor = createExecutor( 1 ); - executor->execute( pipeline->getExecutables( )); + livre::Pipeline pipeline = createPipeline( inputValue, convertFilterCount ); - const livre::OutFutureMap portFutures( pipeOutput->getPostconditions( )); + livre::SimpleExecutor executor( 2 ); + const livre::FutureMap pipelineFutures( executor.execute( pipeline.getExecutables( ))); + const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); + const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData.thanksForAllTheFish, 1761 ); } @@ -313,17 +281,13 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) { const size_t convertFilterCount = 10; const uint32_t inputValue = 90; - livre::PipeFilterPtr pipeInput; - livre::PipeFilterPtr pipeOutput; + livre::Pipeline pipeline = createPipeline( inputValue, convertFilterCount ); - livre::PipelinePtr pipeline = createPipeline( pipeInput, - pipeOutput, - inputValue, - convertFilterCount ); - livre::ExecutorPtr executor = createExecutor( 8 ); - const livre::Futures& futures = executor->execute( pipeline->getExecutables( )); + livre::SimpleExecutor executor( 8 ); + const livre::Futures& futures = executor.execute( pipeline.getExecutables( )); + const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); - const livre::OutFutureMap portFutures1( pipeOutput->getPostconditions( )); + const livre::UniqueFutureMap portFutures1( pipeOutput.getPostconditions( )); const OutputData& outputData1 = portFutures1.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData1.thanksForAllTheFish, 1761 ); @@ -331,15 +295,32 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) const livre::FutureMap futureMap( futures ); futureMap.wait(); - pipeline->reset(); - executor->execute( pipeline->getExecutables( )); - pipeInput->getPromise( "TestInputData" )->set( InputData( inputValue )); + pipeline.reset(); + executor.execute( pipeline.getExecutables( )); + + livre::PipeFilter pipeInput = + static_cast< const livre::PipeFilter& >( + pipeline.getExecutable( "Producer" ).getImpl( )); + pipeInput.getPromise( "TestInputData" ).set( InputData( inputValue )); - const livre::OutFutureMap portFutures2( pipeOutput->getPostconditions( )); + const livre::UniqueFutureMap portFutures2( pipeOutput.getPostconditions( )); const OutputData& outputData2 = portFutures2.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData2.thanksForAllTheFish, 1761 ); } +} +BOOST_AUTO_TEST_CASE( testFutureMaps ) +{ + livre::PipeFilterT< TestFilter > pipeFilter( "Producer" ); + const livre::Futures& uniqueFutures = pipeFilter.getPostconditions(); -} + // The output futures are unique + const livre::UniqueFutureMap portFuturesUnique( uniqueFutures ); + const livre::FutureMap portFutures1( uniqueFutures ); + livre::Futures nonUniqueFutures = { uniqueFutures.front(), uniqueFutures.front() }; + + BOOST_CHECK_EXCEPTION( const livre::UniqueFutureMap portFuturesNonUnique( nonUniqueFutures ), + std::runtime_error, check_error ); + const livre::FutureMap portFutures2( nonUniqueFutures ); +} From 77be5647151e8be093ab0460033ac2e8d4f00148 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Fri, 18 Mar 2016 17:27:19 +0100 Subject: [PATCH 06/17] Fixing pipeline --- livre/core/CMakeLists.txt | 2 +- livre/core/pipeline/AsyncData.cpp | 43 +++----- livre/core/pipeline/AsyncData.h | 27 ++--- .../pipeline/{Executor.cpp => Executable.cpp} | 27 ++--- livre/core/pipeline/Executable.h | 86 ++++----------- livre/core/pipeline/Executor.h | 29 ++--- livre/core/pipeline/Filter.h | 10 +- livre/core/pipeline/Future.cpp | 21 +--- livre/core/pipeline/Future.h | 19 ++-- livre/core/pipeline/FutureMap.h | 8 +- livre/core/pipeline/InputPort.cpp | 8 +- livre/core/pipeline/InputPort.h | 10 +- livre/core/pipeline/OutputPort.cpp | 16 +-- livre/core/pipeline/OutputPort.h | 14 +-- livre/core/pipeline/PipeFilter.cpp | 10 +- livre/core/pipeline/PipeFilter.h | 12 +- livre/core/pipeline/Pipeline.cpp | 49 +++++---- livre/core/pipeline/Pipeline.h | 43 +++----- livre/core/pipeline/PortData.h | 6 +- livre/core/pipeline/Promise.cpp | 24 ++-- livre/core/pipeline/Promise.h | 13 +-- livre/core/pipeline/PromiseMap.h | 9 +- livre/core/pipeline/SimpleExecutor.cpp | 104 ++++++++++++------ livre/core/pipeline/SimpleExecutor.h | 28 ++--- livre/core/pipeline/Workers.cpp | 28 ++--- livre/core/pipeline/Workers.h | 2 +- livre/core/types.h | 2 +- tests/pipeline/pipeline.cpp | 12 +- 28 files changed, 280 insertions(+), 382 deletions(-) rename livre/core/pipeline/{Executor.cpp => Executable.cpp} (66%) diff --git a/livre/core/CMakeLists.txt b/livre/core/CMakeLists.txt index ca67536f..83d5bba3 100644 --- a/livre/core/CMakeLists.txt +++ b/livre/core/CMakeLists.txt @@ -111,7 +111,7 @@ set(LIVRECORE_SOURCES visitor/VisitState.cpp pipeline/AsyncData.cpp - pipeline/Executor.cpp + pipeline/Executable.cpp pipeline/Future.cpp pipeline/FutureMap.cpp pipeline/InputPort.cpp diff --git a/livre/core/pipeline/AsyncData.cpp b/livre/core/pipeline/AsyncData.cpp index 287af623..1036a657 100644 --- a/livre/core/pipeline/AsyncData.cpp +++ b/livre/core/pipeline/AsyncData.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include namespace livre @@ -30,19 +32,6 @@ typedef boost::shared_future< PortDataPtr > ConstPortDataFuture; typedef boost::promise< PortDataPtr > ConstPortDataPromise; typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; -namespace -{ - /* Boost wait_for_any implementation uses the internal locks from the futures. - Therefore, the get/set/query operations on promises/futures causes deadlocks - when used with wait_for_any( futurelist ) if futurelist is including the - future to be queried. With below implementation no locking is needed between - future operations. A higher granularity can be added for checking whether - the list includes the future or not, but simply exiting the wait_for_any - operation when lock is owned is simpler. - */ - ReadWriteMutex waitForAnyLock; -} - struct AsyncData::Impl { Impl( const DataInfo& dataInfo ) @@ -52,14 +41,11 @@ struct AsyncData::Impl ~Impl() { - if( !isReady()) - _promise.set_value( PortDataPtr( )); + set( PortDataPtr( )); } - const PortDataPtr& get( const std::type_index& dataType ) const + PortDataPtr get( const std::type_index& dataType ) const { - ReadLock lock( waitForAnyLock ); - const PortDataPtr& data = _future.get(); if( !data ) @@ -79,20 +65,21 @@ struct AsyncData::Impl LBTHROW( std::runtime_error( "Types does not match on set value")); } - ReadLock lock( waitForAnyLock ); - if( !_future.is_ready( )) + try + { _promise.set_value( data ); + } + catch( const boost::promise_already_satisfied& ) + {} } bool isReady() const { - ReadLock lock( waitForAnyLock ); return _future.is_ready(); } void wait() const { - ReadLock lock( waitForAnyLock ); _future.wait(); } @@ -112,7 +99,7 @@ AsyncData::AsyncData( const DataInfo& dataInfo ) : _impl( new Impl( dataInfo )) {} -const PortDataPtr& AsyncData::get( const std::type_index& dataType ) const +PortDataPtr AsyncData::get( const std::type_index& dataType ) const { return _impl->get( dataType ); } @@ -120,17 +107,17 @@ const PortDataPtr& AsyncData::get( const std::type_index& dataType ) const AsyncData::~AsyncData() {} -const std::type_index& AsyncData::getDataType() const +std::type_index AsyncData::getDataType() const { return _impl->_dataInfo.second; } -const std::string& AsyncData::getName() const +std::string AsyncData::getName() const { return _impl->_dataInfo.first; } -void AsyncData::set( const PortDataPtr& data ) +void AsyncData::set( PortDataPtr data ) { _impl->set( data ); } @@ -160,10 +147,6 @@ bool waitForAny( const Futures& futures ) for( const auto& future: futures ) boostFutures.push_back( future._getAsyncData()._impl->_future ); - WriteLock lock( waitForAnyLock, boost::try_to_lock ); - if( !lock.owns_lock( )) - return true; - boost::wait_for_any( boostFutures.begin(), boostFutures.end( )); return true; } diff --git a/livre/core/pipeline/AsyncData.h b/livre/core/pipeline/AsyncData.h index 32ce8a6b..50d1ed4a 100644 --- a/livre/core/pipeline/AsyncData.h +++ b/livre/core/pipeline/AsyncData.h @@ -26,7 +26,7 @@ namespace livre { /** - * The AsyncData class provides thread safe operations for setting/retrieving/querying + * Provides thread safe operations for setting/retrieving/querying * the data. The internal data has a name and data type. */ class AsyncData @@ -36,28 +36,27 @@ class AsyncData /** * When connection is instantiated the data is not * set yet, so any get() call will block the retrieval - * @param name of the connection - * @param dataType type of the data + * @param dataInfo name, data type pair */ explicit AsyncData( const DataInfo& dataInfo ); ~AsyncData(); /** - * @return the name of the connection + * @return the data type of the connection */ - const std::type_index& getDataType() const; + std::type_index getDataType() const; /** * @return the name of the connection */ - const std::string& getName() const; + std::string getName() const; /** * @param data sets the data * @throws std::runtime_error if data types does not match between data * and current async data */ - void set( const PortDataPtr& data ); + void set( PortDataPtr data ); /** * @param dataType is the requested data type. @@ -65,7 +64,7 @@ class AsyncData * @throws std::runtime_error if data types does not match between dataType * and current async data type */ - const PortDataPtr& get( const std::type_index& dataType ) const; + PortDataPtr get( const std::type_index& dataType ) const; /** * @return true if data is set. @@ -84,12 +83,6 @@ class AsyncData private: - /** - * Waits for any future to be ready. - * @param futures queried to be ready. - * @note this function needs internal access to the futures ( which is not exposed in the API ). - * @return true if any new futures are ready or futures included are not busy. - */ friend bool waitForAny( const Futures& futures ); AsyncData( const AsyncData& ) = delete; @@ -100,10 +93,10 @@ class AsyncData }; /** - * Waits for any futures to be ready. If there are already ready futures the function returns - * imeediately. + * Waits for any futures to be ready. If there are already ready futures, the function returns + * immediately. * @param futures that is waited to be ready - * @return true if there are still not ready futures. + * @return true if there are still not ready futures, false if all futures are ready. */ bool waitForAny( const Futures& futures ); diff --git a/livre/core/pipeline/Executor.cpp b/livre/core/pipeline/Executable.cpp similarity index 66% rename from livre/core/pipeline/Executor.cpp rename to livre/core/pipeline/Executable.cpp index 5fe902dd..21c617c8 100644 --- a/livre/core/pipeline/Executor.cpp +++ b/livre/core/pipeline/Executable.cpp @@ -17,33 +17,24 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include +#include namespace livre { -Futures Executor::execute( const Executable& executable ) +Futures Executable::schedule( Executor& executor ) { - const Futures& fs = executable.getPostconditions(); - _schedule({ executable }); - return fs; + _schedule( executor ); + return getPostconditions(); } -Futures Executor::execute( const Executables& executables ) -{ - Futures futures; - for( const Executable& executable: executables ) - { - const Futures& fs = executable.getPostconditions( ); - futures.insert( futures.end(), fs.begin(), fs.end( )); - } +Executable::~Executable() +{} - _schedule( executables ); - return futures; +void Executable::_schedule( Executor& executor ) +{ + executor.schedule( *this ); } -Executor::~Executor() -{} - } diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h index af6b6b3e..7c882e4c 100644 --- a/livre/core/pipeline/Executable.h +++ b/livre/core/pipeline/Executable.h @@ -22,104 +22,58 @@ #include #include +#include namespace livre { /** - * The Executable class is constructed using ExecutableImpl - * classes. It wraps the methods for execution of ExecutableImpl. - * a ExecutableImpl. It provides extra pre/post - * conditions as futures to retrieve the current situation. - * - * According to the preconditions or postconditions, - * executors can decide on scheduling algorithms. + * Is the base class for execution. It provides methods for execution, + * preconditions and postconditions for decision on scheduling. */ class Executable { public: - struct ExecutableImpl; - - /** - * @param impl Executable implementation. T class must be - * derived from ExecutableImpl and must be copy constructible - */ - template< class T > - Executable( const T& impl ) - : _impl( ExecutableImplPtr( new T( impl ))) - {} - /** - * @return the implementation + * Executes the executable */ - const ExecutableImpl& getImpl() const { return *_impl; } + virtual void execute() = 0; /** - * Executes the executable + * Schedules the executable through an Executor + * @param executor schedules the executable + * @return the post conditions */ - void execute() - { - _impl->execute(); - } + Futures schedule( Executor& executor ); /** - * @return the output futures for getting the outputs of the executable. The post + * @return the output conditions for getting the outputs of the executable. The post * conditions has to be fullfilled by the execute() implementation ( at the end of * execution all futures should be ready ) */ - Futures getPostconditions() const - { - return _impl->getPostconditions(); - } + virtual Futures getPostconditions() const = 0; /** - * @return the input futures which the executable can be queried for the state or + * @return the input conditions which the executable can be queried for the state or * data retrieval. */ - Futures getPreconditions() const - { - return _impl->getPreconditions(); - } + virtual Futures getPreconditions() const = 0; /** * Resets the executable by setting all pre and post conditions to an clean state * ( The futures are not ready ) */ - void reset() { _impl->reset(); } + virtual void reset() {} - /** - * Executable implementation - */ - struct ExecutableImpl - { - /** - * @copydoc Executable::execute - */ - virtual void execute() = 0; - - /** - * @copydoc Executable::getPostconditions - */ - virtual Futures getPostconditions() const = 0; - - /** - * @copydoc Executable::getPreconditions - */ - virtual Futures getPreconditions() const = 0; - - /** - * @copydoc Executable::reset - */ - virtual void reset() {} + virtual ~Executable(); - virtual ~ExecutableImpl() {} - }; +protected: -private: - - typedef std::shared_ptr< ExecutableImpl > ExecutableImplPtr; - ExecutableImplPtr _impl; + /** + * @copydoc Executable::schedule + */ + virtual void _schedule( Executor& executor ); }; } diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h index a66b26f1..c2ac02e5 100644 --- a/livre/core/pipeline/Executor.h +++ b/livre/core/pipeline/Executor.h @@ -26,38 +26,27 @@ namespace livre { /** - * Executor class is the base class for implementing different scheduling - * algorithms for submited work. i.e. The IO or CPU intensive algorithms - * can implement their own scheduling algorithms. + * Is the base class for implementing different scheduling + * algorithms for @see Executable objects. i.e. The IO or CPU intensive + * algorithms can implement their own scheduling algorithms. The + * push/pull scheduling algorithms can be implemented. */ class Executor { public: - virtual ~Executor(); - - /** - * Executes the executable. Returns the futures that can be queried for data. - * @param pipeline to be executed. - */ - Futures execute( const Executable& executable ); - - /** - * Executes the executable. Returns the futures that can be queried for data. - * @param pipeline to be executed. - */ - Futures execute( const Executables& executables ); - -protected: + virtual ~Executor() {} /** * Schedules the executables for execution. The deriving class should implement a * scheduling algorithm for the execution. ( i.e. there may be a work queue and * executables are selected from the work queue according to their pre-post * conditions - * @param executables are the executables to schedule. + * @param executable to schedule */ - virtual void _schedule( const Executables& executables ) = 0; + virtual void schedule( Executable& executable ) = 0; + +protected: /** * Clears the executor ( i.e : Implementation can empty the work queue ) diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h index 4443e913..cc2ad079 100644 --- a/livre/core/pipeline/Filter.h +++ b/livre/core/pipeline/Filter.h @@ -29,7 +29,7 @@ namespace livre * Filters are similar to functions ( immutable ). Their inputs and * outputs are provided with given name and data types. In execution time * values can be queried from the map of futures ( name - future pairs ) - * and can be set through the map of promises ( name - promise maps ) + * and can be set through the map of promises ( name - promise pairs ) */ class Filter { @@ -44,16 +44,16 @@ class Filter virtual void execute( const FutureMap& input, PromiseMap& output ) const = 0; /** - * @return information for the name and data types for the filter + * @return map for the name and data types for the filter * communication. In execution time using these names and types, - * data can be retrieved. + * data can be set. */ virtual DataInfos getInputDataInfos() const { return DataInfos(); } /** - * @return information for the name and data types for the filter + * @return map for the name and data types for the filter * communication. In execution time using these names and types, - * data can be set. + * data can be retrieved. */ virtual DataInfos getOutputDataInfos() const { return DataInfos(); } diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp index d27835cf..82af96ff 100644 --- a/livre/core/pipeline/Future.cpp +++ b/livre/core/pipeline/Future.cpp @@ -25,21 +25,19 @@ namespace livre struct Future::Impl { - Impl( const PipeFilter& pipeFilter, - const AsyncData& data ) + Impl( const AsyncData& data ) : _name( data.getName( )) - , _pipeFilter( pipeFilter ) , _data( data ) {} Future rename( const std::string& name ) const { - Future ret( _pipeFilter, _data ); + Future ret( _data ); ret._impl->_name = name; return ret; } - const std::string& getName() const + std::string getName() const { return _name; } @@ -60,19 +58,17 @@ struct Future::Impl } std::string _name; - const PipeFilter& _pipeFilter; const AsyncData& _data; }; -Future::Future( const PipeFilter& pipeFilter, - const AsyncData& data ) - : _impl( new Future::Impl( pipeFilter, data )) +Future::Future( const AsyncData& data ) + : _impl( new Future::Impl( data )) {} Future::~Future() {} -const std::string& Future::getName() const +std::string Future::getName() const { return _impl->getName(); } @@ -92,11 +88,6 @@ bool Future::isReady() const return _impl->isReady(); } -const PipeFilter& Future::getPipeFilter() const -{ - return _impl->_pipeFilter; -} - const AsyncData& Future::_getAsyncData() const { return _impl->_data; diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h index 77ca5c90..f195120d 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/Future.h @@ -36,21 +36,18 @@ class Future public: /** - * @param pipeFilter is the reference to @Pipefilter class which - * instantiates the @see Promise that Future belongs to. * @param data holds the thread safe data (query/retrieve). */ - Future( const PipeFilter& pipeFilter, - const AsyncData& data ); + Future( const AsyncData& data ); ~Future(); /** * @return name of the future */ - const std::string& getName() const; + std::string getName() const; /** - * Gets a copy future with the given name + * Gets a shallow copy of the future with the given name */ Future rename( const std::string& name ) const; @@ -75,16 +72,16 @@ class Future bool isReady() const; /** - * @return the pipe filter that future belongs to. If executor supports pull mode, - * by getting futures, it will be possible to reach the source of the execution + * @param future is the future to be checked with + * @return true if both futures are same */ - const PipeFilter& getPipeFilter() const; + bool operator==( const Future& future ) const { return _impl == future._impl; } /** * @param future is the future to be checked with - * @return true if both futures are same + * @return true if implementation address is smaller than the other implementation address */ - bool operator==( const Future& future ) const { return _impl == future._impl; } + bool operator<( const Future& future ) const { return _impl.get() < future._impl.get(); } private: diff --git a/livre/core/pipeline/FutureMap.h b/livre/core/pipeline/FutureMap.h index cb2610f2..c37c9dad 100644 --- a/livre/core/pipeline/FutureMap.h +++ b/livre/core/pipeline/FutureMap.h @@ -84,7 +84,7 @@ class FutureMap * @param name of the future. If name is ALL_FUTURES, all futures are marked to return. * @return the futures associated with the name. */ - Futures getFutures( const std::string& portName = ALL_FUTURES ) const; + Futures getFutures( const std::string& name = ALL_FUTURES ) const; /** * Queries if port is ready @@ -93,7 +93,7 @@ class FutureMap * @throw std::runtime_error when there is no future associated with the * given name */ - bool isReady( const std::string& portName = ALL_FUTURES ) const; + bool isReady( const std::string& name = ALL_FUTURES ) const; /** * Waits all futures associated with port name @@ -101,7 +101,7 @@ class FutureMap * @throw std::runtime_error when there is no future associated with the * given name */ - void wait( const std::string& portName = ALL_FUTURES ) const; + void wait( const std::string& name = ALL_FUTURES ) const; /** * Waits all futures associated with port name. @@ -109,7 +109,7 @@ class FutureMap * @throw std::runtime_error when there is no future associated with the * given name */ - bool waitForAny( const std::string& portName = ALL_FUTURES ) const; + bool waitForAny( const std::string& name = ALL_FUTURES ) const; private: diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp index f99024fb..a9cd5e6b 100644 --- a/livre/core/pipeline/InputPort.cpp +++ b/livre/core/pipeline/InputPort.cpp @@ -34,7 +34,7 @@ struct InputPort::Impl ~Impl() {} - const std::string& getName() const + std::string getName() const { return _info.first; } @@ -44,7 +44,7 @@ struct InputPort::Impl return _futures.size(); } - const std::type_index& getDataType() const + std::type_index getDataType() const { return _info.second; } @@ -98,12 +98,12 @@ bool InputPort::disconnect( const OutputPort& port ) return _impl->disconnect( port ); } -const std::string& InputPort::getName() const +std::string InputPort::getName() const { return _impl->getName(); } -const std::type_index& InputPort::getDataType() const +std::type_index InputPort::getDataType() const { return _impl->getDataType(); } diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index 94824e82..d1e106e1 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -26,16 +26,14 @@ namespace livre { /** - * InputPort class implements the input port to a @PipeFilter. It - * provides thread safe query and retrieval. + * Input connection for the @see PipeFilter. */ class InputPort { public: /** - * InputPort constructor based on port information - * @param dataInfo is the port information + * @param dataInfo is the name and type information for the data. */ explicit InputPort( const DataInfo& dataInfo ); ~InputPort(); @@ -43,12 +41,12 @@ class InputPort /** * @return name of the port */ - const std::string& getName() const; + std::string getName() const; /** * @return data type of the port */ - const std::type_index& getDataType() const; + std::type_index getDataType() const; /** * @return the number of the inputs to the port diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp index 6169fe67..37d58e27 100644 --- a/livre/core/pipeline/OutputPort.cpp +++ b/livre/core/pipeline/OutputPort.cpp @@ -26,8 +26,8 @@ namespace livre struct OutputPort::Impl { - Impl( const PipeFilter& pipeFilter, const DataInfo& dataInfo ) - : _promise( pipeFilter, dataInfo ) + Impl( const DataInfo& dataInfo ) + : _promise( dataInfo ) {} ~Impl() @@ -40,12 +40,12 @@ struct OutputPort::Impl _promise.flush(); } - const std::type_index& getDataType() const + std::type_index getDataType() const { return _promise.getDataType(); } - const std::string& getName() const + std::string getName() const { return _promise.getName(); } @@ -58,8 +58,8 @@ struct OutputPort::Impl Promise _promise; }; -OutputPort::OutputPort( const PipeFilter& pipeFilter, const DataInfo& dataInfo ) - : _impl( new OutputPort::Impl( pipeFilter, dataInfo )) +OutputPort::OutputPort( const DataInfo& dataInfo ) + : _impl( new OutputPort::Impl( dataInfo )) {} @@ -70,12 +70,12 @@ OutputPort::OutputPort( OutputPort&& port ) : _impl( std::move( port._impl )) {} -const std::string& OutputPort::getName() const +std::string OutputPort::getName() const { return _impl->getName(); } -const std::type_index& OutputPort::getDataType() const +std::type_index OutputPort::getDataType() const { return _impl->getDataType(); } diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h index 3ee102b0..d124b1a3 100644 --- a/livre/core/pipeline/OutputPort.h +++ b/livre/core/pipeline/OutputPort.h @@ -25,6 +25,9 @@ namespace livre { +/** + * Output connection for the @see PipeFilter. + */ class OutputPort { @@ -32,23 +35,20 @@ class OutputPort /** * @param dataInfo is the name and type information for the data. - * @param pipeFilter is the reference to the pipefilter class which instantiates the - * Promise. */ - OutputPort( const PipeFilter& pipeFilter, - const DataInfo& dataInfo ); + OutputPort( const DataInfo& dataInfo ); ~OutputPort(); OutputPort( OutputPort&& port ); /** * @return name of the port */ - const std::string& getName() const; + std::string getName() const; /** * @return data type of the port */ - const std::type_index& getDataType() const; + std::type_index getDataType() const; /** * @return the promise, that data can be written to @@ -72,8 +72,6 @@ class OutputPort std::unique_ptr _impl; }; -bool waitForAny( const Futures& futures ); - } #endif // _OutputPort_h_ diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index 96f6b73d..7e8fc968 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -53,7 +53,7 @@ struct PipeFilter::Impl { _outputMap.emplace( std::piecewise_construct, std::forward_as_tuple( dataInfo.first ), - std::forward_as_tuple( _pipeFilter, dataInfo )); + std::forward_as_tuple( dataInfo )); } } @@ -110,8 +110,7 @@ struct PipeFilter::Impl _manuallySetPortsMap.emplace( std::piecewise_construct, std::forward_as_tuple( inputPort.getName( )), - std::forward_as_tuple( _pipeFilter, - DataInfo( inputPort.getName(), + std::forward_as_tuple( DataInfo( inputPort.getName(), inputPort.getDataType( )))); OutputPort& outputPort = _manuallySetPortsMap.find( inputPort.getName( ))->second; @@ -196,7 +195,7 @@ PipeFilter::PipeFilter( const std::string& name, PipeFilter::~PipeFilter() {} -const std::string& PipeFilter::getName() const +std::string PipeFilter::getName() const { return _impl->_name; } @@ -230,8 +229,7 @@ void PipeFilter::connect( const std::string& srcPortName, PipeFilter& dst, const std::string& dstPortName ) { - _impl->connect( srcPortName, *dst._impl, dstPortName ); + _impl->connect( srcPortName, *dst._impl, dstPortName ); } - } diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index beb49d32..d3d0f45f 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -27,10 +27,10 @@ namespace livre { /** - * PipeFilter class instantiates the @Filter classes by constructing - * the communication layer around the filter. + * Responsible for execution of the @see Filter objects by constructing + * the communication layer ( output ports, input ports ) around the filter. */ -class PipeFilter : public Executable::ExecutableImpl +class PipeFilter : public Executable { public: @@ -39,10 +39,10 @@ class PipeFilter : public Executable::ExecutableImpl /** * @return the unique name of the filter. */ - const std::string& getName() const; + std::string getName() const; /** - * Connect to given pipe filter with the given port names. Both filters + * Connects to given pipe filter with the given port names. Both filters * should have the same port data type. * @param srcPortName is the source pipe filter. * @param dst is the destination pipe filter. @@ -54,7 +54,7 @@ class PipeFilter : public Executable::ExecutableImpl const std::string& dstPortName ); /** - * @return return promise for the given input port. If there is no connection to the + * @return promise for the given input port. If there is no connection to the * input port, a new promise is created for the port and no further connections are allowed, * if there is a connection getting a promise is not allowed. * @throws std::runtime_error if there is already a connection or if there is diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp index 927b00b1..e8e1b51d 100644 --- a/livre/core/pipeline/Pipeline.cpp +++ b/livre/core/pipeline/Pipeline.cpp @@ -28,24 +28,26 @@ struct Pipeline::Impl { typedef std::map< std::string, const Pipeline > PipelineMap; typedef std::map< std::string, const PipeFilter > PipeFilterMap; - typedef std::map< std::string, Executable > ExecutableMap; + typedef std::map< std::string, std::unique_ptr< Executable >> ExecutableMap; Impl( Pipeline& pipeline ) : _pipeline( pipeline ) {} void add( const std::string& name, - const Executable& executable, + Executable* executable, bool wait ) { if( _executableMap.count( name ) > 0 ) LBTHROW( std::runtime_error( name + " already exists")); - _executableMap.insert({ name, executable }); + _executableMap.emplace( std::piecewise_construct, + std::forward_as_tuple( name ), + std::forward_as_tuple( executable )); if( wait ) { - const Futures& futures = executable.getPostconditions(); + const Futures& futures = executable->getPostconditions(); _outFutures.insert( _outFutures.end(), futures.begin(), futures.end( )); } } @@ -56,11 +58,11 @@ struct Pipeline::Impl Executables::iterator it = executables.begin(); while( !executables.empty( )) { - Executable& executable = *it; - const FutureMap futureMap( executable.getPreconditions( )); + Executable* executable = *it; + const FutureMap futureMap( executable->getPreconditions( )); if( futureMap.isReady( )) { - executable.execute(); + executable->execute(); executables.erase( it ); it = executables.begin(); } @@ -77,8 +79,8 @@ struct Pipeline::Impl { Executables executables; - for( auto pair: _executableMap ) - executables.push_back( pair.second ); + for( auto& pair: _executableMap ) + executables.push_back( pair.second.get( )); return executables; } @@ -88,15 +90,15 @@ struct Pipeline::Impl if( _executableMap.count( name ) == 0 ) LBTHROW( std::runtime_error( name + " executable does not exist")); - return _executableMap.find( name )->second; + return *_executableMap.find( name )->second; } Futures getPreconditions() const { Futures inFutures; - for( auto pair: _executableMap ) + for( auto& pair: _executableMap ) { - const Futures& futures = pair.second.getPreconditions(); + const Futures& futures = pair.second->getPreconditions(); inFutures.insert( inFutures.end(), futures.begin(), futures.end( )); } return inFutures; @@ -107,10 +109,16 @@ struct Pipeline::Impl return _outFutures; } + void schedule( Executor& executor ) + { + for( auto& pair: _executableMap ) + executor.schedule( *pair.second ); + } + void reset() { for( auto& pair: _executableMap ) - pair.second.reset(); + pair.second->reset(); } Pipeline& _pipeline; @@ -127,15 +135,10 @@ Pipeline::~Pipeline() {} void Pipeline::_add( const std::string& name, - const Executable& executable, + Executable* exec, bool wait ) { - _impl->add( name, executable, wait ); -} - -Executables Pipeline::getExecutables() const -{ - return _impl->getExecutables(); + _impl->add( name, exec, wait ); } const Executable& Pipeline::getExecutable( const std::string& name ) const @@ -143,7 +146,6 @@ const Executable& Pipeline::getExecutable( const std::string& name ) const return _impl->getExecutable( name ); } - void Pipeline::execute() { _impl->execute(); @@ -164,4 +166,9 @@ void Pipeline::reset() _impl->reset(); } +void Pipeline::_schedule( Executor& executor ) +{ + _impl->schedule( executor ); +} + } diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index d499cc5e..cae06278 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -28,12 +28,9 @@ namespace livre { /** - * Pipeline represents a filter graph. On asynchronous - * execution through the Executor, the status of the - * execution can be queried whether the execution is - * complete or not through the post conditions. + * Implements the executable graph. */ -class Pipeline : public Executable::ExecutableImpl +class Pipeline : public Executable { public: @@ -43,16 +40,16 @@ class Pipeline : public Executable::ExecutableImpl /** * Adds a pipeline to be executed. - * @param pipeline is added to list of executables - * @param wait If true, on asynchronous execution, pipeline - * can wait on given pipeline. + * @param pipeline is added to list of executables ( shallow copied ) + * @param wait If true, on scheduled execution, pipeline + * can wait on given pipeline post conditions. */ void add( const std::string& name, - const Pipeline& pipeline, + Pipeline& pipeline, bool wait = true ) { _add( name, - Executable( pipeline ), + new Pipeline( pipeline ), wait ); } @@ -61,29 +58,21 @@ class Pipeline : public Executable::ExecutableImpl * @param FilterT is the type of filter to be added to list of executables. * @name name the name of the filter instance. * @param args for the FilterT construction - * @param wait If true, on asynchronous execution, pipeline - * can wait on the added filter. + * @param wait If true, on scheduled execution, pipeline + * can wait on the post conditions of the pipefilter. * @return returns the generated pipe filter. * @throws std::runtime_error if an executable with same name is present */ - template< class FilterT, class... Args, bool wait = true > + template< class FilterT, bool wait = true, class... Args > PipeFilter add( const std::string& name, Args&&... args ) { - PipeFilterT< FilterT > pipeFilter( name, args... ); - _add( name, - Executable( pipeFilter ), - wait ); - return pipeFilter; + PipeFilter* pipeFilter = new PipeFilterT< FilterT >( name, args... ); + _add( name, pipeFilter, wait ); + return *pipeFilter; } - /** - * @return the list of all executables ( pipe filters and - * pipelines ) - */ - Executables getExecutables() const; - /** * @param name of the executable * @return the executable @@ -114,10 +103,12 @@ class Pipeline : public Executable::ExecutableImpl private: void _add( const std::string& name, - const Executable& filter, - bool wait ); + Executable* exec, + bool wait ); private: + void _schedule( Executor& executor ) final; + struct Impl; std::shared_ptr< Impl > _impl; diff --git a/livre/core/pipeline/PortData.h b/livre/core/pipeline/PortData.h index 996596c0..e6721684 100644 --- a/livre/core/pipeline/PortData.h +++ b/livre/core/pipeline/PortData.h @@ -26,7 +26,7 @@ namespace livre { /** - * PortData class is base class for keeping the track for types + * Base class for keeping the track for types of data * by using the std::type_index. */ class PortData @@ -46,6 +46,10 @@ class PortData template< class T> struct PortDataT final : public PortData { + /** + * Constructor + * @param data_ is copied + */ explicit PortDataT( const T& data_ ) : PortData( getType< T >()) , data( data_ ) diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp index 77ba4642..38e787e0 100644 --- a/livre/core/pipeline/Promise.cpp +++ b/livre/core/pipeline/Promise.cpp @@ -26,19 +26,17 @@ namespace livre struct Promise::Impl { - Impl( const PipeFilter& pipeFilter, - const DataInfo& dataInfo ) - : _pipeFilter( pipeFilter ) - , _data( dataInfo ) - , _future( _pipeFilter, _data ) + Impl( const DataInfo& dataInfo ) + : _data( dataInfo ) + , _future( _data ) {} - const std::string& getName() const + std::string getName() const { return _data.getName(); } - const std::type_index& getDataType() const + std::type_index getDataType() const { return _data.getDataType(); } @@ -58,25 +56,23 @@ struct Promise::Impl _data.set( PortDataPtr( )); } - const PipeFilter& _pipeFilter; AsyncData _data; const Future _future; }; -Promise::Promise( const PipeFilter& pipeFilter, - const DataInfo& dataInfo ) - : _impl( new Promise::Impl( pipeFilter, dataInfo )) +Promise::Promise( const DataInfo& dataInfo ) + : _impl( new Promise::Impl( dataInfo )) {} Promise::~Promise() {} -const std::type_index& Promise::getDataType() const +std::type_index Promise::getDataType() const { return _impl->getDataType(); } -const std::string& Promise::getName() const +std::string Promise::getName() const { return _impl->getName(); } @@ -86,7 +82,7 @@ void Promise::flush() _impl->flush(); } -const Future& Promise::getFuture() const +Future Promise::getFuture() const { return _impl->_future; } diff --git a/livre/core/pipeline/Promise.h b/livre/core/pipeline/Promise.h index 2083c5d6..cbb663ff 100644 --- a/livre/core/pipeline/Promise.h +++ b/livre/core/pipeline/Promise.h @@ -29,7 +29,7 @@ namespace livre /** - * The Promise class is similar to the std::promise classes in functionality and it has additional + * Is similar to the std::promise classes in functionality and it has additional * information for the name and data type. It provides methods to set the data. */ class Promise @@ -37,23 +37,20 @@ class Promise public: /** - * @param pipeFilter is the reference to the pipefilter class which instantiates the - * Promise. * @param dataInfo is the name and type information for the data. */ - Promise( const PipeFilter& pipeFilter, - const DataInfo& dataInfo ); + Promise( const DataInfo& dataInfo ); ~Promise(); /** * @return the name of the connection */ - const std::type_index& getDataType() const; + std::type_index getDataType() const; /** * @return the name of the connection */ - const std::string& getName() const; + std::string getName() const; /** * Sets the port with the value. @@ -87,7 +84,7 @@ class Promise /** * @return the future, that can be queried for data retrieval */ - const Future& getFuture() const; + Future getFuture() const; /** * @resets the promise. ( Future is reset and value can be set again ) diff --git a/livre/core/pipeline/PromiseMap.h b/livre/core/pipeline/PromiseMap.h index 85310e7b..8b4a20da 100644 --- a/livre/core/pipeline/PromiseMap.h +++ b/livre/core/pipeline/PromiseMap.h @@ -27,14 +27,7 @@ namespace livre { /** - * The PipeFilterOutput class is used by the @PipeFilter class to instantiate - * the outgoing connections to a given filter using the connection info - * provided by the filter. - * - * It provides functionality to wait on any or all the ports given by - * name. - * - * It also provides thread safe functions to query the state of the port. + * Wrapper class for applying operations on the @Promise objects. */ class PromiseMap { diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp index 023279ce..25f711d6 100644 --- a/livre/core/pipeline/SimpleExecutor.cpp +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include @@ -33,6 +36,9 @@ #include +#include +#include + namespace livre { @@ -42,53 +48,83 @@ struct SimpleExecutor::Impl Impl( const size_t threadCount ) : _workThread( boost::thread( boost::bind( &Impl::schedule, this ))) , _workers( threadCount ) + , _unlockPromise( DataInfo( "LoopUnlock", getType< bool >( ))) {} ~Impl() { _mtWorkQueue.clear(); - _mtWorkQueue.push( Executables( )); + _mtWorkQueue.push( 0 ); _workThread.join(); } void schedule() { + std::set< Future > inputConditions; + std::set< Future > outputConditions; + while( true ) { - Executables executables = _mtWorkQueue.pop(); - if( executables.empty() ) - break; + Executables executables; + Executable* executable = _mtWorkQueue.pop(); + if( !executable ) + return; + + executables.push_back( executable ); - Futures futures; + for( const Executable* exec: executables ) + for( const Future& future: exec->getPreconditions( )) + inputConditions.insert( future ); - do + Executables::iterator it = executables.begin(); + while( it != executables.end( )) { - futures.clear(); - for( const Executable& executable: executables ) + Executable* exec = *it; + const FutureMap futureMap( exec->getPreconditions( )); + if( futureMap.isReady( )) { - const Futures& inputFutures = executable.getPreconditions(); - for( const Future& future: inputFutures ) - { - if( !future.isReady( )) - futures.push_back( future ); - } - } + _workers.execute( *exec ); + it = executables.erase( it ); - Executables::iterator it = executables.begin(); - while( it != executables.end( )) - { - Executable& executable = *it; - const FutureMap futureMap( executable.getPreconditions( )); - if( futureMap.isReady( )) - { - _workers.execute( executable ); - it = executables.erase( it ); - } - else - ++it; + for( const Future& future: exec->getPostconditions( )) + outputConditions.insert( future ); + + for( const Future& future: exec->getPreconditions( )) + inputConditions.erase( future ); } + else + ++it; + } + + Futures intersection; + std::set_intersection( outputConditions.begin(), outputConditions.end(), + inputConditions.begin(), inputConditions.end(), + std::back_inserter( intersection )); + + // Wait only for the futures where executed output conditions + // executables intersects + if( !intersection.empty( )) + { + FutureMap futureMap( intersection ); + futureMap.waitForAny(); + } + + // Add left over executables back to queue + for( Executable* exec: executables ) + _mtWorkQueue.push( exec ); - } while( FutureMap( futures ).waitForAny( )); + FutureMap futureMap( intersection ); + futureMap.waitForAny(); + + std::set< Future >::iterator itFuture = outputConditions.begin(); + while( itFuture != outputConditions.end( )) + { + const Future& future = *itFuture; + if( future.isReady( )) + itFuture = outputConditions.erase( itFuture ); + else + ++itFuture; + } } } @@ -97,14 +133,16 @@ struct SimpleExecutor::Impl _mtWorkQueue.clear(); } - void submit( Executables work ) + void schedule( Executable& exec ) { - _mtWorkQueue.push( work ); + _mtWorkQueue.push( &exec ); } - lunchbox::MTQueue< Executables > _mtWorkQueue; + lunchbox::MTQueue< Executable* > _mtWorkQueue; boost::thread _workThread; Workers _workers; + Promise _unlockPromise; + boost::mutex _promiseReset; }; SimpleExecutor::SimpleExecutor( const size_t threadCount ) @@ -120,9 +158,9 @@ void SimpleExecutor::clear() _impl->clear(); } -void SimpleExecutor::_schedule( const Executables& executables ) +void SimpleExecutor::schedule( Executable& executable ) { - _impl->submit( executables ); + _impl->schedule( executable ); } } diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h index 26fa1762..9cb5ca6c 100644 --- a/livre/core/pipeline/SimpleExecutor.h +++ b/livre/core/pipeline/SimpleExecutor.h @@ -27,20 +27,12 @@ namespace livre { /** - * SimpleExecutor class provides a very basic implementation - * for the @see Executor class. It has a thread pool for - * executing multiple executables asynchronously. + * Provides a very basic implementation for the @see Executor + * class. It has a thread pool for executing multiple executables + * asynchronously. * - * The submitted executables are queued for the worker threads. - * without any real scheduling.The pipeline submission is - * thread safe. - * - * The scheduler implemented in this class, pushes the - * executables without re-ordering. The executable whose - * preconditions are satisfied is marked for execution - * in the thread pool. - * - * SimpleExecutor executes executables in a push based flow. + * The submitted executables are queued for the worker threads, + * by looking at the preconditions if they are satisfied. */ class SimpleExecutor : public Executor @@ -54,6 +46,11 @@ class SimpleExecutor : public Executor explicit SimpleExecutor( size_t threadCount ); virtual ~SimpleExecutor(); + /** + * @copydoc Executor::schedule + */ + void schedule( Executable& executable ) final; + /** * @copydoc Executor::clear() */ @@ -61,11 +58,6 @@ class SimpleExecutor : public Executor private: - /** - * @copydoc Executor::_schedule - */ - void _schedule( const Executables& executables ) final; - struct Impl; std::unique_ptr _impl; }; diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp index 66aa6db2..435147d5 100644 --- a/livre/core/pipeline/Workers.cpp +++ b/livre/core/pipeline/Workers.cpp @@ -29,8 +29,6 @@ namespace livre struct Workers::Impl { - - Impl( Workers& workers, const size_t nThreads, const GLContextPtr& glContext ) @@ -43,16 +41,6 @@ struct Workers::Impl } - struct Work - { - Work( const Executable& executable_ ) - : executable( executable_ ) - {} - Executable executable; - }; - - typedef std::shared_ptr< Work > WorkPtr; - void execute() { if( _glContext ) @@ -64,25 +52,25 @@ struct Workers::Impl while( true ) { - WorkPtr work = _workQueue.pop(); - if( !work ) + Executable* exec = _workQueue.pop(); + if( !exec ) break; - work->executable.execute(); + exec->execute(); } } ~Impl() { for( size_t i = 0; i < getSize(); ++i ) - _workQueue.push( WorkPtr()); + _workQueue.push( 0 ); _threadGroup.join_all(); } - void submitWork( const Executable& executable ) + void submitWork( Executable& executable ) { - _workQueue.push( WorkPtr( new Work( executable ))); + _workQueue.push( &executable ); } size_t getSize() const @@ -91,7 +79,7 @@ struct Workers::Impl } Workers& _workers; - lunchbox::MTQueue< WorkPtr > _workQueue; + lunchbox::MTQueue< Executable* > _workQueue; boost::thread_group _threadGroup; const GLContextPtr _glContext; }; @@ -106,7 +94,7 @@ Workers::Workers( const size_t nThreads, Workers::~Workers() {} -void Workers::execute( const Executable& executable ) +void Workers::execute( Executable& executable ) { _impl->submitWork( executable ); } diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index ec173d55..78249bb4 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -48,7 +48,7 @@ class Workers * threads. * @param executable is executed by thread pool. */ - void execute( const Executable& executable ); + void execute( Executable& executable ); /** * @return the size of thread pool. diff --git a/livre/core/types.h b/livre/core/types.h index f6d89346..381c8b1a 100644 --- a/livre/core/types.h +++ b/livre/core/types.h @@ -192,7 +192,7 @@ typedef std::vector< CacheId > CacheIds; typedef std::vector< CacheObjectPtr > CacheObjects; typedef std::vector< ConstCacheObjectPtr > ConstCacheObjects; -typedef std::list< Executable > Executables; +typedef std::list< Executable* > Executables; typedef std::list< Future > Futures; typedef std::list< Promise > Promises; diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index 52ccbdac..86edb322 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE( testWaitPipeline ) livre::Pipeline pipeline = createPipeline( inputValue, 1 ); livre::SimpleExecutor executor( 2 ); - const livre::FutureMap pipelineFutures( executor.execute( pipeline.getExecutables( ))); + const livre::FutureMap pipelineFutures( pipeline.schedule( executor )); pipelineFutures.wait(); const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); @@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE( testAsynchronousPipeline ) livre::Pipeline pipeline = createPipeline( inputValue, 1 ); livre::SimpleExecutor executor( 2 ); - const livre::FutureMap pipelineFutures( executor.execute( pipeline.getExecutables( ))); + const livre::FutureMap pipelineFutures( pipeline.schedule( executor )); const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); @@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) livre::Pipeline pipeline = createPipeline( inputValue, convertFilterCount ); livre::SimpleExecutor executor( 2 ); - const livre::FutureMap pipelineFutures( executor.execute( pipeline.getExecutables( ))); + const livre::FutureMap pipelineFutures( pipeline.schedule( executor )); const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); @@ -284,7 +284,7 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) livre::Pipeline pipeline = createPipeline( inputValue, convertFilterCount ); livre::SimpleExecutor executor( 8 ); - const livre::Futures& futures = executor.execute( pipeline.getExecutables( )); + const livre::Futures& futures = pipeline.schedule( executor ); const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); const livre::UniqueFutureMap portFutures1( pipeOutput.getPostconditions( )); @@ -296,11 +296,11 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) futureMap.wait(); pipeline.reset(); - executor.execute( pipeline.getExecutables( )); + pipeline.schedule( executor ); livre::PipeFilter pipeInput = static_cast< const livre::PipeFilter& >( - pipeline.getExecutable( "Producer" ).getImpl( )); + pipeline.getExecutable( "Producer" )); pipeInput.getPromise( "TestInputData" ).set( InputData( inputValue )); const livre::UniqueFutureMap portFutures2( pipeOutput.getPostconditions( )); From 71635ceb4b7215875ea2f5ca0c16c1db778977e4 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Wed, 23 Mar 2016 14:32:36 +0100 Subject: [PATCH 07/17] Changes according to comments --- livre/core/pipeline/AsyncData.cpp | 16 ++-- livre/core/pipeline/AsyncData.h | 26 +++--- livre/core/pipeline/Executable.cpp | 1 - livre/core/pipeline/Executor.h | 9 +- livre/core/pipeline/Filter.h | 2 +- livre/core/pipeline/Future.cpp | 10 ++- livre/core/pipeline/Future.h | 39 ++++---- livre/core/pipeline/FutureMap.cpp | 50 +++++++---- livre/core/pipeline/FutureMap.h | 119 ++++++++++++++++++------- livre/core/pipeline/InputPort.cpp | 17 ++-- livre/core/pipeline/InputPort.h | 4 +- livre/core/pipeline/OutputPort.cpp | 4 - livre/core/pipeline/OutputPort.h | 3 +- livre/core/pipeline/PipeFilter.cpp | 8 +- livre/core/pipeline/PipeFilter.h | 10 ++- livre/core/pipeline/Pipeline.h | 7 +- livre/core/pipeline/PortData.h | 6 +- livre/core/pipeline/Promise.cpp | 9 +- livre/core/pipeline/Promise.h | 14 +-- livre/core/pipeline/PromiseMap.cpp | 12 +++ livre/core/pipeline/PromiseMap.h | 21 ++--- livre/core/pipeline/SimpleExecutor.cpp | 5 ++ livre/core/types.h | 11 +-- tests/pipeline/pipeline.cpp | 4 +- 24 files changed, 237 insertions(+), 170 deletions(-) diff --git a/livre/core/pipeline/AsyncData.cpp b/livre/core/pipeline/AsyncData.cpp index 1036a657..e928f6e5 100644 --- a/livre/core/pipeline/AsyncData.cpp +++ b/livre/core/pipeline/AsyncData.cpp @@ -41,7 +41,12 @@ struct AsyncData::Impl ~Impl() { - set( PortDataPtr( )); + try + { + set( PortDataPtr( )); + } + catch( const std::runtime_error& ) + {} } PortDataPtr get( const std::type_index& dataType ) const @@ -70,7 +75,9 @@ struct AsyncData::Impl _promise.set_value( data ); } catch( const boost::promise_already_satisfied& ) - {} + { + LBTHROW( std::runtime_error( "Data only can be set once")); + } } bool isReady() const @@ -137,10 +144,10 @@ void AsyncData::reset() _impl->reset(); } -bool waitForAny( const Futures& futures ) +void waitForAny( const Futures& futures ) { if( futures.empty( )) - return false; + return; ConstPortDataFutures boostFutures; boostFutures.reserve( futures.size( )); @@ -148,7 +155,6 @@ bool waitForAny( const Futures& futures ) boostFutures.push_back( future._getAsyncData()._impl->_future ); boost::wait_for_any( boostFutures.begin(), boostFutures.end( )); - return true; } } diff --git a/livre/core/pipeline/AsyncData.h b/livre/core/pipeline/AsyncData.h index 50d1ed4a..d75520e6 100644 --- a/livre/core/pipeline/AsyncData.h +++ b/livre/core/pipeline/AsyncData.h @@ -34,8 +34,7 @@ class AsyncData public: /** - * When connection is instantiated the data is not - * set yet, so any get() call will block the retrieval + * Constructor * @param dataInfo name, data type pair */ explicit AsyncData( const DataInfo& dataInfo ); @@ -52,17 +51,19 @@ class AsyncData std::string getName() const; /** + * Sets the data. * @param data sets the data - * @throws std::runtime_error if data types does not match between data + * @throw std::runtime_error if data types does not match between data * and current async data + * @throw std::runtime_error if data is set twice. */ void set( PortDataPtr data ); /** + * Gets the data. If data is not set it will block. * @param dataType is the requested data type. - * @return the data. If data is not set it will block. - * @throws std::runtime_error if data types does not match between dataType - * and current async data type + * @return the data. + * @throw std::runtime_error if getDataType() != dataType */ PortDataPtr get( const std::type_index& dataType ) const; @@ -77,13 +78,14 @@ class AsyncData void wait() const; /** - * Resets the promise/future + * Resets the promise/future. This function should not be called when + * threads are blocked on wait() */ void reset(); private: - friend bool waitForAny( const Futures& futures ); + friend void waitForAny( const Futures& futures ); AsyncData( const AsyncData& ) = delete; AsyncData& operator=( const AsyncData& ) = delete; @@ -92,14 +94,6 @@ class AsyncData std::unique_ptr _impl; }; -/** - * Waits for any futures to be ready. If there are already ready futures, the function returns - * immediately. - * @param futures that is waited to be ready - * @return true if there are still not ready futures, false if all futures are ready. - */ -bool waitForAny( const Futures& futures ); - } #endif // _AsyncData_h_ diff --git a/livre/core/pipeline/Executable.cpp b/livre/core/pipeline/Executable.cpp index 21c617c8..22e3c524 100644 --- a/livre/core/pipeline/Executable.cpp +++ b/livre/core/pipeline/Executable.cpp @@ -18,7 +18,6 @@ */ #include -#include namespace livre { diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h index c2ac02e5..f05be62a 100644 --- a/livre/core/pipeline/Executor.h +++ b/livre/core/pipeline/Executor.h @@ -26,10 +26,11 @@ namespace livre { /** - * Is the base class for implementing different scheduling - * algorithms for @see Executable objects. i.e. The IO or CPU intensive - * algorithms can implement their own scheduling algorithms. The - * push/pull scheduling algorithms can be implemented. + * Is base class for implementing different scheduling + * algorithms for Executable objects. i.e. The IO or + * CPU intensive algorithms can implement their own scheduling + * algorithms. The push/pull scheduling algorithms can also + * be implemented. */ class Executor { diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h index cc2ad079..d525efda 100644 --- a/livre/core/pipeline/Filter.h +++ b/livre/core/pipeline/Filter.h @@ -27,7 +27,7 @@ namespace livre /** * Filters are similar to functions ( immutable ). Their inputs and - * outputs are provided with given name and data types. In execution time + * outputs are provided with given name and data types. At execution time * values can be queried from the map of futures ( name - future pairs ) * and can be set through the map of promises ( name - promise pairs ) */ diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp index 82af96ff..32f1b54e 100644 --- a/livre/core/pipeline/Future.cpp +++ b/livre/core/pipeline/Future.cpp @@ -73,9 +73,10 @@ std::string Future::getName() const return _impl->getName(); } -Future Future::rename( const std::string& name ) const +Future::Future( const Future& future, const std::string& name ) + : _impl( future._impl ) { - return _impl->rename( name ); + _impl->_name = name; } void Future::wait() const @@ -88,6 +89,11 @@ bool Future::isReady() const return _impl->isReady(); } +bool Future::operator==( const Future& future ) const +{ + return &_impl->_data == &future._impl->_data; +} + const AsyncData& Future::_getAsyncData() const { return _impl->_data; diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h index f195120d..188ec4f9 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/Future.h @@ -29,16 +29,12 @@ namespace livre /** * The Future class is similar to the std::future classes in functionality and it has additional * information for the name and data type. It provides thread safe methods to query and get the - * data. Futures are retrieved from the @see Promise class. + * data. Futures are retrieved from the Promise class. */ class Future { public: - /** - * @param data holds the thread safe data (query/retrieve). - */ - Future( const AsyncData& data ); ~Future(); /** @@ -47,13 +43,13 @@ class Future std::string getName() const; /** - * Gets a shallow copy of the future with the given name + * Constructs a shallow copy of the future with the given name */ - Future rename( const std::string& name ) const; + Future( const Future& future, const std::string& name ); /** - * Gets the value with the given type T. If output is not set - * this function will block. + * Gets the value with the given type T. Blocks until data is + * available. * @return the value. * @throw std::runtime_error when the data is not exact * type T @@ -73,26 +69,24 @@ class Future /** * @param future is the future to be checked with - * @return true if both futures are same - */ - bool operator==( const Future& future ) const { return _impl == future._impl; } - - /** - * @param future is the future to be checked with - * @return true if implementation address is smaller than the other implementation address + * @return true if both futures are belonging to same promise */ - bool operator<( const Future& future ) const { return _impl.get() < future._impl.get(); } + bool operator==( const Future& future ) const; private: - friend bool livre::waitForAny( const Futures& future ); + friend class Promise; + Future( const AsyncData& data ); + + friend void waitForAny( const Futures& future ); + friend bool operator<( const Future& future1, const Future& future2 ); const AsyncData& _getAsyncData() const; template< class T > const T& _get() const { - const auto& dataPtr = + const auto dataPtr = std::static_pointer_cast< const PortDataT< T >>( _getPtr( getType< T >( ))); return dataPtr->data; @@ -104,6 +98,13 @@ class Future std::shared_ptr _impl; }; +/** + * Waits for any futures to be ready. If there are already ready futures, the function returns + * immediately. + * @param futures that is waited to be ready + */ +void waitForAny( const Futures& futures ); + } #endif // _Future_h_ diff --git a/livre/core/pipeline/FutureMap.cpp b/livre/core/pipeline/FutureMap.cpp index 10d4b667..dc5a7887 100644 --- a/livre/core/pipeline/FutureMap.cpp +++ b/livre/core/pipeline/FutureMap.cpp @@ -24,8 +24,14 @@ namespace livre { +namespace +{ + +const std::string ALL_FUTURES = "ALL_FUTURES"; + +} + typedef std::multimap< std::string, Future > NameFutureMap; -typedef std::pair< std::string, Future > NameFuturePair; struct FutureMapImpl { @@ -56,13 +62,10 @@ struct FutureMapImpl throwError( name ); Futures futures; - NameFutureMap::const_iterator it = _futureMap.find( name ); + const auto& itPair = _futureMap.equal_range( name ); - while( it != _futureMap.end( )) - { + for( auto it = itPair.first; it != itPair.second; ++it ) futures.push_back( it->second ); - ++it; - } return futures; } @@ -83,9 +86,9 @@ struct FutureMapImpl future.wait(); } - bool waitForAny( const std::string& name ) const + void waitForAny( const std::string& name ) const { - return livre::waitForAny( getFutures( name )); + livre::waitForAny( getFutures( name )); } void addFuture( const std::string& name, const Future& future ) @@ -122,9 +125,6 @@ Futures UniqueFutureMap::getFutures() const Future UniqueFutureMap::getFuture( const std::string& name ) const { - if( name == ALL_FUTURES ) - LBTHROW( std::runtime_error( "All futures cannot be retrieved with this function")) - return _impl->getFutures( name ).front(); } @@ -138,9 +138,9 @@ void UniqueFutureMap::wait( const std::string& name ) const _impl->wait( name ); } -bool UniqueFutureMap::waitForAny() const +void UniqueFutureMap::waitForAny() const { - return _impl->waitForAny( ALL_FUTURES ); + _impl->waitForAny( ALL_FUTURES ); } UniqueFutureMap::~UniqueFutureMap() @@ -167,19 +167,39 @@ Futures FutureMap::getFutures( const std::string& name ) const return _impl->getFutures( name ); } +Futures FutureMap::getFutures() const +{ + return _impl->getFutures( ALL_FUTURES ); +} + bool FutureMap::isReady( const std::string& name ) const { return _impl->isReady( name ); } +bool FutureMap::isReady() const +{ + return _impl->isReady( ALL_FUTURES ); +} + void FutureMap::wait( const std::string& name ) const { _impl->wait( name ); } -bool FutureMap::waitForAny( const std::string& name ) const +void FutureMap::wait() const +{ + _impl->wait( ALL_FUTURES ); +} + +void FutureMap::waitForAny( const std::string& name ) const +{ + _impl->waitForAny( name ); +} + +void FutureMap::waitForAny() const { - return _impl->waitForAny( name ); + _impl->waitForAny( ALL_FUTURES ); } FutureMap::~FutureMap() diff --git a/livre/core/pipeline/FutureMap.h b/livre/core/pipeline/FutureMap.h index c37c9dad..c3348a14 100644 --- a/livre/core/pipeline/FutureMap.h +++ b/livre/core/pipeline/FutureMap.h @@ -27,7 +27,17 @@ namespace livre { /** - * FutureMap is a wrapper class to query multiple futures with same names for data and data state. + * FutureMap is a wrapper class to query the map of ( name, future ) + * futures with for data and state. In the map there can be multiple futures + * with the same name. i.e. if there are multiple futures with the same name + * "x", the get() function will block until all the futures with name "x" are + * ready and get() will return a vector of results. + * + * Filters has named ports to communicate with other filters and those ports + * are communicated through promise/future couples. The futures are named + * with the port names and users can access those values using the port + * names in the futures. This class provides convenient functions for querying + * futures with port names. */ class FutureMap { @@ -41,18 +51,17 @@ class FutureMap ~FutureMap(); /** - * Gets the copy of value(s) with the given type T. If input - * is connected and values are not provided this function will - * block. + * Gets a copy of value(s) with the given type T. Until all + * futures with a given name are ready, this function will block. * @param name of the future. * @return the values of the futures. - * @throw std::runtime_error when the port data is not exact + * @throw std::runtime_error when the data is not exact * type T */ template< class T > - ResultsT< T > get( const std::string& name ) const + std::vector< T > get( const std::string& name ) const { - ResultsT< T > results; + std::vector< T > results; for( const auto& future: getFutures( name )) results.push_back( future.get< T >( )); @@ -63,13 +72,13 @@ class FutureMap * Gets the copy of ready value(s) with the given type T. * @param name of the future. * @return the values of the futures. - * @throw std::runtime_error when the port data is not exact + * @throw std::runtime_error when the data is not exact * type T */ template< class T > - ResultsT< T > getReady( const std::string& name ) const + std::vector< T > getReady( const std::string& name ) const { - ResultsT< T > results; + std::vector< T > results; for( const auto& future: getFutures( name )) { if( !future.isReady()) @@ -81,35 +90,62 @@ class FutureMap } /** - * @param name of the future. If name is ALL_FUTURES, all futures are marked to return. - * @return the futures associated with the name. + * @param name of the future. + * @return the futures with the given name + */ + Futures getFutures( const std::string& name ) const; + + /** + * @return the futures + */ + Futures getFutures() const; + + /** + * Queries if futures are ready with a given name + * @param name of the future. + * @return true if all futures with the given name are ready. + * @throw std::runtime_error when there is no future associated with the + * given name + */ + bool isReady( const std::string& name ) const; + + /** + * Queries if all futures are ready + * @return true if all futures are ready. + * @throw std::runtime_error when there is no future associated with the + * given name + */ + bool isReady() const; + + /** + * Waits all futures associated with a given name + * @param name of the future. + * @throw std::runtime_error when there is no future associated with the + * given name */ - Futures getFutures( const std::string& name = ALL_FUTURES ) const; + void wait( const std::string& name ) const; /** - * Queries if port is ready - * @param name of the future. If name is ALL_FUTURES, all futures are queried - * @return true if all port inputs are ready. + * Waits all futures * @throw std::runtime_error when there is no future associated with the * given name */ - bool isReady( const std::string& name = ALL_FUTURES ) const; + void wait() const; /** - * Waits all futures associated with port name - * @param name of the future. If name is ALL_FUTURES, all futures are waited. + * Waits all futures associated with a given name. + * @param name of the future. * @throw std::runtime_error when there is no future associated with the * given name */ - void wait( const std::string& name = ALL_FUTURES ) const; + void waitForAny( const std::string& name ) const; /** - * Waits all futures associated with port name. - * @param name of the future. If name is ALL_FUTURES, all futures are waited. + * Waits all futures. * @throw std::runtime_error when there is no future associated with the * given name */ - bool waitForAny( const std::string& name = ALL_FUTURES ) const; + void waitForAny() const; private: @@ -118,7 +154,9 @@ class FutureMap }; /** - * UniqueFutureMap is a wrapper class to query futures with unique names for data and data state. + * UniqueFutureMap is similar to the FutureMap but for each name there is + * a unique future. So that, the value can be retrieved directly for the given + * name. */ class UniqueFutureMap { @@ -126,7 +164,7 @@ class UniqueFutureMap /** * @param futures the list of futures. - * @throws std::runtime_error when futures are not unique in names + * @throw std::runtime_error when futures are not unique in names */ explicit UniqueFutureMap( const Futures& futures ); ~UniqueFutureMap(); @@ -137,7 +175,7 @@ class UniqueFutureMap * block. * @param name of the future. * @return the value for the future. - * @throw std::runtime_error when the port data is not exact + * @throw std::runtime_error when the data is not exact * type T */ template< class T > @@ -149,7 +187,6 @@ class UniqueFutureMap /** * @param name of the future * @return the future associated with the name. - * @throw std::runtime_error when the name is ALL_FUTURES */ Future getFuture( const std::string& name ) const; @@ -159,27 +196,41 @@ class UniqueFutureMap Futures getFutures() const; /** - * Queries if port is ready + * Queries if future is ready for a given name * @param name of the future + * @return true if all futures with the given name are ready. + * @throw std::runtime_error when there is no future associated with the + * given name + */ + bool isReady( const std::string& name ) const; + + /** + * Queries if future is ready for a given name * @return true if all futures are ready. * @throw std::runtime_error when there is no future associated with the * given name */ - bool isReady( const std::string& name = ALL_FUTURES ) const; + bool isReady() const; + + /** + * Waits for the future associated with a given name + * @param name is the name assoicated with futures. + * @throw std::runtime_error when there is no future associated with the + * given name + */ + void wait( const std::string& name ) const; /** - * Waits for the future associated with port name - * @param name is the port name assoicated with futures. + * Waits for all the futures * @throw std::runtime_error when there is no future associated with the * given name */ - void wait( const std::string& name = ALL_FUTURES ) const; + void wait() const; /** * Waits for any future to be ready. - * @return true if there are still futures which are not ready. */ - bool waitForAny() const; + void waitForAny() const; private: diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp index a9cd5e6b..f9c2bd92 100644 --- a/livre/core/pipeline/InputPort.cpp +++ b/livre/core/pipeline/InputPort.cpp @@ -59,16 +59,13 @@ struct InputPort::Impl bool disconnect( const OutputPort& port ) { - Futures::iterator it = _futures.begin(); - while( it != _futures.end()) - { - if( *it == port.getPromise().getFuture( )) - { - _futures.erase( it ); - return true; - } - ++it; - } + const auto& it = std::find( _futures.begin(), + _futures.end(), + port.getPromise().getFuture( )); + + if( it != _futures.end( )) + _futures.erase( it ); + return false; } diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index d1e106e1..f25f80f5 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -49,12 +49,12 @@ class InputPort std::type_index getDataType() const; /** - * @return the number of the inputs to the port + * @return the number of the connected outputs to the port */ size_t getSize() const; /** - * @return Return all the input futures that port has. + * @return Return all the futures this port has. */ const Futures& getFutures() const; diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp index 37d58e27..e6ab6905 100644 --- a/livre/core/pipeline/OutputPort.cpp +++ b/livre/core/pipeline/OutputPort.cpp @@ -66,10 +66,6 @@ OutputPort::OutputPort( const DataInfo& dataInfo ) OutputPort::~OutputPort() {} -OutputPort::OutputPort( OutputPort&& port ) - : _impl( std::move( port._impl )) -{} - std::string OutputPort::getName() const { return _impl->getName(); diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h index d124b1a3..7252ba63 100644 --- a/livre/core/pipeline/OutputPort.h +++ b/livre/core/pipeline/OutputPort.h @@ -26,7 +26,7 @@ namespace livre { /** - * Output connection for the @see PipeFilter. + * Output connection for the PipeFilter. */ class OutputPort { @@ -39,7 +39,6 @@ class OutputPort OutputPort( const DataInfo& dataInfo ); ~OutputPort(); - OutputPort( OutputPort&& port ); /** * @return name of the port */ diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index 7e8fc968..6ab3f62d 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -36,8 +36,8 @@ struct PipeFilter::Impl typedef std::map< std::string, InputPort > InputPortMap; Impl( PipeFilter& pipeFilter, - const std::string& name, - FilterPtr&& filter ) + const std::string& name, + FilterPtr filter ) : _pipeFilter( pipeFilter ) , _name( name ) , _filter( std::move( filter )) @@ -80,7 +80,7 @@ struct PipeFilter::Impl { const Futures& futures = pair.second.getFutures(); for( const auto& future: futures ) - inputFutures.push_back( future.rename( pair.second.getName( ))); + inputFutures.emplace_back( future, pair.second.getName( )); } const FutureMap futures( inputFutures ); @@ -188,7 +188,7 @@ struct PipeFilter::Impl }; PipeFilter::PipeFilter( const std::string& name, - FilterPtr&& filter ) + FilterPtr filter ) : _impl( new Impl( *this, name, std::move( filter ))) {} diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index d3d0f45f..fedb54c9 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -27,8 +27,10 @@ namespace livre { /** - * Responsible for execution of the @see Filter objects by constructing + * Responsible for execution of the Filter objects by constructing * the communication layer ( output ports, input ports ) around the filter. + * Accesing the copies of the object from other threads for non-const functions + * is not thread safe. */ class PipeFilter : public Executable { @@ -47,7 +49,7 @@ class PipeFilter : public Executable * @param srcPortName is the source pipe filter. * @param dst is the destination pipe filter. * @param dstPortName connection port name. - * @throws std::runtime_error if connection can not be established + * @throw std::runtime_error if connection can not be established */ void connect( const std::string& srcPortName, PipeFilter& dst, @@ -57,7 +59,7 @@ class PipeFilter : public Executable * @return promise for the given input port. If there is no connection to the * input port, a new promise is created for the port and no further connections are allowed, * if there is a connection getting a promise is not allowed. - * @throws std::runtime_error if there is already a connection or if there is + * @throw std::runtime_error if there is already a connection or if there is * no inputport or it is a noification port. */ Promise getPromise( const std::string& portName ); @@ -90,7 +92,7 @@ class PipeFilter : public Executable * @param filter the filter object. */ PipeFilter( const std::string& name, - FilterPtr&& filter ); + FilterPtr filter ); private: diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index cae06278..cf2f073f 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -28,7 +28,8 @@ namespace livre { /** - * Implements the executable graph. + * Implements the executable graph. Accesing the copies of the object from + * other threads for non-const functions is not thread safe. */ class Pipeline : public Executable { @@ -61,7 +62,7 @@ class Pipeline : public Executable * @param wait If true, on scheduled execution, pipeline * can wait on the post conditions of the pipefilter. * @return returns the generated pipe filter. - * @throws std::runtime_error if an executable with same name is present + * @throw std::runtime_error if an executable with same name is present */ template< class FilterT, bool wait = true, class... Args > @@ -76,7 +77,7 @@ class Pipeline : public Executable /** * @param name of the executable * @return the executable - * @throws std::runtime_error if a pipe filter or pipeline does not exist + * @throw std::runtime_error if a pipe filter or pipeline does not exist */ const Executable& getExecutable( const std::string& name ) const; diff --git a/livre/core/pipeline/PortData.h b/livre/core/pipeline/PortData.h index e6721684..259fc9a9 100644 --- a/livre/core/pipeline/PortData.h +++ b/livre/core/pipeline/PortData.h @@ -55,15 +55,11 @@ struct PortDataT final : public PortData , data( data_ ) {} - explicit PortDataT( const T&& data_ ) - : PortData( getType< T >( )) - , data( std::move( data_ )) - {} - ~PortDataT() {} const T data; PortDataT( const PortDataT< T >& ) = delete; + PortDataT( PortDataT< T >&& ) = delete; PortDataT< T >& operator=( const PortDataT< T >& ) = delete; }; diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp index 38e787e0..7f582858 100644 --- a/livre/core/pipeline/Promise.cpp +++ b/livre/core/pipeline/Promise.cpp @@ -53,7 +53,12 @@ struct Promise::Impl void flush() { - _data.set( PortDataPtr( )); + try + { + _data.set( PortDataPtr( )); + } + catch( const std::runtime_error& ) + {} } AsyncData _data; @@ -92,7 +97,7 @@ void Promise::reset() _impl->reset(); } -void Promise::_set( const PortDataPtr& data ) +void Promise::_set( PortDataPtr data ) { _impl->set( data ); } diff --git a/livre/core/pipeline/Promise.h b/livre/core/pipeline/Promise.h index cbb663ff..ecf23dff 100644 --- a/livre/core/pipeline/Promise.h +++ b/livre/core/pipeline/Promise.h @@ -64,18 +64,6 @@ class Promise _set( std::make_shared< PortDataT< T >>( value )); } - /** - * Sets the port with the value. - * @param value to be set - * @throw std::runtime_error when the port data is not exact - * type T or there is no such port name. - */ - template< class T > - void set( const T&& value ) - { - _set( std::make_shared< PortDataT< T >>( value )); - } - /** * Sets the promise with empty data if it is not set already */ @@ -95,7 +83,7 @@ class Promise private: - void _set( const PortDataPtr& data ); + void _set( PortDataPtr data ); struct Impl; std::shared_ptr _impl; diff --git a/livre/core/pipeline/PromiseMap.cpp b/livre/core/pipeline/PromiseMap.cpp index ce0b5928..8f9e183b 100644 --- a/livre/core/pipeline/PromiseMap.cpp +++ b/livre/core/pipeline/PromiseMap.cpp @@ -23,6 +23,13 @@ namespace livre { +namespace +{ + +const std::string ALL_PROMISES = "ALL_PROMISES"; + +} + typedef std::map< std::string, Promise > NamePromiseMap; typedef NamePromiseMap::value_type NamePromisePair; @@ -82,6 +89,11 @@ void PromiseMap::flush( const std::string& name /* = ALL_PROMISES */ ) const _impl->flush( name ); } +void PromiseMap::flush() const +{ + _impl->flush( ALL_PROMISES ); +} + Promise PromiseMap::getPromise( const std::string& name ) const { return _impl->getPromise( name ); diff --git a/livre/core/pipeline/PromiseMap.h b/livre/core/pipeline/PromiseMap.h index 8b4a20da..e1c55a20 100644 --- a/livre/core/pipeline/PromiseMap.h +++ b/livre/core/pipeline/PromiseMap.h @@ -27,7 +27,8 @@ namespace livre { /** - * Wrapper class for applying operations on the @Promise objects. + * Wrapper class for applying operations on map of @Promise objects. i.e a promise with + * the name can be set. */ class PromiseMap { @@ -57,25 +58,17 @@ class PromiseMap } /** - * Sets the port with the value. - * @param name of the promise - * @param value to be set - * @throw std::runtime_error when the port data is not exact - * type T or there is no such port name. + * Writes empty values to promises which are not set already. + * @param name of the promise. + * @throw std::runtime_error there is no such port name. */ - template< class T > - void set( const std::string& name, const T&& value ) const - { - getPromise( name ).set( value ); - } + void flush( const std::string& name ) const; /** * Writes empty values to promises which are not set already. - * @param name of the promise. If ALL_PROMISES is given, - * all promises will be flushed * @throw std::runtime_error there is no such port name. */ - void flush( const std::string& name = ALL_PROMISES ) const; + void flush() const; private: diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp index 25f711d6..2d085be8 100644 --- a/livre/core/pipeline/SimpleExecutor.cpp +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -42,6 +42,11 @@ namespace livre { +bool operator<( const Future& future1, const Future& future2 ) +{ + return future1._impl.get() < future2._impl.get(); +} + struct SimpleExecutor::Impl { diff --git a/livre/core/types.h b/livre/core/types.h index 381c8b1a..5bf941fb 100644 --- a/livre/core/types.h +++ b/livre/core/types.h @@ -196,9 +196,6 @@ typedef std::list< Executable* > Executables; typedef std::list< Future > Futures; typedef std::list< Promise > Promises; -template < class T > -using ResultsT = std::vector< T >; - /** * Map definitions */ @@ -246,9 +243,9 @@ const Identifier INVALID_CACHE_ID = -1; //!< Invalid cache id. const Identifier INVALID_NODE_ID = -1; //!< Invalid node ID. const uint32_t MAX_CHILDREN_BITS = 4; //!< Maximum number of children is 16 -const uint32_t NODEID_LEVEL_BITS = 4; //>! @see NodeId -const uint32_t NODEID_BLOCK_BITS = 14; //>! @see NodeId -const uint32_t NODEID_FRAME_BITS = 18; //>! @see NodeId +const uint32_t NODEID_LEVEL_BITS = 4; //>! NodeId +const uint32_t NODEID_BLOCK_BITS = 14; //>! NodeId +const uint32_t NODEID_FRAME_BITS = 18; //>! NodeId const uint32_t INVALID_POSITION = ( 1u << NODEID_BLOCK_BITS ) - 1; //!< Invalid node ID. const uint32_t INVALID_LEVEL = ( 1u << NODEID_LEVEL_BITS ) - 1; //!< Invalid tree level.4 bits is on @@ -266,8 +263,6 @@ typedef std::map< std::string, // Const definitions static const std::string HIDDEN_PROGRAMDESCRIPTION_STR("_HIDDEN_"); static const std::string NO_PREFIX = ""; -static const std::string ALL_FUTURES = ""; -static const std::string ALL_PROMISES = ""; } diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index 86edb322..ff4bb50a 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -59,7 +59,7 @@ class TestFilter : public livre::Filter { void execute( const livre::FutureMap& input, livre::PromiseMap& output ) const final { - const livre::ResultsT< InputData >& results = input.get< InputData >( "TestInputData" ); + const std::vector< InputData >& results = input.get< InputData >( "TestInputData" ); OutputData outputData; for( const auto& data: results ) @@ -92,7 +92,7 @@ class ConvertFilter : public livre::Filter { void execute( const livre::FutureMap& input, livre::PromiseMap& output ) const final { - const livre::ResultsT< OutputData >& results = input.get< OutputData >( "ConvertInputData" ); + const std::vector< OutputData >& results = input.get< OutputData >( "ConvertInputData" ); InputData inputData; for( const auto& data: results ) From d2ac3310ffc05b572cc55be9b0f66771520eba13 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Thu, 24 Mar 2016 11:59:33 +0100 Subject: [PATCH 08/17] Fixes for the comments --- livre/core/pipeline/FutureMap.cpp | 4 +-- livre/core/pipeline/PipeFilter.cpp | 41 +++++++++++++++--------------- livre/core/pipeline/Pipeline.cpp | 30 +++++++++++----------- livre/core/pipeline/Pipeline.h | 16 +++++++----- livre/core/pipeline/PromiseMap.cpp | 6 ++--- livre/core/pipeline/Workers.cpp | 1 + livre/core/pipeline/Workers.h | 1 - 7 files changed, 51 insertions(+), 48 deletions(-) diff --git a/livre/core/pipeline/FutureMap.cpp b/livre/core/pipeline/FutureMap.cpp index dc5a7887..8446091d 100644 --- a/livre/core/pipeline/FutureMap.cpp +++ b/livre/core/pipeline/FutureMap.cpp @@ -53,8 +53,8 @@ struct FutureMapImpl if( name == ALL_FUTURES ) { Futures futures; - for( const auto& pair: _futureMap ) - futures.push_back( pair.second ); + for( const auto& nameFuture: _futureMap ) + futures.push_back( nameFuture.second ); return futures; } diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index 6ab3f62d..d4d3a5c8 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -76,11 +76,11 @@ struct PipeFilter::Impl void execute() { Futures inputFutures; - for( const auto& pair: _inputMap ) + for( const auto& namePort: _inputMap ) { - const Futures& futures = pair.second.getFutures(); + const Futures& futures = namePort.second.getFutures(); for( const auto& future: futures ) - inputFutures.emplace_back( future, pair.second.getName( )); + inputFutures.emplace_back( future, namePort.second.getName( )); } const FutureMap futures( inputFutures ); @@ -100,29 +100,28 @@ struct PipeFilter::Impl Promise getInputPromise( const std::string& portName ) { - if( !hasInputPort( portName )) + if( !hasInputPort( portName )) throwPortError( portName ); - if( _manuallySetPortsMap.count( portName ) > 0 ) - return _manuallySetPortsMap.find( portName )->second.getPromise(); + const auto& itPromise = _manuallySetPortsMap.find( portName ); + if( itPromise != _manuallySetPortsMap.end( )) + return itPromise->second.getPromise(); InputPort& inputPort = _inputMap.find( portName )->second; - - _manuallySetPortsMap.emplace( std::piecewise_construct, + const auto& itPort = _manuallySetPortsMap.emplace( std::piecewise_construct, std::forward_as_tuple( inputPort.getName( )), std::forward_as_tuple( DataInfo( inputPort.getName(), inputPort.getDataType( )))); - OutputPort& outputPort = _manuallySetPortsMap.find( inputPort.getName( ))->second; - + OutputPort& outputPort = itPort.first->second; inputPort.connect( outputPort ); - return _manuallySetPortsMap.find( portName )->second.getPromise(); + return outputPort.getPromise(); } Promises getOutputPromises() const { Promises promises; - for( const auto& pair: _outputMap ) - promises.push_back( pair.second.getPromise( )); + for( const auto& namePort: _outputMap ) + promises.push_back( namePort.second.getPromise( )); return promises; } @@ -130,9 +129,9 @@ struct PipeFilter::Impl Futures getPostconditions() const { Futures futures; - for( const auto& pair: _outputMap ) + for( const auto& namePort: _outputMap ) { - const Future& outputFuture = pair.second.getPromise().getFuture(); + const Future& outputFuture = namePort.second.getPromise().getFuture(); futures.push_back( outputFuture ); } return futures; @@ -141,9 +140,9 @@ struct PipeFilter::Impl Futures getPreconditions() const { Futures futures; - for( const auto& pair: _inputMap ) + for( const auto& namePort: _inputMap ) { - const Futures& inputFutures = pair.second.getFutures(); + const Futures& inputFutures = namePort.second.getFutures(); futures.insert( futures.end(), inputFutures.begin(), inputFutures.end( )); } return futures; @@ -171,12 +170,12 @@ struct PipeFilter::Impl void reset() { - for( auto& pair: _manuallySetPortsMap ) - _inputMap.find( pair.first )->second.disconnect( pair.second ); + for( auto& namePort: _manuallySetPortsMap ) + _inputMap.find( namePort.first )->second.disconnect( namePort.second ); _manuallySetPortsMap.clear(); - for( auto& pair: _outputMap ) - pair.second.reset(); + for( auto& namePort: _outputMap ) + namePort.second.reset(); } PipeFilter& _pipeFilter; diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp index e8e1b51d..879bd07a 100644 --- a/livre/core/pipeline/Pipeline.cpp +++ b/livre/core/pipeline/Pipeline.cpp @@ -35,21 +35,21 @@ struct Pipeline::Impl {} void add( const std::string& name, - Executable* executable, + Pipeline::ExecutablePtr executable, bool wait ) { if( _executableMap.count( name ) > 0 ) LBTHROW( std::runtime_error( name + " already exists")); - _executableMap.emplace( std::piecewise_construct, - std::forward_as_tuple( name ), - std::forward_as_tuple( executable )); - if( wait ) { const Futures& futures = executable->getPostconditions(); _outFutures.insert( _outFutures.end(), futures.begin(), futures.end( )); } + + _executableMap.emplace( std::piecewise_construct, + std::forward_as_tuple( name ), + std::forward_as_tuple( std::move( executable ))); } void execute() @@ -79,8 +79,8 @@ struct Pipeline::Impl { Executables executables; - for( auto& pair: _executableMap ) - executables.push_back( pair.second.get( )); + for( auto& nameExec: _executableMap ) + executables.push_back( nameExec.second.get( )); return executables; } @@ -96,9 +96,9 @@ struct Pipeline::Impl Futures getPreconditions() const { Futures inFutures; - for( auto& pair: _executableMap ) + for( auto& nameExec: _executableMap ) { - const Futures& futures = pair.second->getPreconditions(); + const Futures& futures = nameExec.second->getPreconditions(); inFutures.insert( inFutures.end(), futures.begin(), futures.end( )); } return inFutures; @@ -111,14 +111,14 @@ struct Pipeline::Impl void schedule( Executor& executor ) { - for( auto& pair: _executableMap ) - executor.schedule( *pair.second ); + for( auto& nameExec: _executableMap ) + executor.schedule( *nameExec.second ); } void reset() { - for( auto& pair: _executableMap ) - pair.second->reset(); + for( auto& nameExec: _executableMap ) + nameExec.second->reset(); } Pipeline& _pipeline; @@ -135,10 +135,10 @@ Pipeline::~Pipeline() {} void Pipeline::_add( const std::string& name, - Executable* exec, + ExecutablePtr exec, bool wait ) { - _impl->add( name, exec, wait ); + _impl->add( name, std::move( exec ), wait ); } const Executable& Pipeline::getExecutable( const std::string& name ) const diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index cf2f073f..d46e7b2b 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -36,6 +36,8 @@ class Pipeline : public Executable public: + typedef std::unique_ptr< Executable > ExecutablePtr; + Pipeline(); ~Pipeline(); @@ -50,7 +52,7 @@ class Pipeline : public Executable bool wait = true ) { _add( name, - new Pipeline( pipeline ), + ExecutablePtr( new Pipeline( pipeline )), wait ); } @@ -69,9 +71,11 @@ class Pipeline : public Executable PipeFilter add( const std::string& name, Args&&... args ) { - PipeFilter* pipeFilter = new PipeFilterT< FilterT >( name, args... ); - _add( name, pipeFilter, wait ); - return *pipeFilter; + PipeFilterT< FilterT > pipeFilter( name, args... ); + _add( name, + ExecutablePtr( new PipeFilter( pipeFilter )), + wait ); + return pipeFilter; } /** @@ -104,8 +108,8 @@ class Pipeline : public Executable private: void _add( const std::string& name, - Executable* exec, - bool wait ); + ExecutablePtr exec, + bool wait ); private: void _schedule( Executor& executor ) final; diff --git a/livre/core/pipeline/PromiseMap.cpp b/livre/core/pipeline/PromiseMap.cpp index 8f9e183b..7da62a83 100644 --- a/livre/core/pipeline/PromiseMap.cpp +++ b/livre/core/pipeline/PromiseMap.cpp @@ -58,9 +58,9 @@ struct PromiseMap::Impl if( name != ALL_PROMISES && !hasPromise( name )) throwError( name ); - for( const NamePromisePair& pair: _promiseMap ) + for( const NamePromisePair& namePromise: _promiseMap ) { - Promise promise = pair.second; + Promise promise = namePromise.second; if( name == ALL_PROMISES || promise.getName() == name ) promise.flush(); } @@ -84,7 +84,7 @@ PromiseMap::PromiseMap( const Promises& promises ) PromiseMap::~PromiseMap() {} -void PromiseMap::flush( const std::string& name /* = ALL_PROMISES */ ) const +void PromiseMap::flush( const std::string& name ) const { _impl->flush( name ); } diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp index 435147d5..06914b39 100644 --- a/livre/core/pipeline/Workers.cpp +++ b/livre/core/pipeline/Workers.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index 78249bb4..a57a28bb 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -21,7 +21,6 @@ #define _Workers_h_ #include -#include namespace livre { From 49bd4474b3b1e62458db831f94101fc1c06ed3fc Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Wed, 30 Mar 2016 11:02:35 +0200 Subject: [PATCH 09/17] Fixed according to comments --- livre/core/pipeline/AsyncData.cpp | 11 +-- livre/core/pipeline/AsyncData.h | 11 +-- livre/core/pipeline/Future.cpp | 11 +-- livre/core/pipeline/InputPort.h | 2 +- livre/core/pipeline/PipeFilter.cpp | 2 +- livre/core/pipeline/PipeFilter.h | 2 +- livre/core/pipeline/Promise.cpp | 6 +- livre/core/pipeline/PromiseMap.cpp | 13 ++-- livre/core/pipeline/SimpleExecutor.cpp | 101 +++++++++++-------------- livre/core/pipeline/SimpleExecutor.h | 16 ++-- livre/core/pipeline/Workers.cpp | 7 +- livre/core/pipeline/Workers.h | 6 +- livre/core/render/GLContext.h | 5 -- livre/core/types.h | 11 ++- livre/eq/render/EqContext.cpp | 13 +--- livre/eq/render/EqContext.h | 7 +- 16 files changed, 91 insertions(+), 133 deletions(-) diff --git a/livre/core/pipeline/AsyncData.cpp b/livre/core/pipeline/AsyncData.cpp index e928f6e5..aadaf62d 100644 --- a/livre/core/pipeline/AsyncData.cpp +++ b/livre/core/pipeline/AsyncData.cpp @@ -90,13 +90,6 @@ struct AsyncData::Impl _future.wait(); } - void reset() - { - ConstPortDataPromise newPromise; - _promise.swap( newPromise ); - _future = _promise.get_future(); - } - ConstPortDataPromise _promise; mutable ConstPortDataFuture _future; const DataInfo _dataInfo; @@ -139,9 +132,9 @@ void AsyncData::wait() const _impl->wait(); } -void AsyncData::reset() +bool AsyncData::operator==( const AsyncData& asyncData ) { - _impl->reset(); + return &_impl->_promise == &asyncData._impl->_promise; } void waitForAny( const Futures& futures ) diff --git a/livre/core/pipeline/AsyncData.h b/livre/core/pipeline/AsyncData.h index d75520e6..77856a8d 100644 --- a/livre/core/pipeline/AsyncData.h +++ b/livre/core/pipeline/AsyncData.h @@ -78,20 +78,17 @@ class AsyncData void wait() const; /** - * Resets the promise/future. This function should not be called when - * threads are blocked on wait() + * @param asyncData to be compared with + * @return true if both async data are same */ - void reset(); + bool operator==( const AsyncData& asyncData ); private: friend void waitForAny( const Futures& futures ); - AsyncData( const AsyncData& ) = delete; - AsyncData& operator=( const AsyncData& ) = delete; - struct Impl; - std::unique_ptr _impl; + std::shared_ptr _impl; }; } diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp index 32f1b54e..5b0e9cc4 100644 --- a/livre/core/pipeline/Future.cpp +++ b/livre/core/pipeline/Future.cpp @@ -30,13 +30,6 @@ struct Future::Impl , _data( data ) {} - Future rename( const std::string& name ) const - { - Future ret( _data ); - ret._impl->_name = name; - return ret; - } - std::string getName() const { return _name; @@ -58,7 +51,7 @@ struct Future::Impl } std::string _name; - const AsyncData& _data; + AsyncData _data; }; Future::Future( const AsyncData& data ) @@ -91,7 +84,7 @@ bool Future::isReady() const bool Future::operator==( const Future& future ) const { - return &_impl->_data == &future._impl->_data; + return _impl->_data == future._impl->_data; } const AsyncData& Future::_getAsyncData() const diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index f25f80f5..b21a7868 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -26,7 +26,7 @@ namespace livre { /** - * Input connection for the @see PipeFilter. + * Input connection for the PipeFilter. */ class InputPort { diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index d4d3a5c8..0caf7372 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -187,7 +187,7 @@ struct PipeFilter::Impl }; PipeFilter::PipeFilter( const std::string& name, - FilterPtr filter ) + FilterPtr&& filter ) : _impl( new Impl( *this, name, std::move( filter ))) {} diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index fedb54c9..b41b951f 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -92,7 +92,7 @@ class PipeFilter : public Executable * @param filter the filter object. */ PipeFilter( const std::string& name, - FilterPtr filter ); + FilterPtr&& filter ); private: diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp index 7f582858..8bdb7e48 100644 --- a/livre/core/pipeline/Promise.cpp +++ b/livre/core/pipeline/Promise.cpp @@ -48,7 +48,9 @@ struct Promise::Impl void reset() { - _data.reset(); + flush(); + _data = AsyncData( DataInfo( _data.getName(), _data.getDataType( ))); + _future = Future( _data ); } void flush() @@ -62,7 +64,7 @@ struct Promise::Impl } AsyncData _data; - const Future _future; + Future _future; }; Promise::Promise( const DataInfo& dataInfo ) diff --git a/livre/core/pipeline/PromiseMap.cpp b/livre/core/pipeline/PromiseMap.cpp index 7da62a83..c2bdd67f 100644 --- a/livre/core/pipeline/PromiseMap.cpp +++ b/livre/core/pipeline/PromiseMap.cpp @@ -55,14 +55,15 @@ struct PromiseMap::Impl void flush( const std::string& name ) const { - if( name != ALL_PROMISES && !hasPromise( name )) - throwError( name ); + getPromise( name ).flush(); + } - for( const NamePromisePair& namePromise: _promiseMap ) + void flush() const + { + for( auto& namePromise: _promiseMap ) { Promise promise = namePromise.second; - if( name == ALL_PROMISES || promise.getName() == name ) - promise.flush(); + promise.flush(); } } @@ -91,7 +92,7 @@ void PromiseMap::flush( const std::string& name ) const void PromiseMap::flush() const { - _impl->flush( ALL_PROMISES ); + _impl->flush(); } Promise PromiseMap::getPromise( const std::string& name ) const diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp index 2d085be8..6f39aaff 100644 --- a/livre/core/pipeline/SimpleExecutor.cpp +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -50,85 +50,70 @@ bool operator<( const Future& future1, const Future& future2 ) struct SimpleExecutor::Impl { - Impl( const size_t threadCount ) - : _workThread( boost::thread( boost::bind( &Impl::schedule, this ))) - , _workers( threadCount ) + Impl( const size_t threadCount, GLContextPtr glContext ) + : _workers( threadCount, glContext ) , _unlockPromise( DataInfo( "LoopUnlock", getType< bool >( ))) + , _workThread( boost::thread( boost::bind( &Impl::schedule, this ))) {} ~Impl() { _mtWorkQueue.clear(); _mtWorkQueue.push( 0 ); + { + ScopedLock lock( _promiseReset ); + _unlockPromise.set( true ); + } _workThread.join(); } void schedule() { - std::set< Future > inputConditions; - std::set< Future > outputConditions; - + std::set< Future > inputConditions = { _unlockPromise.getFuture() }; + Executables executables; while( true ) { - Executables executables; - Executable* executable = _mtWorkQueue.pop(); - if( !executable ) - return; + const Futures inputConds( inputConditions.begin(), inputConditions.end( )); + waitForAny( inputConds ); - executables.push_back( executable ); + { + ScopedLock lock( _promiseReset ); + if( _unlockPromise.getFuture( ).isReady( )) + { + while( !_mtWorkQueue.empty( )) + { + Executable* exec = _mtWorkQueue.pop(); + if( !exec ) + return; + + executables.push_back( exec ); + } - for( const Executable* exec: executables ) - for( const Future& future: exec->getPreconditions( )) - inputConditions.insert( future ); + inputConditions.erase( _unlockPromise.getFuture( )); + _unlockPromise.reset(); + inputConditions.insert( _unlockPromise.getFuture( )); + + } + } Executables::iterator it = executables.begin(); while( it != executables.end( )) { - Executable* exec = *it; - const FutureMap futureMap( exec->getPreconditions( )); + Executable* executable = *it; + const Futures& preConds = executable->getPreconditions(); + const FutureMap futureMap( preConds ); if( futureMap.isReady( )) { - _workers.execute( *exec ); + _workers.schedule( *executable ); it = executables.erase( it ); - - for( const Future& future: exec->getPostconditions( )) - outputConditions.insert( future ); - - for( const Future& future: exec->getPreconditions( )) + for( const auto& future: futureMap.getFutures( )) inputConditions.erase( future ); } else + { ++it; - } - - Futures intersection; - std::set_intersection( outputConditions.begin(), outputConditions.end(), - inputConditions.begin(), inputConditions.end(), - std::back_inserter( intersection )); - - // Wait only for the futures where executed output conditions - // executables intersects - if( !intersection.empty( )) - { - FutureMap futureMap( intersection ); - futureMap.waitForAny(); - } - - // Add left over executables back to queue - for( Executable* exec: executables ) - _mtWorkQueue.push( exec ); - - FutureMap futureMap( intersection ); - futureMap.waitForAny(); - - std::set< Future >::iterator itFuture = outputConditions.begin(); - while( itFuture != outputConditions.end( )) - { - const Future& future = *itFuture; - if( future.isReady( )) - itFuture = outputConditions.erase( itFuture ); - else - ++itFuture; + inputConditions.insert( preConds.begin(), preConds.end( )); + } } } } @@ -140,18 +125,22 @@ struct SimpleExecutor::Impl void schedule( Executable& exec ) { - _mtWorkQueue.push( &exec ); + const bool wasEmpty = _mtWorkQueue.empty(); + _mtWorkQueue.push_back( &exec ); + ScopedLock lock( _promiseReset ); + if( wasEmpty ) + _unlockPromise.set( true ); } lunchbox::MTQueue< Executable* > _mtWorkQueue; - boost::thread _workThread; Workers _workers; Promise _unlockPromise; boost::mutex _promiseReset; + boost::thread _workThread; }; -SimpleExecutor::SimpleExecutor( const size_t threadCount ) - : _impl( new Impl( threadCount )) +SimpleExecutor::SimpleExecutor( const size_t threadCount, GLContextPtr glContext ) + : _impl( new Impl( threadCount, glContext )) { } diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h index 9cb5ca6c..e5179ce2 100644 --- a/livre/core/pipeline/SimpleExecutor.h +++ b/livre/core/pipeline/SimpleExecutor.h @@ -27,23 +27,25 @@ namespace livre { /** - * Provides a very basic implementation for the @see Executor + * Provides a very basic implementation for the Executor * class. It has a thread pool for executing multiple executables * asynchronously. * - * The submitted executables are queued for the worker threads, + * The submitted executables are scheduled to the worker threads, * by looking at the preconditions if they are satisfied. */ - class SimpleExecutor : public Executor { public: /** - * @param threadCount number of workers are thread pools that executes individual - * executables ( PipeFilter, Pipeline ) + * @param threadCount is number of worker threads + * @param glContext if a gl context is provided, a new context will be created and + * the worker threads will share the context with the given context */ - explicit SimpleExecutor( size_t threadCount ); + SimpleExecutor( size_t threadCount, + GLContextPtr glContext = GLContextPtr( )); + virtual ~SimpleExecutor(); /** @@ -52,7 +54,7 @@ class SimpleExecutor : public Executor void schedule( Executable& executable ) final; /** - * @copydoc Executor::clear() + * @copydoc Executor::clear */ void clear() final; diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp index 06914b39..d2fc50b6 100644 --- a/livre/core/pipeline/Workers.cpp +++ b/livre/core/pipeline/Workers.cpp @@ -39,15 +39,14 @@ struct Workers::Impl for( size_t i = 0; i < nThreads; ++i ) _threadGroup.create_thread( boost::bind( &Impl::execute, this )); - } void execute() { if( _glContext ) { - GLContextPtr context = _glContext->createContext(); - _glContext->shareContext( context ); + GLContextPtr context = _glContext->clone(); + context->share( *_glContext ); context->makeCurrent(); } @@ -95,7 +94,7 @@ Workers::Workers( const size_t nThreads, Workers::~Workers() {} -void Workers::execute( Executable& executable ) +void Workers::schedule( Executable& executable ) { _impl->submitWork( executable ); } diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index a57a28bb..841e2e60 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -43,11 +43,11 @@ class Workers ~Workers(); /** - * Submitted executable is executed by the available - * threads. + * Submitted executable is scheduled to the execution + * queue. * @param executable is executed by thread pool. */ - void execute( Executable& executable ); + void schedule( Executable& executable ); /** * @return the size of thread pool. diff --git a/livre/core/render/GLContext.h b/livre/core/render/GLContext.h index a616e60a..2b0da5b4 100644 --- a/livre/core/render/GLContext.h +++ b/livre/core/render/GLContext.h @@ -47,11 +47,6 @@ class GLContext */ virtual GLContextPtr clone() const = 0; - /** - * @return a similar context. - */ - virtual GLContextPtr createContext() const = 0; - /** * Makes the context current. */ diff --git a/livre/core/types.h b/livre/core/types.h index 5bf941fb..e17d84f1 100644 --- a/livre/core/types.h +++ b/livre/core/types.h @@ -187,11 +187,14 @@ typedef std::vector< NodeId > NodeIds; typedef std::vector< CacheId > CacheIds; /** - * Vector/list definitions for complex types + * Vector definitions for complex types */ typedef std::vector< CacheObjectPtr > CacheObjects; typedef std::vector< ConstCacheObjectPtr > ConstCacheObjects; +/** + * List definitions for complex types + */ typedef std::list< Executable* > Executables; typedef std::list< Future > Futures; typedef std::list< Promise > Promises; @@ -243,9 +246,9 @@ const Identifier INVALID_CACHE_ID = -1; //!< Invalid cache id. const Identifier INVALID_NODE_ID = -1; //!< Invalid node ID. const uint32_t MAX_CHILDREN_BITS = 4; //!< Maximum number of children is 16 -const uint32_t NODEID_LEVEL_BITS = 4; //>! NodeId -const uint32_t NODEID_BLOCK_BITS = 14; //>! NodeId -const uint32_t NODEID_FRAME_BITS = 18; //>! NodeId +const uint32_t NODEID_LEVEL_BITS = 4; //>! see NodeId +const uint32_t NODEID_BLOCK_BITS = 14; //>! see NodeId +const uint32_t NODEID_FRAME_BITS = 18; //>! see NodeId const uint32_t INVALID_POSITION = ( 1u << NODEID_BLOCK_BITS ) - 1; //!< Invalid node ID. const uint32_t INVALID_LEVEL = ( 1u << NODEID_LEVEL_BITS ) - 1; //!< Invalid tree level.4 bits is on diff --git a/livre/eq/render/EqContext.cpp b/livre/eq/render/EqContext.cpp index 11d1ad92..db769667 100644 --- a/livre/eq/render/EqContext.cpp +++ b/livre/eq/render/EqContext.cpp @@ -37,18 +37,7 @@ EqContext::~EqContext() delete _systemWindow; } -GLContextPtr EqContext::createContext() const -{ - return GLContextPtr( new EqContext( window_ )); -} - -void EqContext::makeCurrent() -{ - if( systemWindow_ ) - systemWindow_->makeCurrent(); -} - -void EqContext::doneCurrent() +void EqContext::share( const GLContext& src ) { LBASSERT( _window ); diff --git a/livre/eq/render/EqContext.h b/livre/eq/render/EqContext.h index fca62e01..34983e59 100644 --- a/livre/eq/render/EqContext.h +++ b/livre/eq/render/EqContext.h @@ -42,12 +42,7 @@ class EqContext : public GLContext ~EqContext(); /** - * @return a similar context - */ - GLContextPtr createContext() const final; - - /** - * Makes the context, current. + * @copydoc GLContext::share */ void share( const GLContext& src ) final; From beec9b727f5ce173436521ba89887d48d095e029 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Wed, 30 Mar 2016 11:33:18 +0200 Subject: [PATCH 10/17] Added more tests for futures and promises --- livre/core/pipeline/Future.h | 6 ++++++ tests/pipeline/pipeline.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/Future.h index 188ec4f9..99e50ea1 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/Future.h @@ -73,6 +73,12 @@ class Future */ bool operator==( const Future& future ) const; + /** + * @param future is the future to be checked with + * @return true if both futures are belonging to different promise + */ + bool operator!=( const Future& future ) const { return !(*this == future); } + private: friend class Promise; diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index ff4bb50a..9cf33c1f 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -309,6 +309,36 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) } } +BOOST_AUTO_TEST_CASE( testPromiseFuture ) +{ + livre::Promise promise( livre::DataInfo( "Helloworld", livre::getType< uint32_t >( ))); + livre::Future future1 = promise.getFuture(); + livre::Future future2 = promise.getFuture(); + BOOST_CHECK( future1 == future2 ); + + // Promise only be set with the right type + BOOST_CHECK_EXCEPTION( promise.set( 12.0f );, + std::runtime_error, check_error ); + + promise.set( 42u ); + BOOST_CHECK_EQUAL( future1.get< uint32_t >(), 42u ); + BOOST_CHECK_EQUAL( future2.get< uint32_t >(), 42u ); + + // Promise only can be set once + BOOST_CHECK_EXCEPTION( promise.set( 42u );, + std::runtime_error, check_error ); + + promise.reset(); + livre::Future future3 = promise.getFuture(); + BOOST_CHECK( future1 != future3 ); + BOOST_CHECK_EQUAL( future1.get< uint32_t >(), 42u ); + + // Promise is set with explicit conversion + promise.set< uint32_t >( 43.0f ); + + BOOST_CHECK_EQUAL( future3.get< uint32_t >(), 43u ); +} + BOOST_AUTO_TEST_CASE( testFutureMaps ) { livre::PipeFilterT< TestFilter > pipeFilter( "Producer" ); From d0396ae2b2171fb305c4546b0863cb12ac6d7ded Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Wed, 30 Mar 2016 15:31:58 +0200 Subject: [PATCH 11/17] Fixes according to comments --- livre/core/pipeline/SimpleExecutor.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp index 6f39aaff..a543876d 100644 --- a/livre/core/pipeline/SimpleExecutor.cpp +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -73,20 +73,22 @@ struct SimpleExecutor::Impl Executables executables; while( true ) { - const Futures inputConds( inputConditions.begin(), inputConditions.end( )); - waitForAny( inputConds ); - + waitForAny( Futures( inputConditions.begin(), inputConditions.end( ))); { ScopedLock lock( _promiseReset ); - if( _unlockPromise.getFuture( ).isReady( )) + if( _unlockPromise.getFuture().isReady( )) { while( !_mtWorkQueue.empty( )) { Executable* exec = _mtWorkQueue.pop(); + // In destruction tine "0" is pushed to the queue + // and no further executable is scheduled if( !exec ) return; executables.push_back( exec ); + const Futures& preConds = exec->getPreconditions(); + inputConditions.insert( preConds.begin(), preConds.end( )); } inputConditions.erase( _unlockPromise.getFuture( )); @@ -110,10 +112,7 @@ struct SimpleExecutor::Impl inputConditions.erase( future ); } else - { ++it; - inputConditions.insert( preConds.begin(), preConds.end( )); - } } } } @@ -125,9 +124,9 @@ struct SimpleExecutor::Impl void schedule( Executable& exec ) { + ScopedLock lock( _promiseReset ); const bool wasEmpty = _mtWorkQueue.empty(); _mtWorkQueue.push_back( &exec ); - ScopedLock lock( _promiseReset ); if( wasEmpty ) _unlockPromise.set( true ); } From 37c908e08bb2e8c2f38f253178e1c8119bb7a77c Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Thu, 12 May 2016 16:53:40 +0200 Subject: [PATCH 12/17] Livre pipeline --- CMakeLists.txt | 3 +- .../tfEditor/TransferFunctionEditor.ui | 69 ++++ livre/core/CMakeLists.txt | 86 ++--- livre/core/cache/Cache.cpp | 1 + livre/core/dash/DashContextTrait.cpp | 36 -- livre/core/dash/DashRenderNode.cpp | 127 ------- livre/core/dash/DashRenderNode.h | 129 ------- livre/core/dash/DashRenderStatus.cpp | 86 ----- livre/core/dash/DashRenderStatus.h | 100 ------ livre/core/dash/DashTree.cpp | 177 --------- livre/core/dash/DashTree.h | 87 ----- livre/core/dashTypes.h | 48 --- livre/core/dashpipeline/DashConnection.cpp | 69 ---- livre/core/dashpipeline/DashConnection.h | 67 ---- livre/core/dashpipeline/DashProcessor.cpp | 56 --- livre/core/dashpipeline/DashProcessor.h | 70 ---- .../core/dashpipeline/DashProcessorInput.cpp | 139 ------- livre/core/dashpipeline/DashProcessorInput.h | 75 ---- .../core/dashpipeline/DashProcessorOutput.cpp | 88 ----- livre/core/dashpipeline/DashProcessorOutput.h | 74 ---- livre/core/data/DataSource.cpp | 6 + livre/core/data/DataSourcePlugin.cpp | 1 + livre/core/pipeline/AsyncData.cpp | 153 -------- livre/core/pipeline/AsyncData.h | 97 ----- livre/core/pipeline/Connection.h | 190 ---------- livre/core/pipeline/Executable.cpp | 2 +- livre/core/pipeline/Executable.h | 7 +- livre/core/pipeline/Executor.h | 2 +- livre/core/pipeline/Filter.h | 3 + livre/core/pipeline/Future.cpp | 100 ------ livre/core/pipeline/FutureMap.cpp | 5 +- livre/core/pipeline/FutureMap.h | 28 +- livre/core/pipeline/FuturePromise.cpp | 246 +++++++++++++ .../pipeline/{Future.h => FuturePromise.h} | 97 ++++- livre/core/pipeline/InputPort.cpp | 5 +- livre/core/pipeline/OutputPort.cpp | 2 +- livre/core/pipeline/PipeFilter.cpp | 14 +- livre/core/pipeline/PipeFilter.h | 6 +- livre/core/pipeline/Pipeline.cpp | 11 +- livre/core/pipeline/Pipeline.h | 10 +- livre/core/pipeline/Processor.cpp | 44 --- livre/core/pipeline/Processor.h | 153 -------- livre/core/pipeline/ProcessorInput.cpp | 114 ------ livre/core/pipeline/ProcessorInput.h | 139 ------- livre/core/pipeline/ProcessorOutput.cpp | 77 ---- livre/core/pipeline/ProcessorOutput.h | 103 ------ livre/core/pipeline/Promise.cpp | 107 ------ livre/core/pipeline/Promise.h | 95 ----- livre/core/pipeline/PromiseMap.cpp | 31 +- livre/core/pipeline/PromiseMap.h | 27 +- livre/core/pipeline/SimpleExecutor.cpp | 32 +- livre/core/pipeline/SimpleExecutor.h | 4 +- livre/core/pipeline/Workers.cpp | 28 +- livre/core/pipeline/Workers.h | 4 +- livre/core/render/FrameInfo.cpp | 2 + livre/core/render/FrameInfo.h | 6 +- livre/core/render/GLContext.cpp | 5 + livre/core/render/GLContext.h | 2 +- livre/core/render/SelectVisibles.h | 167 +++++++++ livre/core/types.h | 18 +- livre/{lib => core}/visitor/DFSTraversal.cpp | 17 +- livre/{lib => core}/visitor/DFSTraversal.h | 12 +- ...rNodeVisitor.cpp => DataSourceVisitor.cpp} | 45 ++- ...enderNodeVisitor.h => DataSourceVisitor.h} | 31 +- livre/eq/Channel.cpp | 340 ++++++++---------- livre/eq/Channel.h | 1 - livre/eq/Node.cpp | 17 - livre/eq/Node.h | 13 +- livre/eq/Window.cpp | 206 ++--------- livre/eq/Window.h | 14 +- livre/eq/render/EqContext.cpp | 16 +- livre/lib/CMakeLists.txt | 27 +- livre/lib/cache/TextureDataObject.cpp | 2 +- livre/lib/data/MemoryDataSource.cpp | 1 - livre/lib/pipeline/DataUploadFilter.cpp | 162 +++++++++ livre/lib/pipeline/DataUploadFilter.h | 72 ++++ livre/lib/pipeline/RenderFilter.cpp | 96 +++++ .../RenderFilter.h} | 42 ++- livre/lib/pipeline/RenderPipeline.cpp | 212 +++++++++++ livre/lib/pipeline/RenderPipeline.h | 79 ++++ .../pipeline/RenderingSetGeneratorFilter.cpp | 193 ++++++++++ .../pipeline/RenderingSetGeneratorFilter.h} | 48 +-- .../pipeline/VisibleSetGeneratorFilter.cpp | 122 +++++++ .../lib/pipeline/VisibleSetGeneratorFilter.h | 71 ++++ livre/lib/render/AvailableSetGenerator.cpp | 120 ------- livre/lib/render/SelectVisibles.h | 179 --------- livre/lib/types.h | 6 +- livre/lib/uploaders/DataUploadProcessor.cpp | 340 ------------------ livre/lib/uploaders/DataUploadProcessor.h | 71 ---- .../lib/uploaders/TextureUploadProcessor.cpp | 267 -------------- livre/lib/uploaders/TextureUploadProcessor.h | 82 ----- livre/lib/visitor/CollectionTraversal.cpp | 63 ---- livre/lib/visitor/CollectionTraversal.h | 49 --- livre/uvf/UVFDataSource.cpp | 1 - tests/lib/lodSelection.cpp | 19 +- tests/pipeline/pipeline.cpp | 59 +-- 96 files changed, 2121 insertions(+), 4704 deletions(-) create mode 100644 apps/livreGUI/tfEditor/TransferFunctionEditor.ui delete mode 100644 livre/core/dash/DashContextTrait.cpp delete mode 100644 livre/core/dash/DashRenderNode.cpp delete mode 100644 livre/core/dash/DashRenderNode.h delete mode 100644 livre/core/dash/DashRenderStatus.cpp delete mode 100644 livre/core/dash/DashRenderStatus.h delete mode 100644 livre/core/dash/DashTree.cpp delete mode 100644 livre/core/dash/DashTree.h delete mode 100644 livre/core/dashTypes.h delete mode 100644 livre/core/dashpipeline/DashConnection.cpp delete mode 100644 livre/core/dashpipeline/DashConnection.h delete mode 100644 livre/core/dashpipeline/DashProcessor.cpp delete mode 100644 livre/core/dashpipeline/DashProcessor.h delete mode 100644 livre/core/dashpipeline/DashProcessorInput.cpp delete mode 100644 livre/core/dashpipeline/DashProcessorInput.h delete mode 100644 livre/core/dashpipeline/DashProcessorOutput.cpp delete mode 100644 livre/core/dashpipeline/DashProcessorOutput.h delete mode 100644 livre/core/pipeline/AsyncData.cpp delete mode 100644 livre/core/pipeline/AsyncData.h delete mode 100644 livre/core/pipeline/Connection.h delete mode 100644 livre/core/pipeline/Future.cpp create mode 100644 livre/core/pipeline/FuturePromise.cpp rename livre/core/pipeline/{Future.h => FuturePromise.h} (57%) delete mode 100644 livre/core/pipeline/Processor.cpp delete mode 100644 livre/core/pipeline/Processor.h delete mode 100644 livre/core/pipeline/ProcessorInput.cpp delete mode 100644 livre/core/pipeline/ProcessorInput.h delete mode 100644 livre/core/pipeline/ProcessorOutput.cpp delete mode 100644 livre/core/pipeline/ProcessorOutput.h delete mode 100644 livre/core/pipeline/Promise.cpp delete mode 100644 livre/core/pipeline/Promise.h create mode 100644 livre/core/render/SelectVisibles.h rename livre/{lib => core}/visitor/DFSTraversal.cpp (92%) rename livre/{lib => core}/visitor/DFSTraversal.h (83%) rename livre/core/visitor/{RenderNodeVisitor.cpp => DataSourceVisitor.cpp} (53%) rename livre/core/visitor/{RenderNodeVisitor.h => DataSourceVisitor.h} (62%) create mode 100644 livre/lib/pipeline/DataUploadFilter.cpp create mode 100644 livre/lib/pipeline/DataUploadFilter.h create mode 100644 livre/lib/pipeline/RenderFilter.cpp rename livre/lib/{render/AvailableSetGenerator.h => pipeline/RenderFilter.h} (55%) create mode 100644 livre/lib/pipeline/RenderPipeline.cpp create mode 100644 livre/lib/pipeline/RenderPipeline.h create mode 100644 livre/lib/pipeline/RenderingSetGeneratorFilter.cpp rename livre/{core/dash/DashContextTrait.h => lib/pipeline/RenderingSetGeneratorFilter.h} (50%) create mode 100644 livre/lib/pipeline/VisibleSetGeneratorFilter.cpp create mode 100644 livre/lib/pipeline/VisibleSetGeneratorFilter.h delete mode 100644 livre/lib/render/AvailableSetGenerator.cpp delete mode 100644 livre/lib/render/SelectVisibles.h delete mode 100644 livre/lib/uploaders/DataUploadProcessor.cpp delete mode 100644 livre/lib/uploaders/DataUploadProcessor.h delete mode 100644 livre/lib/uploaders/TextureUploadProcessor.cpp delete mode 100644 livre/lib/uploaders/TextureUploadProcessor.h delete mode 100644 livre/lib/visitor/CollectionTraversal.cpp delete mode 100644 livre/lib/visitor/CollectionTraversal.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a369bd32..0bd63c71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,6 @@ common_find_package(BBPTestData) common_find_package(Boost REQUIRED COMPONENTS filesystem program_options thread system regex unit_test_framework) common_find_package(Collage REQUIRED) -common_find_package(dash REQUIRED) common_find_package(Equalizer REQUIRED) common_find_package(Lexis REQUIRED) common_find_package(LibJpegTurbo) @@ -62,7 +61,7 @@ common_find_package(ZeroBuf REQUIRED) common_find_package_post() include(EqGLLibraries) -set(LIVRE_DEPENDENT_LIBRARIES vmmlib Lunchbox dash Equalizer ZeroBuf) +set(LIVRE_DEPENDENT_LIBRARIES vmmlib Lunchbox Equalizer ZeroBuf) add_definitions(-DBOOST_PROGRAM_OPTIONS_DYN_LINK) # Fix for windows and shared boost. add_subdirectory(livre) diff --git a/apps/livreGUI/tfEditor/TransferFunctionEditor.ui b/apps/livreGUI/tfEditor/TransferFunctionEditor.ui new file mode 100644 index 00000000..b15a86fc --- /dev/null +++ b/apps/livreGUI/tfEditor/TransferFunctionEditor.ui @@ -0,0 +1,69 @@ + + + TransferFunctionEditor + + + + 0 + 0 + 518 + 444 + + + + + + + + + + + + Clear + + + + + + + Default + + + + + + + Load... + + + + + + + Save... + + + + + + + + + + + + + + + + + + Color Map + + + + + + + + diff --git a/livre/core/CMakeLists.txt b/livre/core/CMakeLists.txt index 83d5bba3..fffac579 100644 --- a/livre/core/CMakeLists.txt +++ b/livre/core/CMakeLists.txt @@ -20,57 +20,44 @@ set(LIVRECORE_PUBLIC_HEADERS ) set(LIVRECORE_HEADERS - dashTypes.h cache/Cache.h cache/CacheObject.h cache/CacheStatistics.h configuration/Configuration.h configuration/Parameters.h - dash/DashContextTrait.h - dash/DashRenderNode.h - dash/DashRenderStatus.h - dash/DashTree.h data/DataSource.h - dashpipeline/DashConnection.h - dashpipeline/DashProcessor.h - dashpipeline/DashProcessorInput.h - dashpipeline/DashProcessorOutput.h events/EventHandler.h events/EventHandlerFactory.h events/EventInfo.h events/EventMapper.h maths/maths.h maths/Quantizer.h - pipeline/Connection.h - pipeline/Processor.h - pipeline/ProcessorInput.h - pipeline/ProcessorOutput.h - render/FrameInfo.h - render/Frustum.h - render/Renderer.h - render/TexturePool.h - render/TextureState.h - render/TransferFunction1D.h - util/FrameUtils.h - util/ThreadClock.h - visitor/NodeVisitor.h - visitor/RenderNodeVisitor.h - visitor/VisitState.h - - pipeline/AsyncData.h pipeline/Executable.h pipeline/Filter.h - pipeline/Future.h pipeline/FutureMap.h pipeline/InputPort.h pipeline/OutputPort.h pipeline/PipeFilter.h pipeline/Pipeline.h pipeline/PortData.h - pipeline/Promise.h + pipeline/FuturePromise.h pipeline/PromiseMap.h pipeline/SimpleExecutor.h - pipeline/Workers.h ) + pipeline/Workers.h + render/FrameInfo.h + render/Frustum.h + render/Renderer.h + render/SelectVisibles.h + render/TexturePool.h + render/TextureState.h + render/TransferFunction1D.h + util/FrameUtils.h + util/ThreadClock.h + visitor/DFSTraversal.h + visitor/NodeVisitor.h + visitor/DataSourceVisitor.h + visitor/DFSTraversal.h + visitor/VisitState.h) set(LIVRECORE_SOURCES cache/Cache.cpp @@ -78,24 +65,23 @@ set(LIVRECORE_SOURCES cache/CacheStatistics.cpp configuration/Configuration.cpp configuration/Parameters.cpp - dash/DashContextTrait.cpp - dash/DashRenderNode.cpp - dash/DashRenderStatus.cpp - dash/DashTree.cpp data/LODNode.cpp data/MemoryUnit.cpp data/NodeId.cpp data/DataSource.cpp data/DataSourcePlugin.cpp data/VolumeInformation.cpp - dashpipeline/DashConnection.cpp - dashpipeline/DashProcessor.cpp - dashpipeline/DashProcessorInput.cpp - dashpipeline/DashProcessorOutput.cpp events/EventMapper.cpp - pipeline/Processor.cpp - pipeline/ProcessorInput.cpp - pipeline/ProcessorOutput.cpp + pipeline/Executable.cpp + pipeline/FutureMap.cpp + pipeline/InputPort.cpp + pipeline/OutputPort.cpp + pipeline/PipeFilter.cpp + pipeline/Pipeline.cpp + pipeline/FuturePromise.cpp + pipeline/PromiseMap.cpp + pipeline/SimpleExecutor.cpp + pipeline/Workers.cpp render/FrameInfo.cpp render/Frustum.cpp render/GLContext.cpp @@ -107,24 +93,12 @@ set(LIVRECORE_SOURCES util/FrameUtils.cpp util/ThreadClock.cpp util/Utilities.cpp - visitor/RenderNodeVisitor.cpp - visitor/VisitState.cpp - - pipeline/AsyncData.cpp - pipeline/Executable.cpp - pipeline/Future.cpp - pipeline/FutureMap.cpp - pipeline/InputPort.cpp - pipeline/OutputPort.cpp - pipeline/PipeFilter.cpp - pipeline/Pipeline.cpp - pipeline/Promise.cpp - pipeline/PromiseMap.cpp - pipeline/SimpleExecutor.cpp - pipeline/Workers.cpp ) + visitor/DataSourceVisitor.cpp + visitor/DFSTraversal.cpp + visitor/VisitState.cpp) set(LIVRECORE_LINK_LIBRARIES - PUBLIC ${Boost_LIBRARIES} dash Collage Lexis Lunchbox vmmlib + PUBLIC ${Boost_LIBRARIES} Collage Lexis Lunchbox vmmlib ZeroBufRender PRIVATE Equalizer ${GLEW_MX_LIBRARIES}) set(LIVRECORE_INCLUDE_NAME livre/core) diff --git a/livre/core/cache/Cache.cpp b/livre/core/cache/Cache.cpp index 91c210ac..7fe3c79f 100644 --- a/livre/core/cache/Cache.cpp +++ b/livre/core/cache/Cache.cpp @@ -85,6 +85,7 @@ struct Cache::Impl : _policy( maxMemBytes ) , _cache( cache ) , _statistics( name, maxMemBytes ) + , _cacheMap( 128 ) {} ~Impl() diff --git a/livre/core/dash/DashContextTrait.cpp b/livre/core/dash/DashContextTrait.cpp deleted file mode 100644 index e47fae5a..00000000 --- a/livre/core/dash/DashContextTrait.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -namespace livre -{ - -void DashContextTrait::setDashContext( DashContextPtr dashContextPtr ) -{ - dashContextPtr_ = dashContextPtr; - onSetDashContext_( ); -} - -DashContextPtr DashContextTrait::getDashContext() -{ - return dashContextPtr_; -} - -} diff --git a/livre/core/dash/DashRenderNode.cpp b/livre/core/dash/DashRenderNode.cpp deleted file mode 100644 index 864e0354..00000000 --- a/livre/core/dash/DashRenderNode.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -namespace livre -{ - -enum DashAttributeType -{ - DNT_NODE , - DNT_TEXTUREDATA , - DNT_TEXTURE , - DNT_LODVISIBLE , - DNT_INFRUSTUM , - DNT_CACHE_MODIFIED -}; - -DashRenderNode::DashRenderNode( dash::NodePtr dashNode ) - : _dashNode( dashNode ) -{ } - -const LODNode& DashRenderNode::getLODNode( ) const -{ - return getAttribute_< const LODNode& >( DashAttributeType::DNT_NODE ); -} - -ConstCacheObjectPtr DashRenderNode::getTextureDataObject( ) const -{ - return getAttribute_< ConstCacheObjectPtr >( DNT_TEXTUREDATA ); -} - -ConstCacheObjectPtr DashRenderNode::getTextureObject( ) const -{ - return getAttribute_< ConstCacheObjectPtr >( DNT_TEXTURE ); -} - -bool DashRenderNode::isInFrustum( ) const -{ - return getAttribute_< bool >( DNT_INFRUSTUM ); -} - -bool DashRenderNode::isLODVisible( ) const -{ - return getAttribute_< bool >( DNT_LODVISIBLE ); -} - -void DashRenderNode::setLODNode( const LODNode& node ) -{ - *(_dashNode->getAttribute( DNT_NODE )) = node; -} - -void DashRenderNode::setTextureDataObject( ConstCacheObjectPtr textureData ) -{ - *(_dashNode->getAttribute( DNT_TEXTUREDATA )) = textureData; -} - -void DashRenderNode::setTextureObject( ConstCacheObjectPtr texture ) -{ - *(_dashNode->getAttribute( DNT_TEXTURE )) = texture; -} - -void DashRenderNode::setInFrustum( bool visibility ) -{ - *(_dashNode->getAttribute( DNT_INFRUSTUM )) = visibility; -} - -void DashRenderNode::setLODVisible( bool visibility ) -{ - *(_dashNode->getAttribute( DNT_LODVISIBLE )) = visibility; -} - -void DashRenderNode::initializeDashNode( dash::NodePtr dashNode ) -{ - dash::AttributePtr node = new dash::Attribute(); - const LODNode lodNode; - *node = lodNode; - dashNode->insert( node ); - - dash::AttributePtr textureData = new dash::Attribute(); - ConstCacheObjectPtr lodTextureData; - *textureData = lodTextureData; - dashNode->insert( textureData ); - - dash::AttributePtr texture = new dash::Attribute(); - ConstCacheObjectPtr lodTexture; - *texture = lodTexture; - dashNode->insert( texture ); - - dash::AttributePtr isLODVisible = new dash::Attribute(); - *isLODVisible = false; - dashNode->insert( isLODVisible ); - - dash::AttributePtr isInFrustum = new dash::Attribute(); - *isInFrustum = true; - dashNode->insert( isInFrustum ); - - dash::AttributePtr cacheObjectModified = new dash::Attribute(); - *cacheObjectModified = true; - dashNode->insert( cacheObjectModified ); -} - -template< class T > -T DashRenderNode::getAttribute_( const uint32_t nodeType ) const -{ - dash::ConstAttributePtr attribute = _dashNode->getAttribute( nodeType ); - return attribute->getUnsafe< T >( ); -} - - -} diff --git a/livre/core/dash/DashRenderNode.h b/livre/core/dash/DashRenderNode.h deleted file mode 100644 index 62a6af8a..00000000 --- a/livre/core/dash/DashRenderNode.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DashRenderNode_h_ -#define _DashRenderNode_h_ - -#include - -#include -#include - -#include -#include -#include - -namespace livre -{ - -/** - * The DashRenderNode class is an helper class to access the dash nodes attributes. - */ -class DashRenderNode -{ -public: - /** - * @param dashNode The dash node to access. - */ - LIVRECORE_API DashRenderNode( dash::NodePtr dashNode ); - - /** - * @return The dash node. - */ - LIVRECORE_API dash::NodePtr getDashNode() const { return _dashNode; } - - /** - * @return The LODNode. - */ - LIVRECORE_API const LODNode& getLODNode() const; - - /** - * @return \see TextureDataObject, if not initialized in the tree, the returned object - * is empty. - */ - LIVRECORE_API ConstCacheObjectPtr getTextureDataObject() const; - - /** - * @return \see TextureObject, if not initialized in the tree, the returned object is - * empty. - */ - LIVRECORE_API ConstCacheObjectPtr getTextureObject() const; - - /** - * @return True, if object is visible. - * @warning This condition is set from outside of the object. - */ - LIVRECORE_API bool isLODVisible() const; - - /** - * @return True, if object is in frustum. - * @warning This condition is set from outside of the object. - */ - LIVRECORE_API bool isInFrustum() const; - - /** - * Sets the \see LODNode for the dash node. - * @param node Sets the \see which is an abstract rendering information ( size of block, position, etcc ) - */ - LIVRECORE_API void setLODNode( const LODNode& node ); - - /** - * Sets the texture data object. - * @param textureData Sets the texture data object, if \see EmptyCacheObject is - * given the reference count decreases - * for the corresponding \see CacheObject, therefore \see Cache can clean the object. - */ - LIVRECORE_API void setTextureDataObject( ConstCacheObjectPtr textureData ); - - /** - * Sets the texture object. - * @param texture Sets the texture object, if \see EmptyCacheObject is given - * the reference count decreases - * for the corresponding \see CacheObject, therefore \see Cache can clean the object. - */ - LIVRECORE_API void setTextureObject( ConstCacheObjectPtr texture ); - - /** - * Sets visibilty of node. - * @param visibility If parameter is true, node is visible. - */ - LIVRECORE_API void setLODVisible( bool visibility ); - - /** - * Sets frustum status of node. - * @param visibility If parameter is true, node is visible. - */ - LIVRECORE_API void setInFrustum( bool visibility ); - - /** - * Initializes an empty dash node with attributes. - * @param dashNode Input dash node to initialize. - */ - static void initializeDashNode( dash::NodePtr dashNode ); - -private: - - template< class T > - T getAttribute_( const uint32_t nodeType ) const; - - dash::NodePtr _dashNode; -}; - -} -#endif // _DashRenderNode_h_ diff --git a/livre/core/dash/DashRenderStatus.cpp b/livre/core/dash/DashRenderStatus.cpp deleted file mode 100644 index 45ded7e9..00000000 --- a/livre/core/dash/DashRenderStatus.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -namespace livre -{ - -enum DashAttributeType -{ - DNT_FRAME_ID , - DNT_THREAD_OPERATION , - DNT_FRUSTUM -}; - -DashRenderStatus::DashRenderStatus() - : _dashNode( new dash::Node() ) -{ - dash::AttributePtr currentRenderID = new dash::Attribute(); - *currentRenderID = INVALID_FRAME; - _dashNode->insert( currentRenderID ); - - dash::AttributePtr threadOp = new dash::Attribute(); - *threadOp = TO_NONE; - _dashNode->insert( threadOp ); - - dash::AttributePtr frustum = new dash::Attribute(); - *frustum = Frustum( Matrix4f(), Matrix4f( )); - _dashNode->insert( frustum ); -} - -uint64_t DashRenderStatus::getFrameID( ) const -{ - return _getAttribute< uint64_t >( DNT_FRAME_ID ); -} - -void DashRenderStatus::setFrameID( const uint64_t frameId ) -{ - *(_dashNode->getAttribute( DNT_FRAME_ID )) = frameId; -} - -Frustum DashRenderStatus::getFrustum( ) const -{ - return _getAttribute< Frustum >( DNT_FRUSTUM ); -} - -void DashRenderStatus::setFrustum( const Frustum& frustum ) -{ - *(_dashNode->getAttribute( DNT_FRUSTUM )) = frustum; -} - -ThreadOperation DashRenderStatus::getThreadOp( ) const -{ - return _getAttribute< ThreadOperation >( DNT_THREAD_OPERATION ); -} - -void DashRenderStatus::setThreadOp( const ThreadOperation op ) -{ - *(_dashNode->getAttribute( DNT_THREAD_OPERATION )) = op; -} - -template< class T > -T DashRenderStatus::_getAttribute( const uint32_t nodeType ) const -{ - dash::ConstAttributePtr attribute = _dashNode->getAttribute( nodeType ); - return attribute->getUnsafe< T >( ); -} - - -} diff --git a/livre/core/dash/DashRenderStatus.h b/livre/core/dash/DashRenderStatus.h deleted file mode 100644 index 62721664..00000000 --- a/livre/core/dash/DashRenderStatus.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DashRenderStatus_h_ -#define _DashRenderStatus_h_ - -#include - -#include -#include - -#include -#include -#include - -namespace livre -{ - -/** - * The ThreadOperation enum is used to send commands to the threads. - */ -enum ThreadOperation -{ - TO_NONE, //!< Do nothing. - TO_PAUSE, //!< Pause. - TO_EXIT, //!< Exit. - TO_CONTINUE //!< Resume. -}; - -/** - * The DashRenderStatus class enable access to render status between different dash contexts. - */ -class DashRenderStatus : public boost::noncopyable -{ -public: - LIVRECORE_API DashRenderStatus(); - - /** - * @return The dash node. - */ - LIVRECORE_API dash::NodePtr getDashNode() const { return _dashNode; } - - /** - * @return The current frame id. - */ - LIVRECORE_API uint64_t getFrameID() const; - - /** - * Sets the frame id of the node. - * @param frameId The id for the rendered frame. - */ - LIVRECORE_API void setFrameID( const uint64_t frameId ); - - /** - * @return The current rendering frustum. - */ - LIVRECORE_API Frustum getFrustum() const; - - /** - * Sets the current rendering frustum. - * @param frustum Current rendering frustum. - */ - LIVRECORE_API void setFrustum( const Frustum& frustum ); - - /** - * @return The thread command issued. - */ - LIVRECORE_API ThreadOperation getThreadOp() const; - - /** - * Issues a thread command ( stop, pause, continue etc ). Helpful for pipeline. - * @param op Thread operation to be issued. - */ - LIVRECORE_API void setThreadOp( const ThreadOperation op ); - -private: - template< class T > - T _getAttribute( const uint32_t nodeType ) const; - - dash::NodePtr _dashNode; -}; - -} -#endif // _DashRenderStatus_h_ diff --git a/livre/core/dash/DashTree.cpp b/livre/core/dash/DashTree.cpp deleted file mode 100644 index d37d1a8f..00000000 --- a/livre/core/dash/DashTree.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -#include -#include -#include - -#include -#include - -namespace livre -{ - -typedef std::unordered_map< Identifier, dash::NodePtr > IdDashNodeMap; - -struct DashTree::Impl -{ -public: - explicit Impl( const DataSource& dataSource ) - : _dataSource( dataSource ), - _localContext( dash::Context::getMain( )) - { - dash::Context& prevCtx = dash::Context::getCurrent(); - _localContext.setCurrent(); - // Instantiation should be done in the context dash tree knows - _renderStatus = new DashRenderStatus(); - _localContext.commit(); - prevCtx.setCurrent(); - } - - ~Impl() - { - _localContext.commit(); - for( DashContextPtr ctx: dashContexts ) - { - ctx->commit(); - } - delete _renderStatus; - } - - DashContextPtr createContext() - { - WriteLock writeLock( _mutex ); - _localContext.commit(); - DashContextPtr ctx( new dash::Context( )); - dashContexts.push_back( ctx ); - _localContext.map( _renderStatus->getDashNode(), *dashContexts.back() ); - return ctx; - } - - const dash::NodePtr getParentNode( const NodeId& nodeId ) - { - if( nodeId.isRoot( )) - return dash::NodePtr(); - - const NodeId& parentNodeId = nodeId.getParent(); - return getDashNode( parentNodeId ) ; - } - - dash::NodePtr getDashNode( const NodeId& nodeId) const - { - ReadLock readLock( _mutex ); - IdDashNodeMap::const_iterator it = _dashNodeMap.find( nodeId.getId( )); - return it == _dashNodeMap.end() ? dash::NodePtr() : it->second; - } - - dash::NodePtr getDashNode( const NodeId& nodeId ) - { - LBASSERT( &_localContext != &dash::Context::getCurrent() ); - IdDashNodeMap::const_iterator it = _dashNodeMap.find( nodeId.getId( )); - - // "Double-Checked Locking" idiom is used below. - { - ReadLock readLock( _mutex ); - if( it != _dashNodeMap.end( ) && it->second ) - return it->second; - } - - WriteLock writeLock( _mutex ); - it = _dashNodeMap.find( nodeId.getId( )); - if( it != _dashNodeMap.end( )) - return it->second; - - dash::Context& prevCtx = dash::Context::getCurrent(); - _localContext.setCurrent(); - - const LODNode& lodNode = _dataSource.getNode( nodeId ); - if( !lodNode.isValid( )) - { - prevCtx.setCurrent(); - return dash::NodePtr(); - } - - dash::NodePtr node = new dash::Node(); - DashRenderNode::initializeDashNode( node ); - DashRenderNode renderNode( node ); - renderNode.setLODNode( lodNode ); - - _localContext.commit(); - for( DashContextPtr ctx: dashContexts ) - { - _localContext.map( node, *ctx ); - } - prevCtx.setCurrent(); - _dashNodeMap[ nodeId.getId() ] = node; - return node; - } - - const DataSource& _dataSource; - IdDashNodeMap _dashNodeMap; - DashRenderStatus* _renderStatus; - mutable ReadWriteMutex _mutex; - dash::Context& _localContext; - std::vector< DashContextPtr > dashContexts; -}; - -DashTree::DashTree( const DataSource& dataSource ) - : _impl( new Impl( dataSource )) -{} - -const DataSource& DashTree::getDataSource() const -{ - return _impl->_dataSource; -} - -DashTree::~DashTree() -{} - -DashContextPtr DashTree::createContext() -{ - return _impl->createContext(); -} - -const DashRenderStatus& DashTree::getRenderStatus() const -{ - return *_impl->_renderStatus; -} - -DashRenderStatus& DashTree::getRenderStatus() -{ - return *_impl->_renderStatus; -} - -const dash::NodePtr DashTree::getParentNode( const NodeId& nodeId ) -{ - return _impl->getParentNode( nodeId ) ; -} - -dash::NodePtr DashTree::getDashNode( const NodeId& nodeId ) -{ - return _impl->getDashNode( nodeId ) ; -} - -dash::NodePtr DashTree::getDashNode( const NodeId& nodeId) const -{ - return _impl->getDashNode( nodeId ) ; -} - -} diff --git a/livre/core/dash/DashTree.h b/livre/core/dash/DashTree.h deleted file mode 100644 index 8edde94c..00000000 --- a/livre/core/dash/DashTree.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DashTree_h_ -#define _DashTree_h_ - -#include -#include -#include - -namespace livre -{ - -/** - * The DashTree class keeps the hierarcy of the dash nodes representing the LOD nodes. - */ -class DashTree -{ -public: - - /** - * @param dataSource node hierarchy matches the dash tree node hierarchy - */ - LIVRECORE_API DashTree( const DataSource& dataSource ); - LIVRECORE_API ~DashTree(); - - /** - * @return Returns the data source - */ - LIVRECORE_API const DataSource& getDataSource() const; - - /** - * Creates a new context, registers it and maps its data to already registered contexts. - * @return Returns a new dash context - */ - LIVRECORE_API DashContextPtr createContext(); - - /** - * @return The render status of the dash tree. - */ - LIVRECORE_API const DashRenderStatus& getRenderStatus() const; - - /** - * @return The render status of the dash tree. - */ - LIVRECORE_API DashRenderStatus& getRenderStatus(); - - /** - * @return parent of the render node. If there is no parent empty NodePtr is returned. - */ - LIVRECORE_API const dash::NodePtr getParentNode( const NodeId& nodeId ); - - /** - * @return a node by its nodeId, creates a new one if it does not exist. - */ - LIVRECORE_API dash::NodePtr getDashNode( const NodeId& nodeId ); - - /** - * @return a node by its nodeId, returns an empty node if there is no nodeId. - */ - LIVRECORE_API dash::NodePtr getDashNode( const NodeId& nodeId ) const; - -private: - - struct Impl; - std::unique_ptr< Impl > _impl; -}; - -} - -#endif // _DashTree_h_ diff --git a/livre/core/dashTypes.h b/livre/core/dashTypes.h deleted file mode 100644 index 38684bcf..00000000 --- a/livre/core/dashTypes.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _dashTypes_h_ -#define _dashTypes_h_ - -#include -#include - -#include -#include - -namespace livre -{ -/** - * SmartPtr definitions - */ -typedef std::shared_ptr< dash::Context > DashContextPtr; - -/** - * Vector definitions for complex types - */ -typedef std::vector< dash::NodePtr > DashNodeVector; - -/** - * Set definitions - */ -typedef std::set< dash::NodePtr > DashNodeSet; - -} - -#endif // _dashTypes_h_ diff --git a/livre/core/dashpipeline/DashConnection.cpp b/livre/core/dashpipeline/DashConnection.cpp deleted file mode 100644 index 157d443a..00000000 --- a/livre/core/dashpipeline/DashConnection.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -namespace livre -{ - -class DashReceiver: public Receiver< dash::Commit > -{ -public: - - explicit DashReceiver( lunchbox::MTQueue< dash::Commit >& queue ) : queue_( queue ) { } - virtual dash::Commit pop( ) { return queue_.pop(); } - virtual void popAll( std::vector< dash::Commit >& result ) { queue_.tryPop( queue_.getSize( ), result ); } - virtual bool timedPop( const unsigned timeout, dash::Commit& commit ) { return queue_.timedPop( timeout, commit ); } - virtual bool hasData( ) const { return queue_.getSize() > 0; } - virtual void clear( ) { queue_.clear(); } -protected: - lunchbox::MTQueue< dash::Commit >& queue_; -}; - - -class DashSender: public Sender< dash::Commit > -{ -public: - explicit DashSender( lunchbox::MTQueue< dash::Commit >& queue ) : queue_( queue ) { } - virtual void push( dash::Commit& commit ) { queue_.push( commit ); } - virtual void push( const std::vector< dash::Commit >& commits ) { queue_.push( commits ); } - virtual void clear( ) { queue_.clear(); } - -protected: - lunchbox::MTQueue< dash::Commit >& queue_; -}; - -DashConnection::DashConnection( const uint32_t maxSize ) -{ - queue_.setMaxSize( maxSize ); - sender_.reset( new DashSender( queue_ ) ); - receiver_.reset( new DashReceiver( queue_ ) ); -} - -void DashConnection::setSourceContext( DashContextPtr contextPtr ) -{ - sourceContextPtr_= contextPtr; -} - -void DashConnection::setDestinationContext( DashContextPtr contextPtr ) -{ - destinationContextPtr_= contextPtr; -} - -} diff --git a/livre/core/dashpipeline/DashConnection.h b/livre/core/dashpipeline/DashConnection.h deleted file mode 100644 index 8ed206fa..00000000 --- a/livre/core/dashpipeline/DashConnection.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DashConnection_h_ -#define _DashConnection_h_ - -#include -#include -#include -#include - -#include - -namespace livre -{ - -/** - * The DashConnection class implements the connection between dash processors based on dash commits. - */ -class DashConnection : public Connection< dash::Commit > -{ -public: - /** - * @param maxSize Maximum size of queue. - */ - LIVRECORE_API DashConnection( const uint32_t maxSize ); - - /** - * Sets the source context. - * @param contextPtr Source context. - */ - LIVRECORE_API void setSourceContext( DashContextPtr contextPtr ); - - /** - * Sets the destination context. - * @param contextPtr Destination context. - */ - LIVRECORE_API void setDestinationContext( DashContextPtr contextPtr ); - -private: - DashContextPtr sourceContextPtr_; - - DashContextPtr destinationContextPtr_; - - lunchbox::MTQueue< dash::Commit > queue_; - -}; - -} - -#endif // _DashConnection_h_ diff --git a/livre/core/dashpipeline/DashProcessor.cpp b/livre/core/dashpipeline/DashProcessor.cpp deleted file mode 100644 index 82131cb4..00000000 --- a/livre/core/dashpipeline/DashProcessor.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include - -namespace livre -{ - -DashProcessor::DashProcessor() -{ -} - -bool DashProcessor::onPreApply_( const uint32_t connection ) -{ - return getProcessorInput_< DashProcessorInput >()->getConnection( connection ) != 0; -} - -bool DashProcessor::onPreCommit_(const uint32_t connection) -{ - return getProcessorOutput_< DashProcessorOutput >()->getConnection( connection ) != 0; -} - -void DashProcessor::onSetDashContext_() -{ - processorInputPtr_.reset( new DashProcessorInput( *this ) ); - processorOutputPtr_.reset( new DashProcessorOutput( *this ) ); -} - -bool DashProcessor::initializeThreadRun_() -{ - if( !getDashContext( )) - return false; - - getDashContext()->setCurrent(); - return true; -} - -} diff --git a/livre/core/dashpipeline/DashProcessor.h b/livre/core/dashpipeline/DashProcessor.h deleted file mode 100644 index cc6c1e5a..00000000 --- a/livre/core/dashpipeline/DashProcessor.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DashProcessor_h_ -#define _DashProcessor_h_ - -#include -#include -#include -#include - -namespace livre -{ - -/** - * The Processor class is the base class of the processing step in a pipeline. It can listen - * the input connections and can behave accordingly. It has input connections and output connections - * ( \see Connection ). When underlying thread is started with start() method it starts the infinite loop. - */ -class DashProcessor : public Processor, public DashContextTrait -{ -public: - LIVRECORE_API DashProcessor(); - -protected: - /** - * Checks whether connection is valid. - * @param connection connection id - * @return False if connection is not valid - */ - LIVRECORE_API bool onPreApply_( uint32_t connection ) override; - - /** - * Checks whether connection is valid. - * @param connection connection id - * @return False if connection is not valid - */ - LIVRECORE_API bool onPreCommit_( uint32_t connection ) override; - - /** - * Is executed when the dash context is set. - */ - LIVRECORE_API void onSetDashContext_() override; - - /** - * Initializes the dash context for thread. - * @return True if thread initialization is successfull. - */ - LIVRECORE_API bool initializeThreadRun_() override; -}; - -} - -#endif // _DashProcessor_h_ diff --git a/livre/core/dashpipeline/DashProcessorInput.cpp b/livre/core/dashpipeline/DashProcessorInput.cpp deleted file mode 100644 index e8117e14..00000000 --- a/livre/core/dashpipeline/DashProcessorInput.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -#include - -#include -#include - -namespace livre -{ - -DashProcessorInput::DashProcessorInput( DashProcessor& processor ) - : ProcessorInput( processor ) -{ - setDashContext( processor.getDashContext() ); -} - -bool DashProcessorInput::addConnection( const uint32_t connectionId, DashConnectionPtr connection ) -{ - connectionMapModificationLock_.set(); - if( connectionMap_.find( connectionId ) != connectionMap_.end() ) - { - connectionMapModificationLock_.unset(); - return false; - } - - connectionMap_[ connectionId ] = connection; - connection->setDestinationContext( getDashContext() ); - addConnection_( connectionId ); - connectionMapModificationLock_.unset(); - return true; -} - -bool DashProcessorInput::removeConnection( const uint32_t connectionId ) -{ - connectionMapModificationLock_.set(); - if( connectionMap_.find( connectionId ) != connectionMap_.end() ) - { - connectionMapModificationLock_.unset(); - return false; - } - - connectionMap_.erase( connectionId ); - removeConnection_( connectionId ); - connectionMapModificationLock_.unset(); - return true; -} - -DashConnectionPtr DashProcessorInput::getConnection( const uint32_t connectionId ) -{ - if( connectionMap_.find( connectionId ) == connectionMap_.end() ) - return DashConnectionPtr(); - - return connectionMap_[ connectionId ]; -} - -bool DashProcessorInput::dataWaitingOnInput_( const uint32_t inputConnection ) const -{ - DashConnectionMap::const_iterator it = connectionMap_.find( inputConnection ); - return it->second->hasData( ); -} - -bool DashProcessorInput::apply_( const uint32_t inputConnection ) -{ - DashConnectionPtr connection = connectionMap_[ inputConnection ]; - dash::Commit commit = connection->pop(); - if( commit.getImpl()->empty() ) - return false; - getDashContext()->apply( commit ); - return true; -} - -bool DashProcessorInput::applyAll_( const uint32_t inputConnection ) -{ - DashConnectionPtr connection = connectionMap_[ inputConnection ]; - dash::Commit commit = connection->pop( ); - - std::vector< dash::Commit > commits; - connection->popAll( commits ); - - if( commits.empty() && commit.getImpl()->empty() ) - return false; - - getDashContext()->apply( commit ); - - for( std::vector< dash::Commit >::iterator it = commits.begin(); it != commits.end(); ++it ) - { - getDashContext()->apply( *it ); - } - return true; -} - -bool DashProcessorInput::applyAllTimed_( const uint32_t inputConnection, const uint32_t timeMs ) -{ - DashConnectionPtr connection = connectionMap_[ inputConnection ]; - std::vector< dash::Commit > commits; - dash::Commit commit; - if( connection->timedPop( timeMs, commit ) ) - { - if( !commit.getImpl()->empty() ) - { - connection->popAll( commits ); - } - } - - if( !commit.getImpl()->empty() ) - getDashContext()->apply( commit ); - - if( commits.empty() ) - return false; - - for( std::vector< dash::Commit >::iterator it = commits.begin(); it != commits.end(); ++it ) - { - getDashContext()->apply( *it ); - } - - return true; -} - - -} diff --git a/livre/core/dashpipeline/DashProcessorInput.h b/livre/core/dashpipeline/DashProcessorInput.h deleted file mode 100644 index 0c34b8e2..00000000 --- a/livre/core/dashpipeline/DashProcessorInput.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DashProcessorInput_h_ -#define _DashProcessorInput_h_ - -#include -#include -#include -#include - -namespace livre -{ - -/** - * The DashProcessorInput class is responsibe for receiving commits from many connections. - */ -class DashProcessorInput : public ProcessorInput, protected DashContextTrait -{ -public: - /** - * @param processor Adds DashProcessorInput to the destination processor for connections. - */ - LIVRECORE_API DashProcessorInput( DashProcessor& processor ); - - /** - * Adds a connection. - * @param connectionId Connection id. - * @param connection The connection between processors. - * @return True if the connection can be added with the id. - */ - LIVRECORE_API bool addConnection( const uint32_t connectionId, DashConnectionPtr connection ); - - /** - * Removes a connection. - * @param connectionId Connection id. - * @return True if connection exists and can be removed. - */ - LIVRECORE_API bool removeConnection( const uint32_t connectionId ); - - /** - * @param connectionId Connection id. - * @return The connection. If id is not valid, connection is empty. - */ - LIVRECORE_API DashConnectionPtr getConnection( const uint32_t connectionId ); - -private: - bool dataWaitingOnInput_( const uint32_t inputConnection ) const; - bool apply_( const uint32_t inputConnection ); - bool applyAllTimed_( const uint32_t inputConnection, const uint32_t timeMs ); - bool applyAll_( const uint32_t inputConnection ); - - DashConnectionMap connectionMap_; - lunchbox::Lock connectionMapModificationLock_; -}; - -} - -#endif // _DashProcessorInput_h_ diff --git a/livre/core/dashpipeline/DashProcessorOutput.cpp b/livre/core/dashpipeline/DashProcessorOutput.cpp deleted file mode 100644 index 5558e5e5..00000000 --- a/livre/core/dashpipeline/DashProcessorOutput.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -#include -#include -#include - -namespace livre -{ - -DashProcessorOutput::DashProcessorOutput( DashProcessor& processor ) - : ProcessorOutput( processor ) -{ - setDashContext( processor.getDashContext() ); -} - -bool DashProcessorOutput::addConnection(const uint32_t connectionId, DashConnectionPtr connection ) -{ - connectionMapModificationLock_.set(); - if( connectionMap_.find( connectionId ) != connectionMap_.end() ) - { - connectionMapModificationLock_.unset(); - return false; - } - - connectionMap_[ connectionId ] = connection; - connection->setSourceContext( getDashContext() ); - addConnection_( connectionId ); - connectionMapModificationLock_.unset(); - return true; -} - -bool DashProcessorOutput::removeConnection( const uint32_t connectionId ) -{ - connectionMapModificationLock_.set(); - if( connectionMap_.find( connectionId ) != connectionMap_.end() ) - { - connectionMapModificationLock_.unset(); - return false; - } - - connectionMap_.erase( connectionId ); - removeConnection_( connectionId ); - connectionMapModificationLock_.unset(); - return true; -} - -DashConnectionPtr DashProcessorOutput::getConnection( const uint32_t connectionId ) -{ - if( connectionMap_.find( connectionId ) == connectionMap_.end() ) - return DashConnectionPtr(); - - return connectionMap_[ connectionId ]; -} - -CommitState DashProcessorOutput::commit_( const uint32_t outputConnection ) -{ - dash::Commit com = getDashContext()->commit( ); - CommitState ret = CS_NOCHANGE; - - if( !com.getImpl()->empty() ) - { - connectionMap_[ outputConnection ]->push( com ); - ret = CS_COMMITED; - } - - return ret; -} - -} diff --git a/livre/core/dashpipeline/DashProcessorOutput.h b/livre/core/dashpipeline/DashProcessorOutput.h deleted file mode 100644 index e5ab3f3c..00000000 --- a/livre/core/dashpipeline/DashProcessorOutput.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DashProcessorOutput_h_ -#define _DashProcessorOutput_h_ - -#include -#include -#include -#include - -namespace livre -{ - -typedef std::vector< dash::Commit > CommitVector; - -/** - * The DashProcessorOutput class is responsibe for receiving commits from many connections. - */ -class DashProcessorOutput : public ProcessorOutput, protected DashContextTrait -{ -public: - /** - * @param processor Adds DashProcessorOutput to the destination processor for connections. - */ - LIVRECORE_API DashProcessorOutput( DashProcessor& processor ); - - /** - * Adds a connection. - * @param connectionId Connection id. - * @param connection The connection between processors. - */ - LIVRECORE_API bool addConnection( const uint32_t connectionId, DashConnectionPtr connection ); - - /** - * Removes a connection. - * @param connectionId Connection id. - * @return True if connection exists and can be removed. - */ - LIVRECORE_API bool removeConnection( const uint32_t connectionId ); - - /** - * @param connectionId Connection id. - * @return The connection. If id is not valid, connection is empty. - */ - LIVRECORE_API DashConnectionPtr getConnection( const uint32_t connectionId ); - -private: - virtual CommitState commit_( const uint32_t outputConnection ); - - DashConnectionMap connectionMap_; - lunchbox::Lock connectionMapModificationLock_; - -}; - -} - -#endif // _ProcessorOutput_h_ diff --git a/livre/core/data/DataSource.cpp b/livre/core/data/DataSource.cpp index 039e1ab8..e9564aa6 100644 --- a/livre/core/data/DataSource.cpp +++ b/livre/core/data/DataSource.cpp @@ -109,6 +109,9 @@ MemoryUnitPtr DataSource::getData( const NodeId& nodeId ) return MemoryUnitPtr(); const LODNode& lodNode = getNode( nodeId ); + if( !lodNode.isValid( )) + return MemoryUnitPtr(); + return _impl->plugin->getData( lodNode ); } @@ -118,6 +121,9 @@ ConstMemoryUnitPtr DataSource::getData( const NodeId& nodeId ) const return ConstMemoryUnitPtr(); const LODNode& lodNode = getNode( nodeId ); + if( !lodNode.isValid( )) + return ConstMemoryUnitPtr(); + return _impl->plugin->getData( lodNode ); } diff --git a/livre/core/data/DataSourcePlugin.cpp b/livre/core/data/DataSourcePlugin.cpp index eb6c4a71..f3b31389 100644 --- a/livre/core/data/DataSourcePlugin.cpp +++ b/livre/core/data/DataSourcePlugin.cpp @@ -23,6 +23,7 @@ namespace livre { DataSourcePlugin::DataSourcePlugin() + : _lodNodeMap( 128 ) {} LODNode DataSourcePlugin::getNode( const NodeId& nodeId ) const diff --git a/livre/core/pipeline/AsyncData.cpp b/livre/core/pipeline/AsyncData.cpp deleted file mode 100644 index aadaf62d..00000000 --- a/livre/core/pipeline/AsyncData.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include - -#include - -#include - -namespace livre -{ - -typedef boost::shared_future< PortDataPtr > ConstPortDataFuture; -typedef boost::promise< PortDataPtr > ConstPortDataPromise; -typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; - -struct AsyncData::Impl -{ - Impl( const DataInfo& dataInfo ) - : _future( _promise.get_future( )) - , _dataInfo( dataInfo ) - {} - - ~Impl() - { - try - { - set( PortDataPtr( )); - } - catch( const std::runtime_error& ) - {} - } - - PortDataPtr get( const std::type_index& dataType ) const - { - const PortDataPtr& data = _future.get(); - - if( !data ) - LBTHROW( std::runtime_error( "Returns empty data" )); - - if( data->dataType != dataType ) - LBTHROW( std::runtime_error( "Types does not match on get value")); - - return data; - } - - void set( const PortDataPtr& data ) - { - if( data ) - { - if( _dataInfo.second != data->dataType ) - LBTHROW( std::runtime_error( "Types does not match on set value")); - } - - try - { - _promise.set_value( data ); - } - catch( const boost::promise_already_satisfied& ) - { - LBTHROW( std::runtime_error( "Data only can be set once")); - } - } - - bool isReady() const - { - return _future.is_ready(); - } - - void wait() const - { - _future.wait(); - } - - ConstPortDataPromise _promise; - mutable ConstPortDataFuture _future; - const DataInfo _dataInfo; -}; - -AsyncData::AsyncData( const DataInfo& dataInfo ) - : _impl( new Impl( dataInfo )) -{} - -PortDataPtr AsyncData::get( const std::type_index& dataType ) const -{ - return _impl->get( dataType ); -} - -AsyncData::~AsyncData() -{} - -std::type_index AsyncData::getDataType() const -{ - return _impl->_dataInfo.second; -} - -std::string AsyncData::getName() const -{ - return _impl->_dataInfo.first; -} - -void AsyncData::set( PortDataPtr data ) -{ - _impl->set( data ); -} - -bool AsyncData::isReady() const -{ - return _impl->isReady(); -} - -void AsyncData::wait() const -{ - _impl->wait(); -} - -bool AsyncData::operator==( const AsyncData& asyncData ) -{ - return &_impl->_promise == &asyncData._impl->_promise; -} - -void waitForAny( const Futures& futures ) -{ - if( futures.empty( )) - return; - - ConstPortDataFutures boostFutures; - boostFutures.reserve( futures.size( )); - for( const auto& future: futures ) - boostFutures.push_back( future._getAsyncData()._impl->_future ); - - boost::wait_for_any( boostFutures.begin(), boostFutures.end( )); -} - -} diff --git a/livre/core/pipeline/AsyncData.h b/livre/core/pipeline/AsyncData.h deleted file mode 100644 index 77856a8d..00000000 --- a/livre/core/pipeline/AsyncData.h +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _AsyncData_h_ -#define _AsyncData_h_ - -#include - -namespace livre -{ - -/** - * Provides thread safe operations for setting/retrieving/querying - * the data. The internal data has a name and data type. - */ -class AsyncData -{ -public: - - /** - * Constructor - * @param dataInfo name, data type pair - */ - explicit AsyncData( const DataInfo& dataInfo ); - ~AsyncData(); - - /** - * @return the data type of the connection - */ - std::type_index getDataType() const; - - /** - * @return the name of the connection - */ - std::string getName() const; - - /** - * Sets the data. - * @param data sets the data - * @throw std::runtime_error if data types does not match between data - * and current async data - * @throw std::runtime_error if data is set twice. - */ - void set( PortDataPtr data ); - - /** - * Gets the data. If data is not set it will block. - * @param dataType is the requested data type. - * @return the data. - * @throw std::runtime_error if getDataType() != dataType - */ - PortDataPtr get( const std::type_index& dataType ) const; - - /** - * @return true if data is set. - */ - bool isReady() const; - - /** - * Waits until data is set - */ - void wait() const; - - /** - * @param asyncData to be compared with - * @return true if both async data are same - */ - bool operator==( const AsyncData& asyncData ); - -private: - - friend void waitForAny( const Futures& futures ); - - struct Impl; - std::shared_ptr _impl; -}; - -} - -#endif // _AsyncData_h_ - diff --git a/livre/core/pipeline/Connection.h b/livre/core/pipeline/Connection.h deleted file mode 100644 index 46bf1826..00000000 --- a/livre/core/pipeline/Connection.h +++ /dev/null @@ -1,190 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _Connection_h_ -#define _Connection_h_ - -#include - -namespace livre -{ - -/** - * The Receiver class is an abstract class to receive information from the source. - */ -template< class T > -class Receiver -{ -public: - - /** - * ~Receiver destrcutor - */ - virtual ~Receiver() { } - - /** - * @return The popped commit. It may be blocked or unblocked according to implementation. - */ - virtual T pop( ) = 0; - - /** - * @param result Returns all the elements from the source into the result array. - */ - virtual void popAll( std::vector< T >& result ) = 0; - - /** - * Waits a certain amount of time for an pop event to happen, and returns the element to commit. - * @param timeout The time to wait for a pop to happen. - * @param commit The destination commit object. - * @return True if an element is popped from the source in certain amount of time. - */ - virtual bool timedPop( const unsigned timeout, T& commit ) = 0; - - /** - * @return True if any commit arrived. - */ - virtual bool hasData() const = 0; - - /** - * Cleans the items waiting to be processed. - */ - virtual void clear( ) = 0; -}; - -/** - * The Sender class is an abstract class for sending commits. - */ -template< class T > -class Sender -{ -public: - - virtual ~Sender( ) { } - - /** - * Pushes a commit. According to implemetation it can be blocking or unblocking. - * @param commit is the object to push. - */ - virtual void push( T& commit ) = 0; - - /** - * Pushes a list of commits. According to implemetation it can be blocking or unblocking. - * @param commitList is the list of commits to push. - */ - virtual void push( const std::vector< T >& commitList ) = 0; - - /** - * Cleans the items waiting to be processed. - */ - virtual void clear( ) = 0; -}; - -/** -* The Connection class keeps the shared queueing mechanism between sender and receiver. The connection is -* uni-directional from \see Sender to \see Receiver. -*/ -template< class T > -class Connection -{ -public: - - /** - * @return The element from the queueing mechanism. - */ - T pop( ) const - { - return receiver_->pop( ); - } - - /** - * Returns all the elements from the queueing mechanism. - * @param result Returns the elements from the queueing mechanism to the vector object. Oldest element has the - * lowest index. - */ - void popAll( std::vector< T >& result ) - { - receiver_->popAll( result ); - } - - /** - * Pops element from the queueing mechanism in a given time frame. - * @param timeout Waiting period for element to appear in queue mechanism. - * @param element Popped element from the queue. - * @return False if no element appear in the time frame. - */ - bool timedPop( const unsigned timeout, T& element ) - { - return receiver_->timedPop( timeout, element ); - } - - /** - * Pushes the latest change into sender objects queueing mechanism. - * @param commit - */ - void push( T& commit ) - { - sender_->push( commit ); - } - - /** - * Pushes the latest changes into sender objects queueing mechanism. - * @param commits The vector holding the changes. - */ - void push( const std::vector< T >& commits ) - { - sender_->push( commits ); - } - - /** - * @return True if receiver object has changes waiting. - */ - bool hasData( ) const - { - return receiver_->hasData( ); - } - - /** - * Cleans the queue. - */ - void clear( ) - { - sender_->clear(); - } - -protected: - - Connection( ) - { - } - - /** - * Receiver end of connection. - */ - std::shared_ptr< Receiver< T > > receiver_; - - /** - * Sender end of connection. - */ - std::shared_ptr< Sender< T > > sender_; -}; - -} - - -#endif // _Connection_h_ diff --git a/livre/core/pipeline/Executable.cpp b/livre/core/pipeline/Executable.cpp index 22e3c524..ce85b490 100644 --- a/livre/core/pipeline/Executable.cpp +++ b/livre/core/pipeline/Executable.cpp @@ -33,7 +33,7 @@ Executable::~Executable() void Executable::_schedule( Executor& executor ) { - executor.schedule( *this ); + executor.schedule( clone( )); } } diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h index 7c882e4c..f60c584f 100644 --- a/livre/core/pipeline/Executable.h +++ b/livre/core/pipeline/Executable.h @@ -21,7 +21,7 @@ #define _Executable_h_ #include -#include +#include #include namespace livre @@ -66,6 +66,11 @@ class Executable */ virtual void reset() {} + /** + * @return returns a copy + */ + virtual ExecutablePtr clone() const = 0; + virtual ~Executable(); protected: diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h index f05be62a..dd6b8469 100644 --- a/livre/core/pipeline/Executor.h +++ b/livre/core/pipeline/Executor.h @@ -45,7 +45,7 @@ class Executor * conditions * @param executable to schedule */ - virtual void schedule( Executable& executable ) = 0; + virtual void schedule( ExecutablePtr executable ) = 0; protected: diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h index d525efda..0ebfe01d 100644 --- a/livre/core/pipeline/Filter.h +++ b/livre/core/pipeline/Filter.h @@ -21,6 +21,9 @@ #define _Filter_h_ #include +#include +#include +#include namespace livre { diff --git a/livre/core/pipeline/Future.cpp b/livre/core/pipeline/Future.cpp deleted file mode 100644 index 5b0e9cc4..00000000 --- a/livre/core/pipeline/Future.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include - -namespace livre -{ - -struct Future::Impl -{ - Impl( const AsyncData& data ) - : _name( data.getName( )) - , _data( data ) - {} - - std::string getName() const - { - return _name; - } - - PortDataPtr get( const std::type_index& dataType ) const - { - return _data.get( dataType ); - } - - bool isReady() const - { - return _data.isReady(); - } - - void wait() const - { - return _data.wait(); - } - - std::string _name; - AsyncData _data; -}; - -Future::Future( const AsyncData& data ) - : _impl( new Future::Impl( data )) -{} - -Future::~Future() -{} - -std::string Future::getName() const -{ - return _impl->getName(); -} - -Future::Future( const Future& future, const std::string& name ) - : _impl( future._impl ) -{ - _impl->_name = name; -} - -void Future::wait() const -{ - return _impl->wait(); -} - -bool Future::isReady() const -{ - return _impl->isReady(); -} - -bool Future::operator==( const Future& future ) const -{ - return _impl->_data == future._impl->_data; -} - -const AsyncData& Future::_getAsyncData() const -{ - return _impl->_data; -} - -PortDataPtr Future::_getPtr( const std::type_index& dataType ) const -{ - return _impl->get( dataType ); -} - -} diff --git a/livre/core/pipeline/FutureMap.cpp b/livre/core/pipeline/FutureMap.cpp index 8446091d..810eda5a 100644 --- a/livre/core/pipeline/FutureMap.cpp +++ b/livre/core/pipeline/FutureMap.cpp @@ -18,8 +18,6 @@ */ #include -#include -#include namespace livre { @@ -39,8 +37,7 @@ struct FutureMapImpl void throwError( const std::string& name ) const { - LBTHROW( std::runtime_error( std::string( "Unknown future name: ") - + name )); + LBTHROW( std::logic_error( std::string( "Unknown future name: ") + name )); } bool hasFuture( const std::string& name ) const diff --git a/livre/core/pipeline/FutureMap.h b/livre/core/pipeline/FutureMap.h index c3348a14..b328c7cb 100644 --- a/livre/core/pipeline/FutureMap.h +++ b/livre/core/pipeline/FutureMap.h @@ -21,7 +21,7 @@ #define _FutureMap_h_ #include -#include +#include namespace livre { @@ -55,6 +55,8 @@ class FutureMap * futures with a given name are ready, this function will block. * @param name of the future. * @return the values of the futures. + * @throw std::logic_error when there is no future associated with the + * given name * @throw std::runtime_error when the data is not exact * type T */ @@ -72,6 +74,8 @@ class FutureMap * Gets the copy of ready value(s) with the given type T. * @param name of the future. * @return the values of the futures. + * @throw std::logic_error when there is no future associated with the + * given name * @throw std::runtime_error when the data is not exact * type T */ @@ -104,7 +108,7 @@ class FutureMap * Queries if futures are ready with a given name * @param name of the future. * @return true if all futures with the given name are ready. - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ bool isReady( const std::string& name ) const; @@ -120,7 +124,7 @@ class FutureMap /** * Waits all futures associated with a given name * @param name of the future. - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ void wait( const std::string& name ) const; @@ -135,14 +139,14 @@ class FutureMap /** * Waits all futures associated with a given name. * @param name of the future. - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ void waitForAny( const std::string& name ) const; /** * Waits all futures. - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ void waitForAny() const; @@ -164,7 +168,7 @@ class UniqueFutureMap /** * @param futures the list of futures. - * @throw std::runtime_error when futures are not unique in names + * @throw std::logic_error when futures are not unique in names */ explicit UniqueFutureMap( const Futures& futures ); ~UniqueFutureMap(); @@ -175,6 +179,8 @@ class UniqueFutureMap * block. * @param name of the future. * @return the value for the future. + * @throw std::logic_error when there is no future associated with the + * given name * @throw std::runtime_error when the data is not exact * type T */ @@ -187,6 +193,8 @@ class UniqueFutureMap /** * @param name of the future * @return the future associated with the name. + * @throw std::logic_error when there is no future associated with the + * given name */ Future getFuture( const std::string& name ) const; @@ -199,7 +207,7 @@ class UniqueFutureMap * Queries if future is ready for a given name * @param name of the future * @return true if all futures with the given name are ready. - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ bool isReady( const std::string& name ) const; @@ -207,7 +215,7 @@ class UniqueFutureMap /** * Queries if future is ready for a given name * @return true if all futures are ready. - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ bool isReady() const; @@ -215,14 +223,14 @@ class UniqueFutureMap /** * Waits for the future associated with a given name * @param name is the name assoicated with futures. - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ void wait( const std::string& name ) const; /** * Waits for all the futures - * @throw std::runtime_error when there is no future associated with the + * @throw std::logic_error when there is no future associated with the * given name */ void wait() const; diff --git a/livre/core/pipeline/FuturePromise.cpp b/livre/core/pipeline/FuturePromise.cpp new file mode 100644 index 00000000..845ee2e8 --- /dev/null +++ b/livre/core/pipeline/FuturePromise.cpp @@ -0,0 +1,246 @@ +/* Copyright (c) 2011-2016, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include + +#include + +namespace livre +{ + +typedef boost::shared_future< PortDataPtr > ConstPortDataFuture; +typedef boost::promise< PortDataPtr > ConstPortDataPromise; +typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; + +struct Future::Impl +{ + Impl( const ConstPortDataFuture& future, + const std::string& name, + const servus::uint128_t& uuid ) + : _name( name ) + , _future( future ) + , _uuid( uuid ) + {} + + std::string getName() const + { + return _name; + } + + PortDataPtr get( const std::type_index& dataType ) const + { + const PortDataPtr& data = _future.get(); + + if( !data ) + LBTHROW( std::runtime_error( "Returns empty data" )); + + if( data->dataType != dataType ) + LBTHROW( std::runtime_error( "Types does not match on get value")); + + return data; + } + + bool isReady() const + { + return _future.is_ready(); + } + + void wait() const + { + return _future.wait(); + } + + std::string _name; + mutable ConstPortDataFuture _future; + servus::uint128_t _uuid; +}; + +struct Promise::Impl +{ + Impl( const DataInfo& dataInfo ) + : _dataInfo( dataInfo ) + , _uuid( servus::make_UUID( )) + , _futureImpl( new Future::Impl( _promise.get_future(), + dataInfo.first, + _uuid )) + {} + + std::string getName() const + { + return _dataInfo.first; + } + + std::type_index getDataType() const + { + return _dataInfo.second; + } + + void set( const PortDataPtr& data ) + { + if( data ) + { + if( _dataInfo.second != data->dataType ) + LBTHROW( std::runtime_error( "Types does not match on set value")); + } + + try + { + _promise.set_value( data ); + } + catch( const boost::promise_already_satisfied& ) + { + LBTHROW( std::runtime_error( "Data only can be set once")); + } + } + + void reset() + { + try + { + _promise.set_value( PortDataPtr( )); + } + catch( const boost::promise_already_satisfied& ) + { + } + + ConstPortDataPromise promise; + _promise.swap( promise ); + _uuid = servus::make_UUID(); + _futureImpl->_future = _promise.get_future(); + _futureImpl->_uuid = _uuid; + } + + void flush() + { + try + { + _promise.set_value( PortDataPtr( )); + } + catch( const boost::promise_already_satisfied& ) + {} + } + + ConstPortDataPromise _promise; + const DataInfo _dataInfo; + servus::uint128_t _uuid; + std::shared_ptr< Future::Impl > _futureImpl; +}; + +Promise::Promise( const DataInfo& dataInfo ) + : _impl( new Promise::Impl( dataInfo )) +{} + +Promise::~Promise() +{} + +std::type_index Promise::getDataType() const +{ + return _impl->getDataType(); +} + +std::string Promise::getName() const +{ + return _impl->getName(); +} + +void Promise::flush() +{ + _impl->flush(); +} + +Future Promise::getFuture() const +{ + const Future ret( *this ); + return Future( ret ); +} + +void Promise::reset() +{ + _impl->reset(); +} + +void Promise::_set( PortDataPtr data ) +{ + _impl->set( data ); +} + +Future::Future( const Promise& promise ) + : _impl( promise._impl->_futureImpl ) +{} + +Future::Future( const Future& future ) + : _impl( new Future::Impl( future._impl->_future, + future.getName( ), + future._impl->_uuid )) +{} + +Future::~Future() +{} + +std::string Future::getName() const +{ + return _impl->getName(); +} + +Future::Future( const Future& future, const std::string& name ) + : _impl( new Future::Impl( future._impl->_future, name, future._impl->_uuid )) +{ +} + +void Future::wait() const +{ + return _impl->wait(); +} + +bool Future::isReady() const +{ + return _impl->isReady(); +} + +bool Future::operator==( const Future& future ) const +{ + return _impl->_uuid == future._impl->_uuid; +} + +const servus::uint128_t& Future::getId() const +{ + return _impl->_uuid; +} + +PortDataPtr Future::_getPtr( const std::type_index& dataType ) const +{ + return _impl->get( dataType ); +} + +void waitForAny( const Futures& futures ) +{ + if( futures.empty( )) + return; + + ConstPortDataFutures boostFutures; + boostFutures.reserve( futures.size( )); + for( const auto& future: futures ) + boostFutures.push_back( future._impl->_future ); + + boost::wait_for_any( boostFutures.begin(), boostFutures.end( )); +} + +} diff --git a/livre/core/pipeline/Future.h b/livre/core/pipeline/FuturePromise.h similarity index 57% rename from livre/core/pipeline/Future.h rename to livre/core/pipeline/FuturePromise.h index 99e50ea1..4d421c6b 100644 --- a/livre/core/pipeline/Future.h +++ b/livre/core/pipeline/FuturePromise.h @@ -17,8 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _Future_h_ -#define _Future_h_ +#ifndef _Promise_h_ +#define _Promise_h_ #include #include @@ -26,6 +26,74 @@ namespace livre { +/** + * Is similar to the std::promise classes in functionality and it has additional + * information for the name and data type. It provides methods to set the data. + */ +class Promise +{ +public: + + /** + * @param dataInfo is the name and type information for the data. + */ + Promise( const DataInfo& dataInfo ); + ~Promise(); + + /** + * @return the name of the connection + */ + std::type_index getDataType() const; + + /** + * @return the name of the connection + */ + std::string getName() const; + + /** + * Sets the port with the value. + * @param value to be set + * @throw std::runtime_error when the port data is not exact + * type T or there is no such port name. + */ + template< class T > + void set( const T& value ) + { + _set( std::make_shared< PortDataT< T >>( value )); + } + + /** + * Sets the promise with empty data if it is not set already + */ + void flush(); + + /** + * @return the future, that can be queried for data retrieval. + * @note reset() on the promise won't effect the future object. + * If such behaviour is needed Future has a Future( const Promise& ) + * consttructor + */ + Future getFuture() const; + + /** + * @resets the promise.( If related future is constructed using + * Future( const Promise& ) constructor, future can be re-used + * for different data ) + * The behavior of the function is undefined when multiple threads + * execute query/get from future. + */ + void reset(); + +private: + + friend class Future; + + void _set( PortDataPtr data ); + + struct Impl; + std::shared_ptr _impl; +}; + /** * The Future class is similar to the std::future classes in functionality and it has additional * information for the name and data type. It provides thread safe methods to query and get the @@ -37,6 +105,12 @@ class Future ~Future(); + /** + * Copy constructor + * @param future to be copied + */ + Future( const Future& future ); + /** * @return name of the future */ @@ -79,16 +153,27 @@ class Future */ bool operator!=( const Future& future ) const { return !(*this == future); } + /** + * @return the unique identifier for the future + */ + const servus::uint128_t& getId() const; + + /** + * Promise construction is needed when reset() on the promise + * affects the future directly. + * Further copies from the future is not effected by reset() + * on the promise. + * @param promise that future is retrieved + */ + Future( const Promise& promise ); + private: friend class Promise; - Future( const AsyncData& data ); friend void waitForAny( const Futures& future ); friend bool operator<( const Future& future1, const Future& future2 ); - const AsyncData& _getAsyncData() const; - template< class T > const T& _get() const { @@ -113,5 +198,5 @@ void waitForAny( const Futures& futures ); } -#endif // _Future_h_ +#endif // _Promise_h_ diff --git a/livre/core/pipeline/InputPort.cpp b/livre/core/pipeline/InputPort.cpp index f9c2bd92..7a4c3989 100644 --- a/livre/core/pipeline/InputPort.cpp +++ b/livre/core/pipeline/InputPort.cpp @@ -19,8 +19,7 @@ #include #include -#include -#include +#include namespace livre { @@ -54,7 +53,7 @@ struct InputPort::Impl if( getDataType() != port.getDataType( )) LBTHROW( std::runtime_error( "Data types does not match between ports")); - _futures.push_back( port.getPromise().getFuture( )); + _futures.emplace_back( port.getPromise( )); } bool disconnect( const OutputPort& port ) diff --git a/livre/core/pipeline/OutputPort.cpp b/livre/core/pipeline/OutputPort.cpp index e6ab6905..4230a188 100644 --- a/livre/core/pipeline/OutputPort.cpp +++ b/livre/core/pipeline/OutputPort.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include namespace livre { diff --git a/livre/core/pipeline/PipeFilter.cpp b/livre/core/pipeline/PipeFilter.cpp index 0caf7372..de12b359 100644 --- a/livre/core/pipeline/PipeFilter.cpp +++ b/livre/core/pipeline/PipeFilter.cpp @@ -23,8 +23,7 @@ #include #include #include -#include -#include +#include #include namespace livre @@ -96,6 +95,11 @@ struct PipeFilter::Impl promises.flush(); throw err; } + catch( const std::logic_error& err ) + { + promises.flush(); + throw err; + } } Promise getInputPromise( const std::string& portName ) @@ -176,6 +180,7 @@ struct PipeFilter::Impl _manuallySetPortsMap.clear(); for( auto& namePort: _outputMap ) namePort.second.reset(); + } PipeFilter& _pipeFilter; @@ -191,6 +196,11 @@ PipeFilter::PipeFilter( const std::string& name, : _impl( new Impl( *this, name, std::move( filter ))) {} +ExecutablePtr PipeFilter::clone() const +{ + return ExecutablePtr( new PipeFilter( *this )); +} + PipeFilter::~PipeFilter() {} diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index b41b951f..dfdf9956 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -59,8 +59,8 @@ class PipeFilter : public Executable * @return promise for the given input port. If there is no connection to the * input port, a new promise is created for the port and no further connections are allowed, * if there is a connection getting a promise is not allowed. - * @throw std::runtime_error if there is already a connection or if there is - * no inputport or it is a noification port. + * @throw std::logic_error if there is already a connection if there is + * no input port or it is a notification port. */ Promise getPromise( const std::string& portName ); @@ -96,6 +96,8 @@ class PipeFilter : public Executable private: + ExecutablePtr clone() const; + struct Impl; std::shared_ptr< Impl > _impl; }; diff --git a/livre/core/pipeline/Pipeline.cpp b/livre/core/pipeline/Pipeline.cpp index 879bd07a..df9e1f30 100644 --- a/livre/core/pipeline/Pipeline.cpp +++ b/livre/core/pipeline/Pipeline.cpp @@ -35,7 +35,7 @@ struct Pipeline::Impl {} void add( const std::string& name, - Pipeline::ExecutablePtr executable, + Pipeline::UniqueExecutablePtr executable, bool wait ) { if( _executableMap.count( name ) > 0 ) @@ -112,7 +112,7 @@ struct Pipeline::Impl void schedule( Executor& executor ) { for( auto& nameExec: _executableMap ) - executor.schedule( *nameExec.second ); + executor.schedule( nameExec.second->clone( )); } void reset() @@ -135,7 +135,7 @@ Pipeline::~Pipeline() {} void Pipeline::_add( const std::string& name, - ExecutablePtr exec, + UniqueExecutablePtr exec, bool wait ) { _impl->add( name, std::move( exec ), wait ); @@ -171,4 +171,9 @@ void Pipeline::_schedule( Executor& executor ) _impl->schedule( executor ); } +ExecutablePtr Pipeline::clone() const +{ + return ExecutablePtr( new Pipeline( *this )); +} + } diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index d46e7b2b..a54f62b5 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -36,7 +36,7 @@ class Pipeline : public Executable public: - typedef std::unique_ptr< Executable > ExecutablePtr; + typedef std::unique_ptr< Executable > UniqueExecutablePtr; Pipeline(); ~Pipeline(); @@ -52,7 +52,7 @@ class Pipeline : public Executable bool wait = true ) { _add( name, - ExecutablePtr( new Pipeline( pipeline )), + UniqueExecutablePtr( new Pipeline( pipeline )), wait ); } @@ -73,7 +73,7 @@ class Pipeline : public Executable { PipeFilterT< FilterT > pipeFilter( name, args... ); _add( name, - ExecutablePtr( new PipeFilter( pipeFilter )), + UniqueExecutablePtr( new PipeFilter( pipeFilter )), wait ); return pipeFilter; } @@ -108,12 +108,14 @@ class Pipeline : public Executable private: void _add( const std::string& name, - ExecutablePtr exec, + UniqueExecutablePtr exec, bool wait ); private: void _schedule( Executor& executor ) final; + ExecutablePtr clone() const final; + struct Impl; std::shared_ptr< Impl > _impl; diff --git a/livre/core/pipeline/Processor.cpp b/livre/core/pipeline/Processor.cpp deleted file mode 100644 index 1563f3da..00000000 --- a/livre/core/pipeline/Processor.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -namespace livre -{ - -Processor::Processor() -{ -} - -Processor::~Processor( ) -{} - -bool Processor::init() -{ - return initializeThreadRun_(); -} - -void Processor::run() -{ - while( isRunning() ) - runLoop_( ); -} - - -} diff --git a/livre/core/pipeline/Processor.h b/livre/core/pipeline/Processor.h deleted file mode 100644 index 2e511b8f..00000000 --- a/livre/core/pipeline/Processor.h +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _Processor_h_ -#define _Processor_h_ - -#include -#include -#include -#include - -#include -#include - -namespace livre -{ - -/** - * The Processor class is the base class of the processing step in a pipeline. It can listen - * the input connections and can behave accordingly. It has input connections and output connections - * ( \see Connection ). When underlying is started with start() method it starts the infinite loop. - */ -class Processor : public lunchbox::Thread -{ - friend class ProcessorInput; - friend class ProcessorOutput; - -public: - LIVRECORE_API Processor(); - LIVRECORE_API virtual ~Processor(); - - /** - * @return The \see ProcessorInput object that is responsible for receiving data from the incoming - * connections and delivering data. - */ - LIVRECORE_API ProcessorInputPtr getProcessorInput_( ) { return processorInputPtr_; } - - /** - * @return The \see ProcessorInput object that is responsible for receiving data from the incoming - * connections and delivering data. - * @warning Casts the object to the right Connection type. If returned object is not type T, an empty - * shared_ptr is returned. - */ - template< class T > - std::shared_ptr< T > getProcessorInput_( ) - { - return std::dynamic_pointer_cast< T >( processorInputPtr_ ); - } - /** - * @return The \see ProcessorOutput object that is responsible for sending data to the outgoing - * connections and delivering data. - * @warning Casts the object to the right Connection type. If returned object is not type T, an empty - * shared_ptr is returned. - */ - LIVRECORE_API ProcessorOutputPtr getProcessorOutput_( ) { return processorOutputPtr_; } - - /** - * @return The \see ProcessorInput object that is responsible for receiving data from the incoming - * connections and delivering data. - * @warning Casts the object to the right Connection type. If returned object is not type T, an empty - * shared_ptr is returned. - */ - template< class T > - std::shared_ptr< T > getProcessorOutput_( ) - { - return std::dynamic_pointer_cast< T >( processorOutputPtr_ ); - } - -protected: - - /** - * Is called before commiting. - * @param connection Connection number. - * @return False if commit is abandoned. - */ - virtual bool onPreCommit_( uint32_t connection LB_UNUSED ) { return true; } - - /** - * Is called after commiting. - * @param connection Connection number. - * @param state State of the commit. \see livre::CommitState - */ - virtual void onPostCommit_( uint32_t connection LB_UNUSED, CommitState state LB_UNUSED ) { } - - /** - * Is called after applying changes. - * @param connection Connection number. - * @return False if apply is abandoned. - */ - virtual bool onPreApply_( uint32_t connection LB_UNUSED ) { return true; } - - /** - * Is called after changes are applied. - * @param connection Connection number. - * @param applySuccessful True if apply is successfull on connection. - */ - virtual void onPostApply_( uint32_t connection LB_UNUSED, bool applySuccessful LB_UNUSED ) { } - - /** The parent thread waits for this to finish when start() is invoked. */ - LIVRECORE_API bool init() override; - - /** - * Is called when start() method is invoked for the thread. - */ - LIVRECORE_API void run() override; - - /** - * Is called in case any initialization is needed before starting the infinite loop. - * @return True if initialization is successfull. - */ - virtual bool initializeThreadRun_( ) { return true; } - - /** - * Is called in the infinite loop. Most of the application logic goes into this function and its callees. - */ - virtual void runLoop_( ) { } - - /** - * The incoming connections to the processor object - */ - ProcessorInputPtr processorInputPtr_; - - /** - * The outgoing connections from the processor object. - */ - ProcessorOutputPtr processorOutputPtr_; - - /** - * Dash context of the thread. - */ - dash::Context context_; -}; - - -} - -#endif // _Processor_h_ diff --git a/livre/core/pipeline/ProcessorInput.cpp b/livre/core/pipeline/ProcessorInput.cpp deleted file mode 100644 index 09e59163..00000000 --- a/livre/core/pipeline/ProcessorInput.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include - -namespace livre -{ - -#define MAX_CONNECTIONS 64 - -ProcessorInput::ProcessorInput( Processor& processor ) - : processor_( processor ) -{ - -} - -ProcessorInput::~ProcessorInput() -{ -} - -bool ProcessorInput::dataWaitingOnInput( const uint32_t inputConnection ) const -{ - BoolMap::const_iterator it = blockedMap_.find( inputConnection ); - - if( it->second ) - return false; - - return dataWaitingOnInput_( inputConnection ); -} - -bool ProcessorInput::apply( const uint32_t inputConnection ) -{ - if( blockedMap_[ inputConnection ] ) - return false; - - if( !processor_.onPreApply_( inputConnection ) ) - return false; - - const bool ret = apply_( inputConnection ); - processor_.onPostApply_( inputConnection, ret ); - return ret; -} - -bool ProcessorInput::applyAllTimed( const uint32_t inputConnection, const uint32_t timeMs ) -{ - if( blockedMap_[ inputConnection ] ) - return false; - - if( !processor_.onPreApply_( inputConnection ) ) - return false; - - const bool ret = applyAllTimed_( inputConnection, timeMs ); - processor_.onPostApply_( inputConnection, ret ); - return ret; -} - -bool ProcessorInput::applyAll( const uint32_t inputConnection ) -{ - if( blockedMap_[ inputConnection ] ) - return false; - - if( !processor_.onPreApply_( inputConnection ) ) - return false; - - const bool ret = applyAll_( inputConnection ); - processor_.onPostApply_( inputConnection, ret ); - return ret; -} - -void ProcessorInput::setBlocked( const bool block, const uint32_t inputConnection /* =0 */) -{ - blockedMap_[ inputConnection ] = block; -} - - -bool ProcessorInput::isBlocked( const uint32_t inputConnection /* =0 */) const -{ - BoolMap::const_iterator it = blockedMap_.find( inputConnection ); - return it->second; -} - -size_t ProcessorInput::getNumberOfConnections() const -{ - return blockedMap_.size(); -} - -void ProcessorInput::addConnection_( const uint32_t inputConnection ) -{ - blockedMap_[ inputConnection ] = false; -} - -void ProcessorInput::removeConnection_( const uint32_t inputConnection ) -{ - blockedMap_.erase( inputConnection ); -} - -} diff --git a/livre/core/pipeline/ProcessorInput.h b/livre/core/pipeline/ProcessorInput.h deleted file mode 100644 index 21288bd1..00000000 --- a/livre/core/pipeline/ProcessorInput.h +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _ProcessorInput_h_ -#define _ProcessorInput_h_ - -#include -#include - -namespace livre -{ - -/** - * The ProcessorInput class provides abstract methods for application of commits to the context. The derived - * class should fill the methods according to its \see Connection object type. - * @todo Decision of abstraction of Commits when needed. Therefore, moving the connection list to the ProcessorInput - * class. - */ -class ProcessorInput -{ -public: - /** - * @param processor Processor, which the input belonging to. - */ - LIVRECORE_API ProcessorInput( Processor& processor ); - - LIVRECORE_API virtual ~ProcessorInput(); - - /** - * @param inputConnection Connection number. - * @return True if data is waiting on input, false if connection is blocked. - */ - LIVRECORE_API bool dataWaitingOnInput( const uint32_t inputConnection ) const; - - /** - * Applies the oldest and single change to the context. Blocks until a commit arrives. - * @param inputConnection Connection number. - * @return True if apply is successful. If result is false, either connection is blocked or commit is - * empty. - */ - LIVRECORE_API bool apply( const uint32_t inputConnection ); - - /** - * Applies all the changes to the context. Blocks until a commit arrives. - * @param inputConnection inputConnection Connection number. - * @return True if apply is successful. If result is false, either connection is blocked or commit is - * empty. - */ - LIVRECORE_API bool applyAll( const uint32_t inputConnection ); - - /** - * Applies all the changes to the context. Waits for an commit to arrive - * for a certain amount of time, if no commit is in the \see connection. If there are already commits, returns - * immediately. - * @param inputConnection Connection number. - * @param timeMs Time to wait. - * @return True if apply is successful. If result is false, either connection is blocked, commit is - * empty or waiting time is over without any activity. - */ - LIVRECORE_API bool applyAllTimed( const uint32_t inputConnection, const uint32_t timeMs ); - - /** - * Blocks the connection, no operation is allowed after the blocking. - * @param block Blocking flag, if true connection is blocked. - * @param inputConnection Connection number. - */ - LIVRECORE_API void setBlocked( const bool block, const uint32_t inputConnection ); - - /** - * @param inputConnection Connection number. - * @return True if the connection is blocked. - */ - LIVRECORE_API bool isBlocked( const uint32_t inputConnection ) const; - - /** - * @return The number of connections. - */ - size_t getNumberOfConnections() const; - -protected: - - /** - * \see ProcessorInput::dataWaitingOnInput(). Derived class should implement. - */ - virtual bool dataWaitingOnInput_( const uint32_t inputConnection ) const = 0; - - /** - * \see ProcessorInput::apply(). Derived class should implement. - */ - virtual bool apply_( const uint32_t inputConnection ) = 0; - - /** - * \see ProcessorInput::applyAll(). Derived class should implement. - */ - virtual bool applyAll_( const uint32_t inputConnection ) = 0; - - /** - * \see ProcessorInput::applyAllTimed(). Derived class should implement. - */ - virtual bool applyAllTimed_( const uint32_t inputConnection, const uint32_t timeMs ) = 0; - - /** - * Adds the basic information for connection id. - * @param inputConnection Connection id. - */ - void addConnection_( const uint32_t inputConnection ); - - /** - * Removes the basic information for connection id. - * @param inputConnection Connection id. - */ - void removeConnection_( const uint32_t inputConnection ); - -private: - - Processor& processor_; - - BoolMap blockedMap_; -}; - -} - -#endif // _ProcessorInput_h_ diff --git a/livre/core/pipeline/ProcessorOutput.cpp b/livre/core/pipeline/ProcessorOutput.cpp deleted file mode 100644 index 31c5f87a..00000000 --- a/livre/core/pipeline/ProcessorOutput.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include - -namespace livre -{ - -ProcessorOutput::ProcessorOutput( Processor& processor ) - : processor_( processor ) -{ - -} - -ProcessorOutput::~ProcessorOutput() -{ -} - -CommitState ProcessorOutput::commit( const uint32_t outputConnection ) -{ - if( blockedMap_[ outputConnection ] ) - return CS_BLOCKED; - - if( !processor_.onPreCommit_( outputConnection ) ) - return CS_NOCHANGE; - - const CommitState ret = commit_( outputConnection ); - processor_.onPostCommit_( outputConnection, ret ); - return ret; - -} - -void ProcessorOutput::setBlocked( const bool block, const uint32_t outputConnection /* =0 */) -{ - blockedMap_[ outputConnection ] = block; -} - -bool ProcessorOutput::isBlocked( const uint32_t outputConnection /* =0 */ ) const -{ - BoolMap::const_iterator it = blockedMap_.find( outputConnection ); - - return it->second; -} - -size_t ProcessorOutput::getNumberOfConnections() const -{ - return blockedMap_.size(); -} - -void ProcessorOutput::addConnection_( const uint32_t outputConnection ) -{ - blockedMap_[ outputConnection ] = false; -} - -void ProcessorOutput::removeConnection_( const uint32_t outputConnection ) -{ - blockedMap_.erase( outputConnection ); -} - -} diff --git a/livre/core/pipeline/ProcessorOutput.h b/livre/core/pipeline/ProcessorOutput.h deleted file mode 100644 index 9e7073f6..00000000 --- a/livre/core/pipeline/ProcessorOutput.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _ProcessorOutput_h_ -#define _ProcessorOutput_h_ - -#include -#include - -namespace livre -{ - -/** - * The CommitState enum states the situation of commit - */ -enum CommitState -{ - CS_COMMITED, //!< The commit is sent to the receiver. - CS_NOCHANGE, //!< Nothing to commit. - CS_BLOCKED //!< Did not commited. -}; - -/** - * The ProcessorOutput class is to send commits to connections. - */ -class ProcessorOutput -{ -public: - LIVRECORE_API ProcessorOutput( Processor& processor ); - - LIVRECORE_API virtual ~ProcessorOutput( ); - - /** - * Sends commits to the given \see Connection object. - * @param outputConnection Output connection id. - * @return The state of the commit. - */ - LIVRECORE_API CommitState commit( const uint32_t outputConnection ); - - /** - * Blocks the connection, no operation is allowed after the blocking. - * @param block Blocking flag, if true connection is blocked. - * @param inputConnection Connection number. - */ - LIVRECORE_API void setBlocked( const bool block, const uint32_t inputConnection ); - - /** - * @param inputConnection Connection number. - * @return True if the connection is blocked. - */ - LIVRECORE_API bool isBlocked( const uint32_t inputConnection ) const; - - /** - * @return The number of connections. - */ - size_t getNumberOfConnections() const; - -protected: - - /** - * \see ProcessorOutput::commit() - */ - virtual CommitState commit_( const uint32_t outputConnection ) = 0; - - /** - * Adds the basic information for connection id - * @param outputConnection Connection id. - */ - void addConnection_( const uint32_t outputConnection ); - - /** - * Removes the basic information for connection id - * @param outputConnection Connection id. - */ - void removeConnection_( const uint32_t outputConnection ); - -private: - - Processor& processor_; - - BoolMap blockedMap_; - -}; - -} - -#endif // _ProcessorOutput_h_ diff --git a/livre/core/pipeline/Promise.cpp b/livre/core/pipeline/Promise.cpp deleted file mode 100644 index 8bdb7e48..00000000 --- a/livre/core/pipeline/Promise.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include - -namespace livre -{ - -struct Promise::Impl -{ - Impl( const DataInfo& dataInfo ) - : _data( dataInfo ) - , _future( _data ) - {} - - std::string getName() const - { - return _data.getName(); - } - - std::type_index getDataType() const - { - return _data.getDataType(); - } - - void set( const PortDataPtr& data ) - { - _data.set( data ); - } - - void reset() - { - flush(); - _data = AsyncData( DataInfo( _data.getName(), _data.getDataType( ))); - _future = Future( _data ); - } - - void flush() - { - try - { - _data.set( PortDataPtr( )); - } - catch( const std::runtime_error& ) - {} - } - - AsyncData _data; - Future _future; -}; - -Promise::Promise( const DataInfo& dataInfo ) - : _impl( new Promise::Impl( dataInfo )) -{} - -Promise::~Promise() -{} - -std::type_index Promise::getDataType() const -{ - return _impl->getDataType(); -} - -std::string Promise::getName() const -{ - return _impl->getName(); -} - -void Promise::flush() -{ - _impl->flush(); -} - -Future Promise::getFuture() const -{ - return _impl->_future; -} - -void Promise::reset() -{ - _impl->reset(); -} - -void Promise::_set( PortDataPtr data ) -{ - _impl->set( data ); -} - -} diff --git a/livre/core/pipeline/Promise.h b/livre/core/pipeline/Promise.h deleted file mode 100644 index ecf23dff..00000000 --- a/livre/core/pipeline/Promise.h +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (c) 2011-2016, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _Promise_h_ -#define _Promise_h_ - -#include -#include -#include - -namespace livre -{ - - -/** - * Is similar to the std::promise classes in functionality and it has additional - * information for the name and data type. It provides methods to set the data. - */ -class Promise -{ -public: - - /** - * @param dataInfo is the name and type information for the data. - */ - Promise( const DataInfo& dataInfo ); - ~Promise(); - - /** - * @return the name of the connection - */ - std::type_index getDataType() const; - - /** - * @return the name of the connection - */ - std::string getName() const; - - /** - * Sets the port with the value. - * @param value to be set - * @throw std::runtime_error when the port data is not exact - * type T or there is no such port name. - */ - template< class T > - void set( const T& value ) - { - _set( std::make_shared< PortDataT< T >>( value )); - } - - /** - * Sets the promise with empty data if it is not set already - */ - void flush(); - - /** - * @return the future, that can be queried for data retrieval - */ - Future getFuture() const; - - /** - * @resets the promise. ( Future is reset and value can be set again ) - * The behavior of the function is undefined when multiple threads - * execute query/get from future. - */ - void reset(); - -private: - - void _set( PortDataPtr data ); - - struct Impl; - std::shared_ptr _impl; -}; - -} - -#endif // _Promise_h_ - diff --git a/livre/core/pipeline/PromiseMap.cpp b/livre/core/pipeline/PromiseMap.cpp index c2bdd67f..ea2fea75 100644 --- a/livre/core/pipeline/PromiseMap.cpp +++ b/livre/core/pipeline/PromiseMap.cpp @@ -18,7 +18,6 @@ */ #include -#include namespace livre { @@ -43,9 +42,7 @@ struct PromiseMap::Impl void throwError( const std::string& name ) const { - std::stringstream err; - err << "Unknown promise name: " << name << std::endl; - LBTHROW( std::runtime_error( err.str( ))); + LBTHROW( std::logic_error( std::string( "Unknown promise name: ") + name )); } bool hasPromise( const std::string& name ) const @@ -67,6 +64,20 @@ struct PromiseMap::Impl } } + void reset( const std::string& name ) const + { + getPromise( name ).reset(); + } + + void reset() const + { + for( auto& namePromise: _promiseMap ) + { + Promise promise = namePromise.second; + promise.reset(); + } + } + Promise getPromise( const std::string& name ) const { if( !hasPromise( name )) @@ -92,7 +103,17 @@ void PromiseMap::flush( const std::string& name ) const void PromiseMap::flush() const { - _impl->flush(); + _impl->flush(); +} + +void PromiseMap::reset( const std::string& name) const +{ + _impl->reset( name ); +} + +void PromiseMap::reset() const +{ + _impl->flush(); } Promise PromiseMap::getPromise( const std::string& name ) const diff --git a/livre/core/pipeline/PromiseMap.h b/livre/core/pipeline/PromiseMap.h index e1c55a20..3b320d59 100644 --- a/livre/core/pipeline/PromiseMap.h +++ b/livre/core/pipeline/PromiseMap.h @@ -20,7 +20,7 @@ #ifndef _PromiseMap_h_ #define _PromiseMap_h_ -#include +#include #include namespace livre @@ -48,8 +48,10 @@ class PromiseMap * Sets the port with the value. * @param name of the promise * @param value to be set + * @throw std::logic_error when there is no promise associated with the + * given name * @throw std::runtime_error when the port data is not exact - * type T or there is no such port name. + * type T */ template< class T > void set( const std::string& name, const T& value ) const @@ -60,16 +62,33 @@ class PromiseMap /** * Writes empty values to promises which are not set already. * @param name of the promise. - * @throw std::runtime_error there is no such port name. + * @throw std::logic_error when there is no promise associated with the + * given name */ void flush( const std::string& name ) const; /** * Writes empty values to promises which are not set already. - * @throw std::runtime_error there is no such port name. + * @throw std::logic_error when there is no promise associated with the + * given name */ void flush() const; + /** + * Resets the promise after they are done. + * @param name of the promise. + * @throw std::logic_error when there is no promise associated with the + * given name + */ + void reset( const std::string& name ) const; + + /** + * Resets the promises after they are done. + * @throw std::logic_error when there is no promise associated with the + * given name + */ + void reset() const; + private: struct Impl; diff --git a/livre/core/pipeline/SimpleExecutor.cpp b/livre/core/pipeline/SimpleExecutor.cpp index a543876d..623090fa 100644 --- a/livre/core/pipeline/SimpleExecutor.cpp +++ b/livre/core/pipeline/SimpleExecutor.cpp @@ -24,9 +24,8 @@ #include #include #include -#include -#include -#include +#include +#include #include #include @@ -44,13 +43,13 @@ namespace livre bool operator<( const Future& future1, const Future& future2 ) { - return future1._impl.get() < future2._impl.get(); + return future1.getId() < future2.getId(); } struct SimpleExecutor::Impl { - Impl( const size_t threadCount, GLContextPtr glContext ) + Impl( const size_t threadCount, ConstGLContextPtr glContext ) : _workers( threadCount, glContext ) , _unlockPromise( DataInfo( "LoopUnlock", getType< bool >( ))) , _workThread( boost::thread( boost::bind( &Impl::schedule, this ))) @@ -70,7 +69,7 @@ struct SimpleExecutor::Impl void schedule() { std::set< Future > inputConditions = { _unlockPromise.getFuture() }; - Executables executables; + std::list< ExecutablePtr > executables; while( true ) { waitForAny( Futures( inputConditions.begin(), inputConditions.end( ))); @@ -80,7 +79,7 @@ struct SimpleExecutor::Impl { while( !_mtWorkQueue.empty( )) { - Executable* exec = _mtWorkQueue.pop(); + ExecutablePtr exec = _mtWorkQueue.pop(); // In destruction tine "0" is pushed to the queue // and no further executable is scheduled if( !exec ) @@ -91,22 +90,19 @@ struct SimpleExecutor::Impl inputConditions.insert( preConds.begin(), preConds.end( )); } - inputConditions.erase( _unlockPromise.getFuture( )); _unlockPromise.reset(); - inputConditions.insert( _unlockPromise.getFuture( )); - } } - Executables::iterator it = executables.begin(); + std::list< ExecutablePtr >::iterator it = executables.begin(); while( it != executables.end( )) { - Executable* executable = *it; + ExecutablePtr executable = *it; const Futures& preConds = executable->getPreconditions(); const FutureMap futureMap( preConds ); if( futureMap.isReady( )) { - _workers.schedule( *executable ); + _workers.schedule( executable ); it = executables.erase( it ); for( const auto& future: futureMap.getFutures( )) inputConditions.erase( future ); @@ -122,23 +118,23 @@ struct SimpleExecutor::Impl _mtWorkQueue.clear(); } - void schedule( Executable& exec ) + void schedule( ExecutablePtr exec ) { ScopedLock lock( _promiseReset ); const bool wasEmpty = _mtWorkQueue.empty(); - _mtWorkQueue.push_back( &exec ); + _mtWorkQueue.push_back( exec ); if( wasEmpty ) _unlockPromise.set( true ); } - lunchbox::MTQueue< Executable* > _mtWorkQueue; + lunchbox::MTQueue< ExecutablePtr > _mtWorkQueue; Workers _workers; Promise _unlockPromise; boost::mutex _promiseReset; boost::thread _workThread; }; -SimpleExecutor::SimpleExecutor( const size_t threadCount, GLContextPtr glContext ) +SimpleExecutor::SimpleExecutor( const size_t threadCount, ConstGLContextPtr glContext ) : _impl( new Impl( threadCount, glContext )) { } @@ -151,7 +147,7 @@ void SimpleExecutor::clear() _impl->clear(); } -void SimpleExecutor::schedule( Executable& executable ) +void SimpleExecutor::schedule( ExecutablePtr executable ) { _impl->schedule( executable ); } diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h index e5179ce2..7f6c2e7a 100644 --- a/livre/core/pipeline/SimpleExecutor.h +++ b/livre/core/pipeline/SimpleExecutor.h @@ -44,14 +44,14 @@ class SimpleExecutor : public Executor * the worker threads will share the context with the given context */ SimpleExecutor( size_t threadCount, - GLContextPtr glContext = GLContextPtr( )); + ConstGLContextPtr glContext = ConstGLContextPtr( )); virtual ~SimpleExecutor(); /** * @copydoc Executor::schedule */ - void schedule( Executable& executable ) final; + void schedule( ExecutablePtr executable ) final; /** * @copydoc Executor::clear diff --git a/livre/core/pipeline/Workers.cpp b/livre/core/pipeline/Workers.cpp index d2fc50b6..52905e9c 100644 --- a/livre/core/pipeline/Workers.cpp +++ b/livre/core/pipeline/Workers.cpp @@ -32,7 +32,7 @@ struct Workers::Impl { Impl( Workers& workers, const size_t nThreads, - const GLContextPtr& glContext ) + const ConstGLContextPtr& glContext ) : _workers( workers ) , _glContext( glContext ) { @@ -43,34 +43,42 @@ struct Workers::Impl void execute() { + GLContextPtr context; if( _glContext ) { - GLContextPtr context = _glContext->clone(); + context = _glContext->clone(); context->share( *_glContext ); context->makeCurrent(); } while( true ) { - Executable* exec = _workQueue.pop(); + ExecutablePtr exec = _workQueue.pop(); if( !exec ) break; exec->execute(); } + + if( context ) + { + context->doneCurrent(); + context.reset(); + } } ~Impl() { for( size_t i = 0; i < getSize(); ++i ) - _workQueue.push( 0 ); + _workQueue.push( ExecutablePtr( )); _threadGroup.join_all(); + _glContext.reset(); } - void submitWork( Executable& executable ) + void submitWork( ExecutablePtr executable ) { - _workQueue.push( &executable ); + _workQueue.push( executable ); } size_t getSize() const @@ -79,13 +87,13 @@ struct Workers::Impl } Workers& _workers; - lunchbox::MTQueue< Executable* > _workQueue; + lunchbox::MTQueue< ExecutablePtr > _workQueue; boost::thread_group _threadGroup; - const GLContextPtr _glContext; + ConstGLContextPtr _glContext; }; Workers::Workers( const size_t nThreads, - GLContextPtr glContext ) + ConstGLContextPtr glContext ) : _impl( new Workers::Impl( *this, nThreads, glContext )) @@ -94,7 +102,7 @@ Workers::Workers( const size_t nThreads, Workers::~Workers() {} -void Workers::schedule( Executable& executable ) +void Workers::schedule( ExecutablePtr executable ) { _impl->submitWork( executable ); } diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index 841e2e60..33494553 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -39,7 +39,7 @@ class Workers * context. */ Workers( size_t nThreads = 4, - GLContextPtr glContext = GLContextPtr( )); + ConstGLContextPtr glContext = ConstGLContextPtr( )); ~Workers(); /** @@ -47,7 +47,7 @@ class Workers * queue. * @param executable is executed by thread pool. */ - void schedule( Executable& executable ); + void schedule( ExecutablePtr executable ); /** * @return the size of thread pool. diff --git a/livre/core/render/FrameInfo.cpp b/livre/core/render/FrameInfo.cpp index 9840eeb8..95a64da1 100644 --- a/livre/core/render/FrameInfo.cpp +++ b/livre/core/render/FrameInfo.cpp @@ -26,6 +26,8 @@ FrameInfo::FrameInfo( const Frustum& frustum_, const uint32_t frameId_ ) : frustum( frustum_ ) , frameId( frameId_ ) + , nAvailable( 0 ) + , nNotAvailable( 0 ) { } diff --git a/livre/core/render/FrameInfo.h b/livre/core/render/FrameInfo.h index c77dfb2a..f562a1f2 100644 --- a/livre/core/render/FrameInfo.h +++ b/livre/core/render/FrameInfo.h @@ -33,11 +33,11 @@ struct FrameInfo LIVRECORE_API FrameInfo( const Frustum& frustum, const uint32_t frameId ); - NodeIds allNodes; //!< The list of nodes to be rendered. - NodeIds notAvailableRenderNodes; //!< The unavailable nodes for rendering. - ConstCacheObjects renderNodes; //!< The list of nodes to be rendered. Frustum frustum; //!< The current frustum. uint32_t frameId ; //!< The current frame id. + + size_t nAvailable; //!< Number of available nodes + size_t nNotAvailable; //!< Number of not available nodes }; } diff --git a/livre/core/render/GLContext.cpp b/livre/core/render/GLContext.cpp index 2bc8f888..9019fe1f 100644 --- a/livre/core/render/GLContext.cpp +++ b/livre/core/render/GLContext.cpp @@ -42,6 +42,11 @@ void GLContext::makeCurrent() perThreadContext_.reset( this ); } +void GLContext::doneCurrent() +{ + perThreadContext_.reset( 0 ); +} + const GLContext* GLContext::getCurrent() { return perThreadContext_.get(); diff --git a/livre/core/render/GLContext.h b/livre/core/render/GLContext.h index 2b0da5b4..95a648e4 100644 --- a/livre/core/render/GLContext.h +++ b/livre/core/render/GLContext.h @@ -55,7 +55,7 @@ class GLContext /** * Clears the current context. */ - virtual void doneCurrent() = 0; + virtual void doneCurrent(); /** * Gets the current context diff --git a/livre/core/render/SelectVisibles.h b/livre/core/render/SelectVisibles.h new file mode 100644 index 00000000..d5d7ab87 --- /dev/null +++ b/livre/core/render/SelectVisibles.h @@ -0,0 +1,167 @@ +/* Copyright (c) 2015, EPFL/Blue Brain Project + * Stefan.Eilemann@epfl.ch + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LIVRE_SELECTVISIBLES_H +#define LIVRE_SELECTVISIBLES_H + +#include +#include +#include +#include +#include +#include +#include + +//#define LIVRE_STATIC_DECOMPOSITION + +namespace livre +{ +/** Selects all visible rendering nodes */ +class SelectVisibles : public DataSourceVisitor +{ +public: + SelectVisibles( const DataSource& dataSource, + const Frustum& frustum, + const uint32_t windowHeight, + const float screenSpaceError, + const uint32_t minLOD, + const uint32_t maxLOD, + const Range& range ) + : DataSourceVisitor( dataSource ) + , _frustum( frustum ) + , _windowHeight( windowHeight ) + , _screenSpaceError( screenSpaceError ) + , _minLOD( minLOD ) + , _maxLOD( maxLOD ) + , _range( range ) + {} + + const NodeIds& getVisibles() const { return _visibles; } + +protected: + void visitPre() final { _visibles.clear(); } + + void visit( const LODNode& lodNode, VisitState& state ) final + { + const Boxf& worldBox = lodNode.getWorldBox(); + const bool isInFrustum = _frustum.boxInFrustum( worldBox ); + if( !isInFrustum ) + { + state.setVisitChild( false ); + return; + } + + Vector3f vmin, vmax; + const Plane& nearPlane = _frustum.getNearPlane(); + + worldBox.computeNearFar( nearPlane, vmin, vmax ); + + Vector4f hVmin = vmin; + hVmin[ 3 ] = 1.0f; + + Vector4f hVmax = vmax; + hVmax[ 3 ] = 1.0f; + + // The bounding box intersects the plane + if( _frustum.getNearPlane().dot( hVmin ) < 0 || + _frustum.getNearPlane().dot( hVmax ) < 0 ) + { + // Where eye direction intersects with near plane + vmin = _frustum.getEyePos() - _frustum.getViewDir() * _frustum.nearPlane(); + } + + const Vector3f voxelBox = lodNode.getVoxelBox().getSize(); + const Vector3f worldSpacePerVoxel = worldBox.getSize() / voxelBox; + + bool lodVisible = isLODVisible( _frustum, + vmin, + worldSpacePerVoxel.find_min(), + _windowHeight, + _screenSpaceError ); + + const VolumeInformation& volInfo = getDataSource().getVolumeInfo(); + const uint32_t depth = volInfo.rootNode.getDepth(); + lodVisible = ( lodVisible && lodNode.getRefLevel() >= _minLOD ) + || ( lodNode.getRefLevel() == _maxLOD ) + || ( lodNode.getRefLevel() == depth - 1 ); + + if( lodVisible ) + _visibles.push_back( lodNode.getNodeId( )); + + state.setVisitChild( !lodVisible ); + } + + bool isLODVisible( const Frustum& frustum, + const Vector3f& worldCoord, + const float worldSpacePerVoxel, + const uint32_t windowHeight, + const float screenSpaceError ) const + { + const float t = frustum.top(); + const float b = frustum.bottom(); + + const float worldSpacePerPixel = ( t - b ) / windowHeight; + const float pixelPerVoxel = worldSpacePerVoxel / worldSpacePerPixel; + + Vector4f hWorldCoord = worldCoord; + hWorldCoord[ 3 ] = 1.0f; + const float distance = std::abs( frustum.getNearPlane().dot( hWorldCoord )); + + const float n = frustum.nearPlane(); + const float pixelPerVoxelInDistance = pixelPerVoxel * n / ( n + distance ); + + return pixelPerVoxelInDistance <= screenSpaceError; + } + + void visitPost() final + { + // Sort-last range selection: +#ifndef LIVRE_STATIC_DECOMPOSITION + const size_t startIndex = _range[0] * _visibles.size(); + const size_t endIndex = _range[1] * _visibles.size(); +#endif + NodeIds selected; + for( size_t i = 0; i < _visibles.size(); ++i ) + { +#ifdef LIVRE_STATIC_DECOMPOSITION + const Range& nodeRange = + _visibles[ i ].getRange(); + const bool isInRange = nodeRange[ 1 ] > _range[0] && + nodeRange[ 1 ] <= _range[1]; +#else + const bool isInRange = i >= startIndex && i < endIndex; +#endif + if( isInRange ) + selected.push_back( _visibles[i] ); + } + _visibles.swap( selected ); + } + +private: + + const Frustum _frustum; + const uint32_t _windowHeight; + const float _screenSpaceError; + const uint32_t _minLOD; + const uint32_t _maxLOD; + const Range _range; + NodeIds _visibles; +}; +} +#endif diff --git a/livre/core/types.h b/livre/core/types.h index e17d84f1..f0996fbc 100644 --- a/livre/core/types.h +++ b/livre/core/types.h @@ -25,8 +25,6 @@ #include #include -#include - #include #include @@ -56,13 +54,6 @@ class Cache; class CacheObject; class CacheStatistics; class Configuration; -class DashConnection; -class DashProcessor; -class DashProcessorInput; -class DashProcessorOutput; -class DashRenderNode; -class DashRenderStatus; -class DashTree; class EventHandler; class EventHandlerFactory; class EventInfo; @@ -73,6 +64,7 @@ class GLSLShaders; class LODNode; class MemoryUnit; class NodeId; +class NodeVisitor; class Parameter; class Processor; class ProcessorInput; @@ -122,12 +114,8 @@ typedef std::array< float, 2 > Range; */ typedef std::shared_ptr< AllocMemoryUnit > AllocMemoryUnitPtr; -typedef std::shared_ptr< DashConnection > DashConnectionPtr; -typedef std::shared_ptr< Processor > ProcessorPtr; -typedef std::shared_ptr< DashProcessor > DashProcessorPtr; -typedef std::shared_ptr< ProcessorInput > ProcessorInputPtr; -typedef std::shared_ptr< ProcessorOutput > ProcessorOutputPtr; typedef std::shared_ptr< GLContext > GLContextPtr; +typedef std::shared_ptr< const GLContext > ConstGLContextPtr; typedef std::shared_ptr< TextureState > TextureStatePtr; typedef std::shared_ptr< const TextureState > ConstTextureStatePtr; typedef std::shared_ptr< DataSource > DataSourcePtr; @@ -141,6 +129,7 @@ typedef std::shared_ptr< const CacheObject > ConstCacheObjectPtr; typedef std::shared_ptr< CacheObject > CacheObjectPtr; typedef std::shared_ptr< const CacheObject > ConstCacheObjectPtr; typedef std::shared_ptr< PortData > PortDataPtr; +typedef std::shared_ptr< Executable > ExecutablePtr; typedef std::unique_ptr< Filter > FilterPtr; @@ -206,7 +195,6 @@ typedef std::unordered_map< CacheId, CacheObjectPtr > CacheMap; typedef std::unordered_map< CacheId, ConstCacheObjectPtr > ConstCacheMap; typedef std::unordered_map< uint32_t, bool > BoolMap; typedef std::unordered_map< uint32_t, EventHandlerPtr > EventHandlerMap; -typedef std::unordered_map< uint32_t, DashConnectionPtr > DashConnectionMap; template < class T > inline std::type_index getType() diff --git a/livre/lib/visitor/DFSTraversal.cpp b/livre/core/visitor/DFSTraversal.cpp similarity index 92% rename from livre/lib/visitor/DFSTraversal.cpp rename to livre/core/visitor/DFSTraversal.cpp index b6a5b454..6e6f959e 100644 --- a/livre/lib/visitor/DFSTraversal.cpp +++ b/livre/core/visitor/DFSTraversal.cpp @@ -19,10 +19,8 @@ #include #include -#include -#include #include -#include +#include #include namespace livre @@ -31,7 +29,9 @@ namespace livre struct DFSTraversal::Impl { public: - bool traverse( const NodeId& nodeId, const uint32_t depth, + + bool traverse( const NodeId& nodeId, + const uint32_t depth, livre::NodeVisitor& visitor ) { if( depth == 0 || _state.getBreakTraversal() ) @@ -70,11 +70,14 @@ struct DFSTraversal::Impl }; DFSTraversal::DFSTraversal( ) - : _impl( new Impl( )) -{} + : _impl( new DFSTraversal::Impl() ) +{ +} DFSTraversal::~DFSTraversal() -{} +{ + +} bool DFSTraversal::traverse( const RootNode& rootNode, const NodeId& node, NodeVisitor& visitor ) diff --git a/livre/lib/visitor/DFSTraversal.h b/livre/core/visitor/DFSTraversal.h similarity index 83% rename from livre/lib/visitor/DFSTraversal.h rename to livre/core/visitor/DFSTraversal.h index 32823659..3e637df3 100644 --- a/livre/lib/visitor/DFSTraversal.h +++ b/livre/core/visitor/DFSTraversal.h @@ -23,13 +23,11 @@ #include #include -#include -#include namespace livre { -/** Depth First Search ( DFS ) traverser for a dash node tree. */ +/** Depth First Search ( DFS ) traverser for a LOD node tree. */ class DFSTraversal { public: @@ -37,7 +35,7 @@ class DFSTraversal LIVRE_API ~DFSTraversal(); /** - * Traverse the dash node tree starting from the given node. + * Traverse the node tree starting from the given node. * @param rootNode The tree root information. * @param node starting node to traverse. * @param visitor Visitor object. @@ -48,19 +46,19 @@ class DFSTraversal NodeVisitor& visitor ); /** - * Traverse the dash node tree starting from the root. + * Traverse the node tree starting from the root. * @param rootNode The tree root information. * @param visitor Visitor object. * @param frame The temporal position of the node tree. */ LIVRE_API void traverse( const RootNode& rootNode, NodeVisitor& visitor, - uint32_t frame ); + const uint32_t frame ); private: struct Impl; - std::unique_ptr< Impl > _impl; + std::unique_ptr _impl; }; } diff --git a/livre/core/visitor/RenderNodeVisitor.cpp b/livre/core/visitor/DataSourceVisitor.cpp similarity index 53% rename from livre/core/visitor/RenderNodeVisitor.cpp rename to livre/core/visitor/DataSourceVisitor.cpp index edadd383..56737d06 100644 --- a/livre/core/visitor/RenderNodeVisitor.cpp +++ b/livre/core/visitor/DataSourceVisitor.cpp @@ -17,52 +17,47 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include -#include +#include +#include +#include namespace livre { -struct RenderNodeVisitor::Impl +class DataSourceVisitor::Impl { public: - explicit Impl( livre::DashTree& dashTree ) - : _dashTree( dashTree ) + explicit Impl( const DataSource& dataSource ) + : _dataSource( dataSource ) {} - dash::NodePtr getDashNode( const NodeId& nodeId ) + LODNode getNode( const NodeId& nodeId ) const { - return _dashTree.getDashNode( nodeId ); + return _dataSource.getNode( nodeId ); } - livre::DashTree& getDashTree() { return _dashTree; } - livre::DashTree& _dashTree; + const DataSource& _dataSource; }; -RenderNodeVisitor::RenderNodeVisitor( DashTree& dashTree ) - : _impl( new Impl( dashTree )) -{ - -} +DataSourceVisitor::DataSourceVisitor( const DataSource& dataSource ) + : _impl( new DataSourceVisitor::Impl( dataSource )) +{} -RenderNodeVisitor::~RenderNodeVisitor() +DataSourceVisitor::~DataSourceVisitor() {} -DashTree& RenderNodeVisitor::getDashTree() +const DataSource& DataSourceVisitor::getDataSource() const { - return _impl->getDashTree(); + return _impl->_dataSource; } -void RenderNodeVisitor::visit( const NodeId& nodeId, +void DataSourceVisitor::visit( const NodeId& nodeId, VisitState& state ) { - dash::NodePtr node = _impl->getDashNode( nodeId ); - if( !node) - return; - - DashRenderNode renderNode( node ); - visit( renderNode, state ); + const LODNode& node = _impl->getNode( nodeId ); + if( node.isValid( )) + visit( node, state ); } } + diff --git a/livre/core/visitor/RenderNodeVisitor.h b/livre/core/visitor/DataSourceVisitor.h similarity index 62% rename from livre/core/visitor/RenderNodeVisitor.h rename to livre/core/visitor/DataSourceVisitor.h index e55d7d2e..46389825 100644 --- a/livre/core/visitor/RenderNodeVisitor.h +++ b/livre/core/visitor/DataSourceVisitor.h @@ -17,43 +17,46 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _RenderNodeVisitor_h_ -#define _RenderNodeVisitor_h_ +#ifndef _DataSourceVisitor_h_ +#define _DataSourceVisitor_h_ #include #include #include +#include namespace livre { /** - * The RenderNodeVisitor class is base class for invoking traversing events on DashRenderNodes. -*/ -class RenderNodeVisitor : public NodeVisitor + * The DataSourceVisitor is for data source traversal. + */ +class DataSourceVisitor : public NodeVisitor { public: - LIVRECORE_API explicit RenderNodeVisitor( DashTree& dashTree ); - LIVRECORE_API ~RenderNodeVisitor(); + LIVRECORE_API DataSourceVisitor( const DataSource& dataSource ); + LIVRECORE_API ~DataSourceVisitor(); /** - * @see NodeVisitor::visit + * @copydoc NodeVisitor::visit */ - virtual void visit( DashRenderNode& node, + virtual void visit( const LODNode& node, VisitState& state ) = 0; /** - * @return Returns the dash tree + * @return Returns the data source */ - LIVRECORE_API DashTree& getDashTree(); + LIVRECORE_API const DataSource& getDataSource() const; private: - LIVRECORE_API void visit( const NodeId& nodeId, VisitState& state ) final; + + LIVRECORE_API void visit( const NodeId& nodeId, + VisitState& state ) final; struct Impl; - std::unique_ptr< Impl > _impl; + std::unique_ptr _impl; }; } -#endif // _RenderNodeVisitor_h_ +#endif // _DataSourceVisitor_h_ diff --git a/livre/eq/Channel.cpp b/livre/eq/Channel.cpp index 2ef20c31..b06551cf 100644 --- a/livre/eq/Channel.cpp +++ b/livre/eq/Channel.cpp @@ -38,19 +38,17 @@ #include #include #include - -#include -#include -#include +#include #include -#include -#include -#include -#include #include #include #include +#include + +#include +#include +#include #ifdef LIVRE_USE_ZEROEQ # include @@ -64,13 +62,63 @@ namespace livre const float nearPlane = 0.1f; const float farPlane = 15.0f; +struct RedrawFilter : public Filter +{ + +public: + + RedrawFilter( Channel* channel ) + : _channel( channel ) + {} + + ~RedrawFilter() {} + void execute( const FutureMap& input, + PromiseMap& ) const final + { + waitForAny( input.getFutures( )); + + const bool isRenderingDone = input.get< bool >( "RenderingDone" )[ 0 ]; + if( !isRenderingDone ) + _channel->getConfig()->sendEvent( REDRAW ); + } + + DataInfos getInputDataInfos() const final + { + return + { + { "CacheObjects", getType< ConstCacheObjects >() }, + { "RenderingDone", getType< bool >() } + }; + } + + Channel* _channel; +}; + + +struct EqRaycastRenderer : public RayCastRenderer +{ + EqRaycastRenderer( Channel::Impl& channel, + const TextureCache& textureCache, + uint32_t samplesPerRay, + uint32_t samplesPerPixel ) + : RayCastRenderer( textureCache, samplesPerRay, samplesPerPixel ) + , _channel( channel ) + {} + + void _onFrameStart( const Frustum& frustum, + const PixelViewport& view, + const NodeIds& renderBricks ) final; + + Channel::Impl& _channel; +}; + + struct Channel::Impl { public: explicit Impl( Channel* channel ) : _channel( channel ) - , _frustum( Matrix4f(), Matrix4f( )) - , _frameInfo( _frustum, INVALID_FRAME ) + , _frameInfo( Frustum( Matrix4f(), Matrix4f()), INVALID_FRAME ) , _progress( "Loading bricks", 0 ) {} @@ -98,21 +146,19 @@ struct Channel::Impl const uint32_t nSamplesPerPixel = getFrameData()->getVRParameters().getSamplesPerPixel(); - const livre::Window* window = - static_cast< livre::Window* >( _channel->getWindow( )); - _renderer.reset( new RayCastRenderer( window->getTextureCache(), - nSamplesPerRay, - nSamplesPerPixel )); + const Window* window = static_cast< const Window* >( _channel->getWindow( )); + _renderer.reset( new EqRaycastRenderer( *this, + window->getTextureCache(), + nSamplesPerRay, + nSamplesPerPixel )); } - const Frustum& setupFrustum() + Frustum setupFrustum() const { const eq::Matrix4f& modelView = computeModelView(); const eq::Frustumf& eqFrustum = _channel->getFrustum(); const eq::Matrix4f& projection = eqFrustum.computePerspectiveMatrix(); - - _frustum = Frustum( modelView, projection ); - return _frustum; + return Frustum( modelView, projection ); } eq::Matrix4f computeModelView() const @@ -134,177 +180,88 @@ struct Channel::Impl glScissor( 0, 0, channelPvp.w, channelPvp.h ); } - void generateRenderBricks( const ConstCacheObjects& renderNodes, - NodeIds& renderBricks ) - { - - renderBricks.reserve( renderNodes.size( )); - for( const ConstCacheObjectPtr& cacheObject: renderNodes ) - renderBricks.emplace_back( cacheObject->getId( )); - - } - - DashRenderNodes requestData() - { - livre::Node* node = static_cast< livre::Node* >( _channel->getNode( )); - livre::Window* window = static_cast< livre::Window* >( _channel->getWindow( )); - livre::Pipe* pipe = static_cast< livre::Pipe* >( window->getPipe( )); - - const VolumeRendererParameters& vrParams = - pipe->getFrameData()->getVRParameters(); - const uint32_t minLOD = vrParams.getMinLOD(); - const uint32_t maxLOD = vrParams.getMaxLOD(); - const float screenSpaceError = vrParams.getSSE(); - - DashTree& dashTree = node->getDashTree(); - - const VolumeInformation& volInfo = dashTree.getDataSource().getVolumeInfo(); - - _drawRange = _channel->getRange(); - SelectVisibles visitor( dashTree, - _frustum, - _channel->getPixelViewport().h, - screenSpaceError, - minLOD, maxLOD, - Range{{ _drawRange.start, _drawRange.end }}); - - livre::DFSTraversal traverser; - traverser.traverse( volInfo.rootNode, visitor, - dashTree.getRenderStatus().getFrameID( )); - window->commit(); - return visitor.getVisibles(); - } - void updateRegions( const NodeIds& renderBricks, const Frustum& frustum ) - { - const Matrix4f& mvpMatrix = frustum.getMVPMatrix(); + { + const Matrix4f& mvpMatrix = frustum.getMVPMatrix(); - livre::Node* node = - static_cast< livre::Node* >( _channel->getNode( )); - const DataSource& dataSource = node->getTextureDataCache().getDataSource(); + livre::Node* node = + static_cast< livre::Node* >( _channel->getNode( )); + const DataSource& dataSource = node->getTextureDataCache().getDataSource(); - for( const NodeId& nodeId : renderBricks ) + for( const NodeId& nodeId : renderBricks ) + { + const LODNode& lodNode = dataSource.getNode( nodeId ); + const Boxf& worldBox =lodNode.getWorldBox(); + const Vector3f& min = worldBox.getMin(); + const Vector3f& max = worldBox.getMax(); + const Vector3f corners[8] = + { + Vector3f( min[0], min[1], min[2] ), + Vector3f( max[0], min[1], min[2] ), + Vector3f( min[0], max[1], min[2] ), + Vector3f( max[0], max[1], min[2] ), + Vector3f( min[0], min[1], max[2] ), + Vector3f( max[0], min[1], max[2] ), + Vector3f( min[0], max[1], max[2] ), + Vector3f( max[0], max[1], max[2] ) + }; + + Vector4f region( std::numeric_limits< float >::max(), + std::numeric_limits< float >::max(), + -std::numeric_limits< float >::max(), + -std::numeric_limits< float >::max( )); + + for( size_t i = 0; i < 8; ++i ) { - const LODNode& lodNode = dataSource.getNode( nodeId ); - const Boxf& worldBox =lodNode.getWorldBox(); - const Vector3f& min = worldBox.getMin(); - const Vector3f& max = worldBox.getMax(); - const Vector3f corners[8] = - { - Vector3f( min[0], min[1], min[2] ), - Vector3f( max[0], min[1], min[2] ), - Vector3f( min[0], max[1], min[2] ), - Vector3f( max[0], max[1], min[2] ), - Vector3f( min[0], min[1], max[2] ), - Vector3f( max[0], min[1], max[2] ), - Vector3f( min[0], max[1], max[2] ), - Vector3f( max[0], max[1], max[2] ) - }; - - Vector4f region( std::numeric_limits< float >::max(), - std::numeric_limits< float >::max(), - -std::numeric_limits< float >::max(), - -std::numeric_limits< float >::max( )); - - for( const auto& corner: corners ) - { - const Vector3f& mvpCorner = mvpMatrix * corner; - region[0] = std::min( mvpCorner[0], region[0] ); - region[1] = std::min( mvpCorner[1], region[1] ); - region[2] = std::max( mvpCorner[0], region[2] ); - region[3] = std::max( mvpCorner[1], region[3] ); - } - - // transform ROI from [ -1 -1 1 1 ] to normalized viewport - const Vector4f normalized( region[0] * .5f + .5f, - region[1] * .5f + .5f, - ( region[2] - region[0] ) * .5f, - ( region[3] - region[1] ) * .5f ); - - _channel->declareRegion( eq::Viewport( normalized )); + const Vector3f corner = mvpMatrix * corners[i]; + region[0] = std::min( corner[0], region[0] ); + region[1] = std::min( corner[1], region[1] ); + region[2] = std::max( corner[0], region[2] ); + region[3] = std::max( corner[1], region[3] ); } - #ifndef NDEBUG - _channel->outlineViewport(); - #endif - } - void freeTexture( const NodeId& nodeId ) - { - livre::Node* node = static_cast< livre::Node* >( _channel->getNode( )); - DashTree& dashTree = node->getDashTree(); + // transform ROI from [ -1 -1 1 1 ] to normalized viewport + const Vector4f normalized( region[0] * .5f + .5f, + region[1] * .5f + .5f, + ( region[2] - region[0] ) * .5f, + ( region[3] - region[1] ) * .5f ); - dash::NodePtr dashNode = dashTree.getDashNode( nodeId ); - if( !dashNode ) - return; - - DashRenderNode renderNode( dashNode ); - if( renderNode.getLODNode().getRefLevel() != 0 ) - renderNode.setTextureObject( CacheObjectPtr( )); - } - - void freeTextures() - { - for( const auto& cacheObject: _frameInfo.renderNodes ) - { - const NodeId nodeId(cacheObject->getId( )); - freeTexture( nodeId ); + _channel->declareRegion( eq::Viewport( normalized )); } - - for( const NodeId& nodeId: _frameInfo.allNodes ) - freeTexture( nodeId ); +#ifndef NDEBUG + _channel->outlineViewport(); +#endif } void frameDraw( const eq::uint128_t& ) { - livre::Node* node = static_cast< livre::Node* >( _channel->getNode( )); - const DashRenderStatus& renderStatus = node->getDashTree().getRenderStatus(); - const uint32_t frame = renderStatus.getFrameID(); + + const Pipe* pipe = static_cast< Pipe* >( _channel->getPipe( )); + const uint32_t frame = + pipe->getFrameData()->getFrameSettings().getFrameNumber(); + if( frame >= INVALID_FRAME ) return; applyCamera(); - setupFrustum(); - _frameInfo = FrameInfo( _frustum, frame ); - - const DashRenderNodes& visibles = requestData(); - - livre::Window* window = static_cast< livre::Window* >( _channel->getWindow( )); - const livre::Pipe* pipe = static_cast< const livre::Pipe* >( _channel->getPipe( )); - - const bool isSynchronous = - pipe->getFrameData()->getVRParameters().getSynchronousMode(); - - // #75: only wait for data in synchronous mode - const bool dashTreeUpdated = window->apply( isSynchronous ); - - if( dashTreeUpdated ) - { - const Frustum& receivedFrustum = renderStatus.getFrustum(); - - // If there are multiple channels, this may cause the ping-pong - // because every channel will try to update the same DashTree in - // node with their own frustum. - if( !isSynchronous && receivedFrustum != _frustum ) - _channel->getConfig()->sendEvent( REDRAW ); - } - - const AvailableSetGenerator generateSet( window->getTextureCache( )); - - for( const auto& visible : visibles ) - _frameInfo.allNodes.push_back(visible.getLODNode().getNodeId()); - generateSet.generateRenderingSet( _frameInfo ); - - _renderer->update( *pipe->getFrameData( )); - NodeIds renderBricks; - generateRenderBricks( _frameInfo.renderNodes, renderBricks ); + const Frustum& frustum = setupFrustum(); + _frameInfo = FrameInfo( frustum, frame ); const eq::PixelViewport& vp = _channel->getPixelViewport(); - _renderer->render( _frustum, - PixelViewport( vp.x, vp.y, vp.w, vp.h ), - renderBricks ); - updateRegions( renderBricks, _frustum ); - freeTextures(); + _drawRange = _channel->getRange(); + + const livre::Window* window = static_cast< const livre::Window* >( _channel->getWindow( )); + const RenderPipeline& renderPipeline = window->getRenderPipeline(); + + renderPipeline.render( pipe->getFrameData()->getVRParameters(), + _frameInfo, + { _drawRange.start, _drawRange.end }, + PixelViewport( vp.x, vp.y, vp.w, vp.h ), + PipeFilterT< RedrawFilter >( "RedrawFilter", _channel ), + *_renderer, + _frameInfo.nAvailable, + _frameInfo.nNotAvailable ); } void applyCamera() @@ -322,7 +279,6 @@ struct Channel::Impl void configExit() { - _frameInfo.renderNodes.clear(); _frame.getFrameData()->flush(); } @@ -351,11 +307,11 @@ struct Channel::Impl } #ifdef LIVRE_USE_ZEROEQ - const size_t all = _frameInfo.allNodes.size(); + const size_t all = _frameInfo.nAvailable + _frameInfo.nNotAvailable; if( all > 0 ) { _progress.restart( all ); - _progress += all - _frameInfo.notAvailableRenderNodes.size(); + _progress += _frameInfo.nAvailable; _publisher.publish( _progress ); } #endif @@ -376,8 +332,8 @@ struct Channel::Impl glMatrixMode( GL_MODELVIEW ); livre::Node* node = static_cast< livre::Node* >( _channel->getNode( )); - const size_t all = _frameInfo.allNodes.size(); - const size_t missing = _frameInfo.notAvailableRenderNodes.size(); + const size_t all = _frameInfo.nAvailable + _frameInfo.nNotAvailable; + const size_t missing = _frameInfo.nNotAvailable; const float done = all > 0 ? float( all - missing ) / float( all ) : 0; Window* window = static_cast< Window* >( _channel->getWindow( )); @@ -386,8 +342,8 @@ struct Channel::Impl << int( 100.f * done + .5f ) << "% loaded" << std::endl << window->getTextureCache().getStatistics(); - const DataSource& dataSource = static_cast< livre::Node* >( - _channel->getNode( ))->getDashTree().getDataSource(); + const DataSource& dataSource = + node->getTextureDataCache().getDataSource(); const VolumeInformation& info = dataSource.getVolumeInfo(); Vector3f voxelSize = info.boundingBox.getSize() / info.voxels; std::string unit = "m"; @@ -429,13 +385,6 @@ struct Channel::Impl font->draw( text ); } - void frameFinish() - { - livre::Node* node = static_cast< livre::Node* >( _channel->getNode( )); - DashRenderStatus& renderStatus = node->getDashTree().getRenderStatus(); - renderStatus.setFrustum( _frustum ); - } - void frameReadback( const eq::Frames& frames ) const { for( eq::Frame* frame : frames ) // Drop depth buffer from output frames @@ -586,10 +535,9 @@ struct Channel::Impl } } - livre::Channel* const _channel; + livre::Channel* _channel; eq::Range _drawRange; eq::Frame _frame; - Frustum _frustum; FrameGrabber _frameGrabber; FrameInfo _frameInfo; std::unique_ptr< RayCastRenderer > _renderer; @@ -599,6 +547,14 @@ struct Channel::Impl #endif }; +void EqRaycastRenderer::_onFrameStart( const Frustum& frustum, + const PixelViewport& view, + const NodeIds& renderBricks ) +{ + _channel.updateRegions( renderBricks, frustum ); + RayCastRenderer::_onFrameStart( frustum, view, renderBricks ); +} + Channel::Channel( eq::Window* parent ) : eq::Channel( parent ) , _impl( new Impl( this )) @@ -637,12 +593,6 @@ void Channel::frameDraw( const lunchbox::uint128_t& frameId ) _impl->frameDraw( frameId ); } -void Channel::frameFinish( const eq::uint128_t& frameID, const uint32_t frameNumber ) -{ - _impl->frameFinish(); - eq::Channel::frameFinish( frameID, frameNumber ); -} - void Channel::frameViewStart( const uint128_t& frameId ) { eq::Channel::frameViewStart( frameId ); @@ -676,11 +626,9 @@ void Channel::frameReadback( const eq::uint128_t& frameId, std::string Channel::getDumpImageFileName() const { - const livre::Node* node = static_cast< const livre::Node* >( getNode( )); - const DashTree& dashTree = node->getDashTree(); std::stringstream filename; filename << std::setw( 5 ) << std::setfill('0') - << dashTree.getRenderStatus().getFrameID() << ".png"; + << _impl->_frameInfo.frameId << ".png"; return filename.str(); } diff --git a/livre/eq/Channel.h b/livre/eq/Channel.h index 71ba15b8..8af32ec9 100644 --- a/livre/eq/Channel.h +++ b/livre/eq/Channel.h @@ -45,7 +45,6 @@ class Channel : public eq::Channel void frameStart( const eq::uint128_t&, const uint32_t ) final; void frameDraw( const eq::uint128_t& frameId ) final; - void frameFinish( const eq::uint128_t&, const uint32_t ) final; void frameViewStart( const eq::uint128_t& frameId ) final; void frameViewFinish( const eq::uint128_t &frameID ) final; void frameAssemble( const eq::uint128_t&, const eq::Frames& ) final; diff --git a/livre/eq/Node.cpp b/livre/eq/Node.cpp index b6b286e6..f0559285 100644 --- a/livre/eq/Node.cpp +++ b/livre/eq/Node.cpp @@ -32,10 +32,6 @@ #include #include #include -#include -#include -#include -#include #include #include @@ -71,9 +67,7 @@ struct Node::Impl const VolumeSettings& volumeSettings = _config->getFrameData().getVolumeSettings(); const lunchbox::URI& uri = lunchbox::URI( volumeSettings.getURI( )); - dash::Context::getMain(); // Create the main context _dataSource.reset( new livre::DataSource( uri )); - _dashTree.reset( new livre::DashTree( *_dataSource )); } catch( const std::runtime_error& err ) { @@ -114,7 +108,6 @@ struct Node::Impl livre::Config* const _config; std::unique_ptr< DataSource > _dataSource; std::unique_ptr< TextureDataCache > _textureDataCache; - std::unique_ptr< livre::DashTree > _dashTree; }; Node::Node( eq::Config* parent ) @@ -165,16 +158,6 @@ TextureDataCache& Node::getTextureDataCache() return *_impl->_textureDataCache; } -DashTree& Node::getDashTree() -{ - return *_impl->_dashTree; -} - -const DashTree& Node::getDashTree() const -{ - return *_impl->_dashTree; -} - void Node::frameStart( const eq::uint128_t &frameId, const uint32_t frameNumber) { diff --git a/livre/eq/Node.h b/livre/eq/Node.h index b1da22b3..6e3aa2db 100644 --- a/livre/eq/Node.h +++ b/livre/eq/Node.h @@ -23,7 +23,6 @@ #define _Node_h_ #include -#include #include #include @@ -33,7 +32,7 @@ namespace livre * The Node class is a standard EQ abstraction for a process. It manages the data loaders * and keeps the data cache. */ -class Node : public eq::Node, public DashContextTrait +class Node : public eq::Node { public: /** @@ -47,16 +46,6 @@ class Node : public eq::Node, public DashContextTrait */ TextureDataCache& getTextureDataCache(); - /** - * @return The dash tree. - */ - DashTree& getDashTree(); - - /** - * @return The dash tree. - */ - const DashTree& getDashTree() const; - private: bool configInit( const eq::uint128_t& initId ) final; void frameStart( const eq::uint128_t& frameId, diff --git a/livre/eq/Window.cpp b/livre/eq/Window.cpp index 897214da..73660c9f 100644 --- a/livre/eq/Window.cpp +++ b/livre/eq/Window.cpp @@ -31,16 +31,9 @@ #include #include -#include -#include -#include -#include -#include - #include - -#include -#include +#include +#include #include @@ -49,38 +42,11 @@ const uint32_t maxQueueSize = 65536; namespace livre { -class EqTextureUploadProcessor : public TextureUploadProcessor -{ -public: - EqTextureUploadProcessor( Config& config, - DashTree& dashTree, - GLContextPtr shareContext, - TextureDataCache& dataCache, - const VolumeRendererParameters& parameters ) - : TextureUploadProcessor( dashTree, shareContext, - dataCache, parameters ) - , _config( config ) - {} - - void onPostCommit_( uint32_t connection LB_UNUSED, CommitState state ) final - { - if( state != CommitState::CS_NOCHANGE ) - glFinish(); - - if( needRedraw( )) - _config.sendEvent( REDRAW ); - } - -private: - Config& _config; -}; - struct Window::Impl { public: explicit Impl( Window* window ) : _window( window ) - , _dashProcessor( new DashProcessor( )) {} void configInitGL() @@ -88,147 +54,49 @@ struct Window::Impl _glContext.reset( new EqContext( _window )); } - void configInit() - { - initializePipelineProcessors(); - initializePipelineConnections(); - startUploadProcessors(); - } - - void configExitGL() - { - // if we are the last window of a share group, release the processors - LBASSERT( _dataUploader.use_count() == _textureUploader.use_count( )); - if( !_dataUploader.unique() || !_dashProcessor->getDashContext( )) - return; - - stopUploadProcessors(); - } - - void configExit() - { - // If it did not arrive at the frameStart, the current context should - // be set correctly. - _dashProcessor->getDashContext()->setCurrent(); - livre::Node* node = static_cast< livre::Node* >( _window->getNode( )); - node->getDashTree().getRenderStatus().setThreadOp( TO_EXIT ); - } - - void frameStart() - { - _dashProcessor->getDashContext()->setCurrent(); - livre::Node* node = static_cast< livre::Node* >( _window->getNode( )); - DashRenderStatus& renderStatus = node->getDashTree().getRenderStatus(); - - const Pipe* pipe = static_cast< Pipe* >( _window->getPipe( )); - const uint32_t frame = - pipe->getFrameData()->getFrameSettings().getFrameNumber(); - renderStatus.setFrameID( frame ); - } - - void startUploadProcessors() - { -#ifdef _MSC_VER - // https://www.opengl.org/discussion_boards/showthread.php/152648-wglShareLists-failing - LBCHECK( wglMakeCurrent( 0,0 )); -#endif - if( !_textureUploader->isRunning( )) - _textureUploader->start(); - - if( !_dataUploader->isRunning( )) - _dataUploader->start(); -#ifdef _MSC_VER - _window->makeCurrent( false ); -#endif - } - - void stopUploadProcessors() - { - commit(); - _textureUploader->join(); - _dataUploader->join(); - } - - void commit() + bool configExitGL() { - _dashProcessor->getProcessorOutput_()->commit( CONNECTION_ID ); + _glContext->doneCurrent(); + _glContext.reset(); + return true; } - bool apply( bool wait ) + void configInit() { - ProcessorInputPtr input = _dashProcessor->getProcessorInput_(); + shareGLContexts(); - if( wait || input->dataWaitingOnInput( CONNECTION_ID )) - return input->applyAll( CONNECTION_ID ); + Node* node = static_cast< Node* >( _window->getNode( )); + Pipe* pipe = static_cast< Pipe* >( _window->getPipe( )); + const size_t maxGpuMemory = + pipe->getFrameData()->getVRParameters().getMaxGPUCacheMemoryMB(); + _textureCache.reset( new TextureCache( node->getTextureDataCache(), + maxGpuMemory * LB_1MB, GL_LUMINANCE8 )); + + const size_t computeThreads = 2; + const size_t uploadThreads = 4; + _renderPipeline.reset( new RenderPipeline( *_textureCache, + computeThreads, + uploadThreads, + _glContext )); - return false; } - void initializePipelineProcessors() + void shareGLContexts() { const Window* sharedWindow = static_cast< const Window* >( _window->getSharedContextWindow( )); - // share upload processors for windows which also share the GL context if( sharedWindow && sharedWindow != _window ) { _glContext = sharedWindow->_impl->_glContext; - _dashProcessor = sharedWindow->_impl->_dashProcessor; - _textureUploader = sharedWindow->_impl->_textureUploader; - _dataUploader = sharedWindow->_impl->_dataUploader; return; } - - // First one in group: setup - Node* node = static_cast< Node* >( _window->getNode( )); - DashTree& dashTree = node->getDashTree(); - _dashProcessor->setDashContext( dashTree.createContext( )); - _dataUploader.reset( new DataUploadProcessor( dashTree, _glContext, - node->getTextureDataCache( ))); - - Config* config = static_cast< Config* >( _window->getConfig( )); - Pipe* pipe = static_cast< Pipe* >( _window->getPipe( )); - - _textureUploader.reset( - new EqTextureUploadProcessor( *config, dashTree, _glContext, - node->getTextureDataCache(), - pipe->getFrameData()->getVRParameters( ))); - } - - void initializePipelineConnections() - { - // Connects data uploader to texture uploader - DashConnectionPtr dataOutputConnectionPtr( new DashConnection( maxQueueSize ) ); - _dataUploader->getProcessorOutput_< DashProcessorOutput >( ) - ->addConnection( CONNECTION_ID, dataOutputConnectionPtr ); - - _textureUploader->getProcessorInput_< DashProcessorInput >( ) - ->addConnection( CONNECTION_ID, dataOutputConnectionPtr ); - - // Connects texture uploader to pipe - DashConnectionPtr texOutputConnectionPtr( new DashConnection( maxQueueSize ) ); - _textureUploader->getProcessorOutput_< DashProcessorOutput >() - ->addConnection( CONNECTION_ID, texOutputConnectionPtr ); - _dashProcessor->getProcessorInput_< DashProcessorInput >() - ->addConnection( CONNECTION_ID, texOutputConnectionPtr ); - // Connects pipe to data uploader - DashConnectionPtr pipeOutputConnectionPtr( new DashConnection( maxQueueSize ) ); - _dataUploader->getProcessorInput_< DashProcessorInput >() - ->addConnection( CONNECTION_ID, pipeOutputConnectionPtr ); - _dashProcessor->getProcessorOutput_< DashProcessorOutput >() - ->addConnection( CONNECTION_ID, pipeOutputConnectionPtr ); } Window* const _window; - - typedef std::shared_ptr< TextureUploadProcessor > TextureUploadProcessorPtr; - TextureUploadProcessorPtr _textureUploader; - - typedef std::shared_ptr< DataUploadProcessor > DataUploadProcessorPtr; - DataUploadProcessorPtr _dataUploader; - - DashProcessorPtr _dashProcessor; GLContextPtr _glContext; + std::unique_ptr< TextureCache > _textureCache; + std::unique_ptr< RenderPipeline > _renderPipeline; }; Window::Window( eq::Pipe *parent ) @@ -252,12 +120,6 @@ bool Window::configInit( const eq::uint128_t& initId ) return true; } -bool Window::configExit() -{ - _impl->configExit(); - return eq::Window::configExit(); -} - bool Window::configInitGL( const eq::uint128_t& initId ) { if( !GLEW_ARB_shader_objects ) @@ -286,30 +148,22 @@ bool Window::configInitGL( const eq::uint128_t& initId ) bool Window::configExitGL() { - _impl->configExitGL(); - return eq::Window::configExitGL(); -} - -void Window::frameStart( const eq::uint128_t& frameID, - const uint32_t frameNumber ) -{ - _impl->frameStart(); - eq::Window::frameStart( frameID, frameNumber ); + return _impl->configExitGL(); } -void Window::commit() +TextureCache& Window::getTextureCache() { - _impl->commit(); + return *_impl->_textureCache; } -bool Window::apply( bool wait ) +const RenderPipeline& Window::getRenderPipeline() const { - return _impl->apply( wait ); + return *_impl->_renderPipeline; } const TextureCache& Window::getTextureCache() const { - return _impl->_textureUploader->getTextureCache(); + return *_impl->_textureCache; } } diff --git a/livre/eq/Window.h b/livre/eq/Window.h index 05155c86..d56bb685 100644 --- a/livre/eq/Window.h +++ b/livre/eq/Window.h @@ -43,24 +43,20 @@ class Window : public eq::Window /** Commits changes. */ void commit(); - /** - * Applies all the changes to the context. - * @param wait if true blocks until changes are applied to the current context - * @return true if any change is applied to the current context - */ - bool apply( bool wait); + /** @return The texture data cache. */ + TextureCache& getTextureCache(); /** @return The texture data cache. */ const TextureCache& getTextureCache() const; + /** @return The rendering pipeline. */ + const RenderPipeline& getRenderPipeline() const; + private: bool configInit( const eq::uint128_t& initId ) final; - bool configExit() final; bool configInitGL( const eq::uint128_t& initId ) final; bool configExitGL() final; - void frameStart( const eq::uint128_t& frameID, - const uint32_t frameNumber ) final; struct Impl; std::unique_ptr< Impl > _impl; diff --git a/livre/eq/render/EqContext.cpp b/livre/eq/render/EqContext.cpp index db769667..ba039dea 100644 --- a/livre/eq/render/EqContext.cpp +++ b/livre/eq/render/EqContext.cpp @@ -26,6 +26,11 @@ namespace livre { +namespace +{ +boost::mutex glContextMutex; +} + EqContext::EqContext( Window* const window ) : GLContext( window->glewGetContext( )) , _window( window ) @@ -40,6 +45,7 @@ EqContext::~EqContext() void EqContext::share( const GLContext& src ) { LBASSERT( _window ); + ScopedLock lock( glContextMutex ); // Context is already created so return. if( _systemWindow ) @@ -64,7 +70,7 @@ void EqContext::share( const GLContext& src ) const eq::Pipe* pipe = _window->getPipe(); _systemWindow = pipe->getWindowSystem().createWindow( _window, settings ); - if( !_systemWindow->configInit( ) ) + if( !_systemWindow->configInit( )) { delete _systemWindow; _systemWindow = 0; @@ -86,6 +92,12 @@ void EqContext::makeCurrent() } void EqContext::doneCurrent() -{} +{ + if( _systemWindow ) + { + GLContext::doneCurrent(); + _systemWindow->doneCurrent(); + } +} } diff --git a/livre/lib/CMakeLists.txt b/livre/lib/CMakeLists.txt index 41b18b2b..d6c24e4d 100644 --- a/livre/lib/CMakeLists.txt +++ b/livre/lib/CMakeLists.txt @@ -19,17 +19,14 @@ set(LIVRELIB_PUBLIC_HEADERS cache/TextureDataCache.h cache/TextureObject.h cache/TextureDataObject.h - data/MemoryDataSource.h configuration/ApplicationParameters.h configuration/VolumeRendererParameters.h - render/AvailableSetGenerator.h - uploaders/DataUploadProcessor.h - uploaders/TextureUploadProcessor.h - visitor/CollectionTraversal.h - visitor/DFSTraversal.h) - -set(LIVRELIB_HEADERS - render/SelectVisibles.h) + pipeline/DataUploadFilter.h + pipeline/RenderFilter.h + pipeline/RenderingSetGeneratorFilter.h + pipeline/RenderPipeline.h + pipeline/VisibleSetGeneratorFilter.h + data/MemoryDataSource.h) set(LIVRELIB_SOURCES ${ZEROBUF_GENERATED_SOURCES} @@ -38,14 +35,14 @@ set(LIVRELIB_SOURCES cache/TextureDataCache.cpp cache/TextureObject.cpp cache/TextureDataObject.cpp - data/MemoryDataSource.cpp configuration/ApplicationParameters.cpp configuration/VolumeRendererParameters.cpp - render/AvailableSetGenerator.cpp - uploaders/DataUploadProcessor.cpp - uploaders/TextureUploadProcessor.cpp - visitor/CollectionTraversal.cpp - visitor/DFSTraversal.cpp) + pipeline/DataUploadFilter.cpp + pipeline/RenderFilter.cpp + pipeline/RenderingSetGeneratorFilter.cpp + pipeline/RenderPipeline.cpp + pipeline/VisibleSetGeneratorFilter.cpp + data/MemoryDataSource.cpp) set(LIVRELIB_LINK_LIBRARIES PUBLIC LivreCore PRIVATE Equalizer ${VTUNE_LIBRARIES}) diff --git a/livre/lib/cache/TextureDataObject.cpp b/livre/lib/cache/TextureDataObject.cpp index 63878456..0769ff0b 100644 --- a/livre/lib/cache/TextureDataObject.cpp +++ b/livre/lib/cache/TextureDataObject.cpp @@ -67,7 +67,7 @@ struct TextureDataObject::Impl size_t getSize() const { - return _data->getAllocSize(); + return getDataSize(); } const void* getDataPtr() const diff --git a/livre/lib/data/MemoryDataSource.cpp b/livre/lib/data/MemoryDataSource.cpp index 5fdb9016..b6c6bc83 100644 --- a/livre/lib/data/MemoryDataSource.cpp +++ b/livre/lib/data/MemoryDataSource.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/livre/lib/pipeline/DataUploadFilter.cpp b/livre/lib/pipeline/DataUploadFilter.cpp new file mode 100644 index 00000000..1a83e9e4 --- /dev/null +++ b/livre/lib/pipeline/DataUploadFilter.cpp @@ -0,0 +1,162 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include + +namespace livre +{ + +struct DataUploadFilter::Impl +{ +public: + + Impl( const size_t id, + const size_t nUploaders, + TextureCache& textureCache ) + : _textureCache( textureCache ) + , _id( id ) + , _nUploaders( nUploaders ) + {} + + ConstCacheObjects load( const NodeIds& visibles ) const + { + ConstCacheObjects cacheObjects; + cacheObjects.reserve( visibles.size( )); + for( const NodeId& nodeId: visibles ) + { + ConstCacheObjectPtr texture = _textureCache.get( nodeId.getId( )); + if( !texture ) + { + CacheObjectPtr data = _textureCache.getDataCache().load( nodeId.getId( )); + cacheObjects.push_back( _textureCache.load( nodeId.getId( ))); + data.reset(); + } + else + cacheObjects.push_back( texture ); + } + + return cacheObjects; + } + + ConstCacheObjects get( const NodeIds& visibles ) const + { + ConstCacheObjects cacheObjects; + cacheObjects.reserve( visibles.size( )); + for( const NodeId& nodeId: visibles ) + { + ConstCacheObjectPtr texture = _textureCache.get( nodeId.getId( )); + cacheObjects.push_back( texture ); + } + + return cacheObjects; + } + + void execute( const FutureMap& input, PromiseMap& output ) const + { + const UniqueFutureMap uniqueInputs( input.getFutures()); + const auto& vrParams = + uniqueInputs.get< VolumeRendererParameters >( "Params" ); + + const auto& visibles = + uniqueInputs.get< NodeIds >( "VisibleNodes" ); + + const bool isAsync = !vrParams.getSynchronousMode(); + const size_t perThreadSize = std::max( (size_t)1, visibles.size() / _nUploaders ); + + NodeIds partialVisibles; + + if( _id * perThreadSize < visibles.size( )) + { + const NodeId* begin = visibles.data() + perThreadSize * _id; + if( _id == _nUploaders - 1 ) // last item + partialVisibles = NodeIds( begin, + begin + (visibles.size() - ( perThreadSize * _id ))); + else + partialVisibles = NodeIds( begin, + begin + perThreadSize ); + } + + if( isAsync ) + { + output.set( "CacheObjects", get( partialVisibles)); // Already loaded ones + load( partialVisibles ); // load + } + else + output.set( "CacheObjects", load( partialVisibles )); // load all + } + + DataInfos getInputDataInfos() const + { + return + { + { "Params" ,getType< VolumeRendererParameters >( )}, + { "VisibleNodes" ,getType< NodeIds >() }, + }; + } + + DataInfos getOutputDataInfos() const + { + return + { + { "CacheObjects" ,getType< ConstCacheObjects >() }, + }; + } + + TextureCache& _textureCache; + const size_t _id; + const size_t _nUploaders; +}; + +DataUploadFilter::DataUploadFilter( const size_t id, + const size_t nUploaders, + TextureCache& textureCache) + : _impl( new DataUploadFilter::Impl( id, + nUploaders, + textureCache )) +{ +} + +DataUploadFilter::~DataUploadFilter() +{ + +} + +void DataUploadFilter::execute( const FutureMap& input, + PromiseMap& output ) const +{ + _impl->execute( input, output ); +} + +DataInfos DataUploadFilter::getInputDataInfos() const +{ + return _impl->getInputDataInfos(); +} + +DataInfos DataUploadFilter::getOutputDataInfos() const +{ + return _impl->getOutputDataInfos(); +} + + + +} diff --git a/livre/lib/pipeline/DataUploadFilter.h b/livre/lib/pipeline/DataUploadFilter.h new file mode 100644 index 00000000..4dd0ebe6 --- /dev/null +++ b/livre/lib/pipeline/DataUploadFilter.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2011-2014, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _DataUploadFilter_h_ +#define _DataUploadFilter_h_ + +#include +#include + +namespace livre +{ + + +/** + * DataUploadFilter class implements the parallel data loading for raw volume data and + * textures. A group of uploaders is executed in rendering pipeline and each uploader + * has an id in the group. + */ +class DataUploadFilter : public Filter +{ +public: + + /** + * Constructor + * @param id of the data uploader ( in a group of other uploaders ) + * @param nbUploaders total number of uploders + * @param textureCache texture cache + */ + DataUploadFilter( const size_t id, + const size_t nbUploaders, + TextureCache& textureCache ); + ~DataUploadFilter(); + + /** + * @copydoc Filter::execute + */ + void execute( const FutureMap& input, PromiseMap& output ) const final; + + /** + * @copydoc Filter::getInputDataInfos + */ + DataInfos getInputDataInfos() const final; + + /** + * @copydoc Filter::getOutputDataInfos + */ + DataInfos getOutputDataInfos() const final; + +private: + + struct Impl; + std::unique_ptr _impl; +}; +} + +#endif diff --git a/livre/lib/pipeline/RenderFilter.cpp b/livre/lib/pipeline/RenderFilter.cpp new file mode 100644 index 00000000..2bedc903 --- /dev/null +++ b/livre/lib/pipeline/RenderFilter.cpp @@ -0,0 +1,96 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include +#include +#include + +namespace livre +{ + +struct RenderFilter::Impl +{ + Impl( const DataSource& dataSource, + Renderer& renderer ) + : _dataSource( dataSource ) + , _renderer( renderer ) + {} + + void execute( const FutureMap& input, + PromiseMap&) const + { + RenderBricks renderBricks; + for( const auto& cacheObjects: input.getFutures( "CacheObjects" )) + for( const auto& cacheObject: cacheObjects.get< ConstCacheObjects >( )) + { + const ConstTextureObjectPtr& texture = + std::static_pointer_cast< const TextureObject >( + cacheObject ); + + renderBricks.emplace_back( + _dataSource.getNode( NodeId( texture->getId( ))), + texture->getTextureState( )); + } + + const auto& frustums = input.get< Frustum >( "Frustum" ); + const auto& viewports = input.get< PixelViewport >( "Viewport" ); + _renderer.render( frustums[ 0 ], viewports[ 0 ], renderBricks ); + } + + DataInfos getInputDataInfos() const + { + return + { + { "CacheObjects" ,getType< ConstCacheObjects >() }, + { "Frustum" ,getType< Frustum >() }, + { "Viewport" ,getType< PixelViewport >() } + }; + } + + const DataSource& _dataSource; + Renderer& _renderer; + +}; + +RenderFilter::RenderFilter( const DataSource& dataSource, + Renderer& renderer ) + : _impl( new RenderFilter::Impl( dataSource, renderer )) +{ +} + +RenderFilter::~RenderFilter() +{ +} + +void RenderFilter::execute( const FutureMap& input, + PromiseMap& output ) const +{ + _impl->execute( input, output ); +} + +DataInfos RenderFilter::getInputDataInfos() const +{ + return _impl->getInputDataInfos(); +} + +} diff --git a/livre/lib/render/AvailableSetGenerator.h b/livre/lib/pipeline/RenderFilter.h similarity index 55% rename from livre/lib/render/AvailableSetGenerator.h rename to livre/lib/pipeline/RenderFilter.h index 3aa57a8a..acb4deae 100644 --- a/livre/lib/render/AvailableSetGenerator.h +++ b/livre/lib/pipeline/RenderFilter.h @@ -1,5 +1,5 @@ /* Copyright (c) 2011-2015, EPFL/Blue Brain Project - * Ahmet Bilgili + * Ahmet Bilgili * * This file is part of Livre * @@ -17,40 +17,50 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _AvailableSetGenerator_h_ -#define _AvailableSetGenerator_h_ +#ifndef _RenderFilter_h_ +#define _RenderFilter_h_ -#include #include +#include + namespace livre { /** - * The AvailableSetGenerator class generates a rendering set according to the availability - * of the textures. + * RenderFilter implements the rendering of loaded textures given the renderer. */ -class AvailableSetGenerator +class RenderFilter : public Filter { + public: + /** - * @param textureCache is the cache for textures. + * Constructor + * @param dataSource the data source + * @param renderer the renderer ( RayCaster, etc ) */ - LIVRE_API explicit AvailableSetGenerator( const TextureCache& textureCache ); - LIVRE_API ~AvailableSetGenerator(); + RenderFilter( const DataSource& dataSource, + Renderer& renderer ); + ~RenderFilter(); /** - * Generates the rendering set according to the given frustum. - * @param frameInfo Keeps the frame information + * @copydoc Filter::execute */ - LIVRE_API void generateRenderingSet( FrameInfo& frameInfo ) const; + void execute( const FutureMap& input, PromiseMap& output ) const final; + + /** + * @copydoc Filter::getInputDataInfos + */ + DataInfos getInputDataInfos() const final; private: struct Impl; - std::unique_ptr< Impl > _impl; + std::unique_ptr _impl; }; - } -#endif // _AvailableSetGenerator_h_ + +#endif + diff --git a/livre/lib/pipeline/RenderPipeline.cpp b/livre/lib/pipeline/RenderPipeline.cpp new file mode 100644 index 00000000..b6896bfe --- /dev/null +++ b/livre/lib/pipeline/RenderPipeline.cpp @@ -0,0 +1,212 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace livre +{ + +struct RenderPipeline::Impl +{ + Impl( TextureCache& textureCache, + const size_t nComputeThreads, + const size_t nUploadThreads, + ConstGLContextPtr glContext ) + : _textureCache( textureCache ) + , _dataSource( textureCache.getDataCache().getDataSource( )) + , _computeExecutor( nComputeThreads, glContext ) + , _uploadExecutor( nUploadThreads, glContext ) + , _nUploadThreads( nUploadThreads ) + { + } + + void createAndConnectUploaders( Pipeline& uploadPipeline, + PipeFilter& visibleSetGenerator, + PipeFilter& output ) const + { + for( size_t i = 0; i < _nUploadThreads; ++i ) + { + std::stringstream name; + name << "DataUploader" << i; + PipeFilter uploader = + uploadPipeline.add< DataUploadFilter >( name.str(), + i, + _nUploadThreads, + _textureCache ); + visibleSetGenerator.connect( "VisibleNodes", + uploader, "VisibleNodes" ); + visibleSetGenerator.connect( "Params", + uploader, "Params" ); + uploader.connect( "CacheObjects", output, "CacheObjects" ); + } + } + + void createSyncPipeline( PipeFilter& renderFilter, + Pipeline& computePipeline, + Pipeline& uploadPipeline ) const + { + PipeFilter visibleSetGenerator = + computePipeline.add< VisibleSetGeneratorFilter >( + "VisibleSetGenerator", _dataSource ); + + createAndConnectUploaders( uploadPipeline, + visibleSetGenerator, + renderFilter ); + } + + void createAsyncPipeline( PipeFilter& renderFilter, + PipeFilter& redrawFilter, + Pipeline& computePipeline, + Pipeline& uploadPipeline ) const + { + PipeFilter visibleSetGenerator = + computePipeline.add< VisibleSetGeneratorFilter >( + "VisibleSetGenerator", _dataSource ); + + PipeFilter renderingSetGenerator = + computePipeline.add< RenderingSetGeneratorFilter >( + "RenderingSetGenerator", _textureCache ); + + visibleSetGenerator.connect( "VisibleNodes", + renderingSetGenerator, "VisibleNodes" ); + + renderingSetGenerator.connect( "CacheObjects", + renderFilter, "CacheObjects" ); + + renderingSetGenerator.connect( "RenderingDone", + redrawFilter, "RenderingDone" ); + + createAndConnectUploaders( uploadPipeline, + visibleSetGenerator, + redrawFilter ); + } + + void render( const VolumeRendererParameters& vrParams, + const FrameInfo& frameInfo, + const Range& dataRange, + const PixelViewport& pixelViewPort, + PipeFilter redrawFilter, + Renderer& renderer, + size_t& nAvailable, + size_t& nNotAvailable ) const + { + + PipeFilterT< RenderFilter > renderFilter( "RenderFilter", _dataSource, renderer ); + + Pipeline computePipeline; + Pipeline uploadPipeline; + + if( vrParams.getSynchronousMode( )) + createSyncPipeline( renderFilter, + computePipeline, + uploadPipeline ); + else + createAsyncPipeline( renderFilter, + redrawFilter, + computePipeline, + uploadPipeline ); + + PipeFilter visibleSetGenerator = + static_cast< const livre::PipeFilter& >( + computePipeline.getExecutable( "VisibleSetGenerator" )); + + visibleSetGenerator.getPromise( "Frustum" ).set( frameInfo.frustum ); + visibleSetGenerator.getPromise( "Frame" ).set( frameInfo.frameId ); + visibleSetGenerator.getPromise( "DataRange" ).set( dataRange ); + visibleSetGenerator.getPromise( "Params" ).set( vrParams ); + visibleSetGenerator.getPromise( "Viewport" ).set( pixelViewPort ); + + renderFilter.getPromise( "Frustum" ).set( frameInfo.frustum ); + renderFilter.getPromise( "Viewport" ).set( pixelViewPort ); + + if( !vrParams.getSynchronousMode( )) + redrawFilter.schedule( _computeExecutor ); + computePipeline.schedule( _computeExecutor ); + uploadPipeline.schedule( _uploadExecutor ); + + renderFilter.execute(); + + if( vrParams.getSynchronousMode( )) + { + const UniqueFutureMap futures( visibleSetGenerator.getPostconditions( )); + nAvailable = futures.get< NodeIds >( "VisibleNodes" ).size(); + nNotAvailable = 0; + } + else + { + const PipeFilter renderingSetGenerator = + static_cast< const livre::PipeFilter& >( + computePipeline.getExecutable( "RenderingSetGenerator" )); + + const UniqueFutureMap futures( renderingSetGenerator.getPostconditions( )); + nAvailable = futures.get< size_t >( "AvailableCount" ); + nNotAvailable = futures.get< size_t >( "NotAvailableCount" ); + } + } + + TextureCache& _textureCache; + const DataSource& _dataSource; + mutable SimpleExecutor _computeExecutor; + mutable SimpleExecutor _uploadExecutor; + const size_t _nUploadThreads; +}; + +RenderPipeline::RenderPipeline( TextureCache& textureCache, + const size_t nComputeThreads, + const size_t nUploadThreads, + ConstGLContextPtr glContext ) + : _impl( new RenderPipeline::Impl( textureCache, + nComputeThreads, + nUploadThreads, + glContext )) +{} + +RenderPipeline::~RenderPipeline() +{} + +void RenderPipeline::render( const VolumeRendererParameters& vrParams, + const FrameInfo& frameInfo, + const Range& dataRange, + const PixelViewport& pixelViewPort, + const PipeFilter& redrawFilter, + Renderer& renderer, + size_t& nAvailable, + size_t& nNotAvailable ) const +{ + _impl->render( vrParams, + frameInfo, + dataRange, + pixelViewPort, + redrawFilter, + renderer, + nAvailable, + nNotAvailable ); +} + +} diff --git a/livre/lib/pipeline/RenderPipeline.h b/livre/lib/pipeline/RenderPipeline.h new file mode 100644 index 00000000..1fbb1d62 --- /dev/null +++ b/livre/lib/pipeline/RenderPipeline.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _RenderPipeline_h_ +#define _RenderPipeline_h_ + +#include +#include + +namespace livre +{ + +/** + * RenderPipeline generates and executes the rendering pipeline every frame + */ +class RenderPipeline +{ + +public: + + /** + * Constructor + * @param textureCache the texture cache + * @param nComputeThreads number of compute threads + * @param nUploadThreads number of upload threads + * @param glContext the gl context that will be shared + */ + RenderPipeline( TextureCache& textureCache, + const size_t nComputeThreads, + const size_t nUploadThreads, + ConstGLContextPtr glContext ); + + ~RenderPipeline(); + + /** + * Renders a frame using the given frustum and view + * @param vrParams rendering parameters + * @param frameInfo frustum and frame id + * @param dataRange range of the data + * @param pixelViewPort the view port + * @param redrawFilter executed on data update + * @param renderer the rendering algorithm + * @param nAvailable number of available texture blocks + * @param nNotAvailable number of not available texture blocks + */ + void render( const VolumeRendererParameters& vrParams, + const FrameInfo& frameInfo, + const Range& dataRange, + const PixelViewport& pixelViewPort, + const PipeFilter& redrawFilter, + Renderer& renderer, + size_t& nAvailable, + size_t& nNotAvailable ) const; +private: + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif + diff --git a/livre/lib/pipeline/RenderingSetGeneratorFilter.cpp b/livre/lib/pipeline/RenderingSetGeneratorFilter.cpp new file mode 100644 index 00000000..2f3ee37a --- /dev/null +++ b/livre/lib/pipeline/RenderingSetGeneratorFilter.cpp @@ -0,0 +1,193 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include +#include +#include +#include + +namespace livre +{ + +struct RenderingSetGenerator +{ + RenderingSetGenerator( const TextureCache& textureCache ) + : _textureCache( textureCache ) + {} + + bool hasParentInMap( const NodeId& childRenderNode, + const ConstCacheMap& cacheMap ) const + { + const NodeIds& parentNodeIds = childRenderNode.getParents(); + + for( const NodeId& parentId : parentNodeIds ) + if( cacheMap.find( parentId.getId( )) != cacheMap.end() ) + return true; + + return false; + } + + void collectLoadedTextures( const NodeId& nodeId, + ConstCacheMap& cacheMap ) const + { + NodeId current = nodeId; + while( current.isValid( )) + { + const NodeId& currentNodeId = current; + const ConstCacheObjectPtr texture = _textureCache.get( currentNodeId.getId( )); + if( texture && texture->isLoaded( )) + { + cacheMap[ currentNodeId.getId() ] = texture; + break; + } + + current = currentNodeId.isRoot() ? NodeId() : + currentNodeId.getParent(); + } + } + + ConstCacheObjects generateRenderingSet( const NodeIds& visibles, + size_t& nAvailable, + size_t& nNotAvailable ) const + { + ConstCacheMap cacheMap; + for( const NodeId& nodeId : visibles ) + { + collectLoadedTextures( nodeId, cacheMap ); + cacheMap.count( nodeId.getId( )) > 0 ? ++nAvailable : ++nNotAvailable; + } + + if( visibles.size() != cacheMap.size( )) + { + ConstCacheMap::const_iterator it = cacheMap.begin(); + size_t previousSize = 0; + do + { + previousSize = cacheMap.size(); + while( it != cacheMap.end( )) + { + if( hasParentInMap( NodeId( it->first ), cacheMap )) + it = cacheMap.erase( it ); + else + ++it; + } + } + while( previousSize != cacheMap.size( )); + } + + ConstCacheObjects cacheObjects; + cacheObjects.reserve( cacheMap.size( )); + for( ConstCacheMap::const_iterator it = cacheMap.begin(); + it != cacheMap.end(); ++it ) + { + cacheObjects.push_back( it->second ); + } + + return cacheObjects; + } + + const TextureCache& _textureCache; +}; + +struct RenderingSetGeneratorFilter::Impl +{ + Impl( const TextureCache& cache ) + : _cache( cache ) + {} + + void execute( const FutureMap& input, + PromiseMap& output ) const + { + RenderingSetGenerator renderSetGenerator( _cache ); + + ConstCacheObjects cacheObjects; + size_t nVisible = 0; + size_t nAvailable = 0; + size_t nNotAvailable = 0; + for( const auto& visibles: input.get< NodeIds >( "VisibleNodes" )) + { + size_t available = 0; + size_t notAvailable = 0; + const ConstCacheObjects& objs = renderSetGenerator.generateRenderingSet( visibles, + available, + notAvailable ); + cacheObjects.insert( cacheObjects.end(), objs.begin(), objs.end( )); + nVisible += visibles.size(); + nAvailable += available; + nNotAvailable += notAvailable; + } + + output.set( "CacheObjects", cacheObjects ); + output.set( "RenderingDone", cacheObjects.size() == nVisible ); + output.set( "AvailableCount", nAvailable ); + output.set( "NotAvailableCount", nNotAvailable ); + } + + DataInfos getInputDataInfos() const + { + return + { + { "VisibleNodes", getType< NodeIds >( )} + }; + } + + DataInfos getOutputDataInfos() const + { + return + { + { "CacheObjects", getType< ConstCacheObjects >( )}, + { "RenderingDone", getType< bool >() }, + { "AvailableCount", getType< size_t >() }, + { "NotAvailableCount", getType< size_t >() }, + }; + } + + const TextureCache& _cache; +}; + +RenderingSetGeneratorFilter::RenderingSetGeneratorFilter( const TextureCache& cache ) + : _impl( new RenderingSetGeneratorFilter::Impl( cache )) +{ +} + +RenderingSetGeneratorFilter::~RenderingSetGeneratorFilter() +{ +} + +void RenderingSetGeneratorFilter::execute( const FutureMap& input, + PromiseMap& output ) const +{ + _impl->execute( input, output ); +} + +DataInfos RenderingSetGeneratorFilter::getInputDataInfos() const +{ + return _impl->getInputDataInfos(); +} + +DataInfos RenderingSetGeneratorFilter::getOutputDataInfos() const +{ + return _impl->getOutputDataInfos(); +} + + +} diff --git a/livre/core/dash/DashContextTrait.h b/livre/lib/pipeline/RenderingSetGeneratorFilter.h similarity index 50% rename from livre/core/dash/DashContextTrait.h rename to livre/lib/pipeline/RenderingSetGeneratorFilter.h index 79f51046..9ed53a15 100644 --- a/livre/core/dash/DashContextTrait.h +++ b/livre/lib/pipeline/RenderingSetGeneratorFilter.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project * Ahmet Bilgili * * This file is part of Livre @@ -17,47 +17,53 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _DashContextTrait_h_ -#define _DashContextTrait_h_ +#ifndef _RenderingSetGeneratorFilter_h_ +#define _RenderingSetGeneratorFilter_h_ -#include -#include -#include +#include + +#include +#include namespace livre { /** - * DashContextTrait class is used to give dash abilities to the classes. + * RenderingSetGeneratorFilter class generates the rendering set given the visibles. */ -class DashContextTrait +class RenderingSetGeneratorFilter : public Filter { + public: + /** - * Sets the dash context. - * @param dashContextPtr context ptr. + * Constructor + * @param textureCache the texture cache */ - LIVRECORE_API void setDashContext( DashContextPtr dashContextPtr ); + RenderingSetGeneratorFilter( const TextureCache& textureCache ); + ~RenderingSetGeneratorFilter(); /** - * @return The dash context. + * @copydoc Filter::execute */ - LIVRECORE_API DashContextPtr getDashContext( ); + void execute( const FutureMap& input, PromiseMap& output ) const final; - LIVRECORE_API virtual ~DashContextTrait() {} - -private: + /** + * @copydoc Filter::getInputDataInfos + */ + DataInfos getInputDataInfos() const final; /** - * Is called when the dash context is set. + * @copydoc Filter::getOutputDataInfos */ - virtual void onSetDashContext_( ) {} + DataInfos getOutputDataInfos() const final; - DashContextPtr dashContextPtr_; +private: + struct Impl; + std::unique_ptr _impl; }; - } -#endif // _Processor_h_ +#endif diff --git a/livre/lib/pipeline/VisibleSetGeneratorFilter.cpp b/livre/lib/pipeline/VisibleSetGeneratorFilter.cpp new file mode 100644 index 00000000..10c022ef --- /dev/null +++ b/livre/lib/pipeline/VisibleSetGeneratorFilter.cpp @@ -0,0 +1,122 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace livre +{ + +struct VisibleSetGeneratorFilter::Impl +{ + Impl( const DataSource& dataSource ) + : _dataSource( dataSource ) + {} + + void execute( const FutureMap& input, + PromiseMap& output ) const + { + const UniqueFutureMap uniqueInputs( input.getFutures( )); + + const auto& frustum = uniqueInputs.get< Frustum >( "Frustum" ); + const auto& frame = uniqueInputs.get< uint32_t >( "Frame" ); + const auto& range = uniqueInputs.get< Range >( "DataRange" ); + const auto& params = uniqueInputs.get< VolumeRendererParameters >( "Params" ); + const auto& vp = uniqueInputs.get< PixelViewport >( "Viewport" ); + + const uint32_t windowHeight = vp[ 3 ]; + const float sse = params.getSSE(); + const uint32_t minLOD = params.getMinLOD(); + const uint32_t maxLOD = params.getMaxLOD(); + + SelectVisibles visitor( _dataSource, + frustum, + windowHeight, + sse, + minLOD, + maxLOD, + range ); + + DFSTraversal traverser; + traverser.traverse( _dataSource.getVolumeInfo().rootNode, + visitor, + frame ); + + output.set( "VisibleNodes", visitor.getVisibles( )); + output.set( "Params", params ); + } + + DataInfos getInputDataInfos() const + { + return { + { "Frustum" ,getType< Frustum >() }, + { "Frame" ,getType< uint32_t >() }, + { "DataRange" ,getType< Range >() }, + { "Params" ,getType< VolumeRendererParameters >() }, + { "Viewport" ,getType< PixelViewport >() } + }; + } + + DataInfos getOutputDataInfos() const + { + return + { + { "VisibleNodes" ,getType< NodeIds >( )}, + { "Params" ,getType< VolumeRendererParameters >() } + }; + } + + const DataSource& _dataSource; +}; + +VisibleSetGeneratorFilter::VisibleSetGeneratorFilter( const DataSource& dataSource ) + : _impl( new VisibleSetGeneratorFilter::Impl( dataSource )) +{ +} + +VisibleSetGeneratorFilter::~VisibleSetGeneratorFilter() +{ + +} + +void VisibleSetGeneratorFilter::execute( const FutureMap& input, + PromiseMap& output ) const +{ + _impl->execute( input, output ); +} + +DataInfos VisibleSetGeneratorFilter::getInputDataInfos() const +{ + return _impl->getInputDataInfos(); +} + +DataInfos VisibleSetGeneratorFilter::getOutputDataInfos() const +{ + return _impl->getOutputDataInfos(); +} + + + +} diff --git a/livre/lib/pipeline/VisibleSetGeneratorFilter.h b/livre/lib/pipeline/VisibleSetGeneratorFilter.h new file mode 100644 index 00000000..00c30dc1 --- /dev/null +++ b/livre/lib/pipeline/VisibleSetGeneratorFilter.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2011-2015, EPFL/Blue Brain Project + * Ahmet Bilgili + * + * This file is part of Livre + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 3.0 as published + * by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _VisibleSetGeneratorFilter_h_ +#define _VisibleSetGeneratorFilter_h_ + +#include + +#include +#include + +namespace livre +{ + +/** + * Collects all the visibles for given inputs ( Frustums, Frames, Data Ranges, + * Rendering params and Viewports ) + */ +class VisibleSetGeneratorFilter : public Filter +{ + +public: + + /** + * Constructor + * @param dataSource the data source + */ + VisibleSetGeneratorFilter( const DataSource& dataSource ); + ~VisibleSetGeneratorFilter(); + + /** + * @copydoc Filter::execute + */ + void execute( const FutureMap& input, PromiseMap& output ) const final; + + /** + * @copydoc Filter::getInputDataInfos + */ + DataInfos getInputDataInfos() const final; + + /** + * @copydoc Filter::getOutputDataInfos + * + */ + DataInfos getOutputDataInfos() const final; + +private: + + struct Impl; + std::unique_ptr _impl; +}; + +} + +#endif diff --git a/livre/lib/render/AvailableSetGenerator.cpp b/livre/lib/render/AvailableSetGenerator.cpp deleted file mode 100644 index 5496ec3b..00000000 --- a/livre/lib/render/AvailableSetGenerator.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -#include -#include - -namespace livre -{ - -struct AvailableSetGenerator::Impl -{ - Impl( const TextureCache& textureCache ) - : _textureCache( textureCache ) - {} - - bool hasParentInMap( const NodeId& childRenderNode, - const ConstCacheMap& cacheMap ) const - { - const NodeIds& parentNodeIds = childRenderNode.getParents(); - - for( const NodeId& parentId : parentNodeIds ) - if( cacheMap.find( parentId.getId( )) != cacheMap.end() ) - return true; - - return false; - } - - void collectLoadedTextures( const NodeId& nodeId, ConstCacheMap& cacheMap, - NodeIds& notAvailableRenderNodes ) const - { - NodeId current = nodeId; - while( current.isValid( )) - { - const NodeId& currentNodeId = current; - const ConstCacheObjectPtr texture = _textureCache.get( currentNodeId.getId( )); - if( texture && texture->isLoaded( )) - { - cacheMap[ currentNodeId.getId() ] = texture; - break; - } - - current = currentNodeId.isRoot() ? NodeId() : - currentNodeId.getParent(); - } - - if( nodeId != current ) - notAvailableRenderNodes.push_back( nodeId ); - } - - void generateRenderingSet( FrameInfo& frameInfo ) const - { - ConstCacheMap cacheMap; - for( const NodeId& nodeId : frameInfo.allNodes ) - { - collectLoadedTextures( nodeId, cacheMap, - frameInfo.notAvailableRenderNodes ); - } - - if( !frameInfo.notAvailableRenderNodes.empty( )) - { - ConstCacheMap::const_iterator it = cacheMap.begin(); - size_t previousSize = 0; - do - { - previousSize = cacheMap.size(); - while( it != cacheMap.end( )) - { - if( hasParentInMap( NodeId( it->first ), cacheMap )) - it = cacheMap.erase( it ); - else - ++it; - } - } - while( previousSize != cacheMap.size( )); - } - - frameInfo.renderNodes.reserve( cacheMap.size( )); - for( ConstCacheMap::const_iterator it = cacheMap.begin(); - it != cacheMap.end(); ++it ) - { - frameInfo.renderNodes.push_back( it->second ); - } - } - - const TextureCache& _textureCache; -}; - - -AvailableSetGenerator::AvailableSetGenerator( const TextureCache& textureCache ) - : _impl( new AvailableSetGenerator::Impl( textureCache )) -{ -} - -AvailableSetGenerator::~AvailableSetGenerator() -{} - -void AvailableSetGenerator::generateRenderingSet( FrameInfo& frameInfo ) const -{ - _impl->generateRenderingSet( frameInfo ); -} - -} diff --git a/livre/lib/render/SelectVisibles.h b/livre/lib/render/SelectVisibles.h deleted file mode 100644 index 96be0975..00000000 --- a/livre/lib/render/SelectVisibles.h +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2015, EPFL/Blue Brain Project - * Stefan.Eilemann@epfl.ch - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _SelectVisibles_h_ -#define _SelectVisibles_h_ - -#include -#include -#include -#include -#include -#include -#include -#include - -//#define LIVRE_STATIC_DECOMPOSITION - -namespace livre -{ -/** Selects all visible rendering nodes */ -class SelectVisibles : public livre::RenderNodeVisitor -{ -public: - SelectVisibles( DashTree& dashTree, - const Frustum& frustum, - const uint32_t windowHeight, - const float screenSpaceError, - const uint32_t minLOD, - const uint32_t maxLOD, - const Range& range ) - : RenderNodeVisitor( dashTree ) - , _frustum( frustum ) - , _windowHeight( windowHeight ) - , _screenSpaceError( screenSpaceError ) - , _minLOD( minLOD ) - , _maxLOD( maxLOD ) - , _range( range ) - {} - - const DashRenderNodes& getVisibles() const { return _visibles; } - -protected: - void visitPre() final { _visibles.clear(); } - - void visit( DashRenderNode& renderNode, VisitState& state ) final - { - const LODNode& lodNode = renderNode.getLODNode(); - if( !lodNode.isValid( )) - return; - - const Boxf& worldBox = lodNode.getWorldBox(); - const bool isInFrustum = _frustum.boxInFrustum( worldBox ); - renderNode.setInFrustum( isInFrustum ); - renderNode.setLODVisible( false ); - if( !isInFrustum ) - { - state.setVisitChild( false ); - return; - } - - Vector3f vmin, vmax; - const Plane& nearPlane = _frustum.getNearPlane(); - - worldBox.computeNearFar( nearPlane, vmin, vmax ); - - Vector4f hVmin = vmin; - hVmin[ 3 ] = 1.0f; - - Vector4f hVmax = vmax; - hVmax[ 3 ] = 1.0f; - - // The bounding box intersects the plane - if( _frustum.getNearPlane().dot( hVmin ) < 0 || - _frustum.getNearPlane().dot( hVmax ) < 0 ) - { - // Where eye direction intersects with near plane - vmin = _frustum.getEyePos() - _frustum.getViewDir() * _frustum.nearPlane(); - } - - const Vector3f voxelBox = lodNode.getVoxelBox().getSize(); - const Vector3f worldSpacePerVoxel = worldBox.getSize() / voxelBox; - - bool lodVisible = isLODVisible( _frustum, - vmin, - worldSpacePerVoxel.find_min(), - _windowHeight, - _screenSpaceError ); - - const VolumeInformation& volInfo = - getDashTree().getDataSource().getVolumeInfo(); - const uint32_t depth = volInfo.rootNode.getDepth(); - lodVisible = ( lodVisible && lodNode.getRefLevel() >= _minLOD ) - || ( lodNode.getRefLevel() == _maxLOD ) - || ( lodNode.getRefLevel() == depth - 1 ); - - if( lodVisible ) - _visibles.push_back( renderNode ); - state.setVisitChild( !lodVisible ); - } - - - bool isLODVisible( const Frustum& frustum, - const Vector3f& worldCoord, - const float worldSpacePerVoxel, - const uint32_t windowHeight, - const float screenSpaceError ) - { - const float t = frustum.top(); - const float b = frustum.bottom(); - - const float worldSpacePerPixel = ( t - b ) / windowHeight; - const float pixelPerVoxel = worldSpacePerVoxel / worldSpacePerPixel; - - Vector4f hWorldCoord = worldCoord; - hWorldCoord[ 3 ] = 1.0f; - const float distance = std::abs( frustum.getNearPlane().dot( hWorldCoord )); - - const float n = frustum.nearPlane(); - const float pixelPerVoxelInDistance = pixelPerVoxel * n / ( n + distance ); - - return pixelPerVoxelInDistance <= screenSpaceError; - } - - void visitPost() final - { - // Sort-last range selection: -#ifndef LIVRE_STATIC_DECOMPOSITION - const size_t startIndex = _range[0] * _visibles.size(); - const size_t endIndex = _range[1] * _visibles.size(); -#endif - DashRenderNodes selected; - - for( size_t i = 0; i < _visibles.size(); ++i ) - { -#ifdef LIVRE_STATIC_DECOMPOSITION - const Range& nodeRange = - _visibles[i].getLODNode().getNodeId().getRange(); - const bool isInRange = nodeRange[1] > _range[0] && - nodeRange[1] <= _range[1]; -#else - const bool isInRange = i >= startIndex && i < endIndex; -#endif - _visibles[i].setLODVisible( isInRange ); - _visibles[i].setInFrustum( isInRange ); - if( isInRange ) - selected.push_back( _visibles[i] ); - } - _visibles.swap( selected ); - } - -private: - - const Frustum& _frustum; - const uint32_t _windowHeight; - const float _screenSpaceError; - const uint32_t _minLOD; - const uint32_t _maxLOD; - const Range _range; - DashRenderNodes _visibles; -}; -} -#endif - diff --git a/livre/lib/types.h b/livre/lib/types.h index 8624d07e..2ce1fc37 100644 --- a/livre/lib/types.h +++ b/livre/lib/types.h @@ -27,13 +27,11 @@ namespace livre { -class DataUploadProcessor; -class RenderNodeVisitor; +class RenderPipeline; class TextureCache; class TextureDataCache; class TextureDataObject; class TextureObject; -class TextureUploadProcessor; struct ApplicationParameters; typedef std::shared_ptr< const TextureDataObject > ConstTextureDataObjectPtr; @@ -43,8 +41,6 @@ typedef std::shared_ptr< TextureObject > TextureObjectPtr; static const uint32_t CONNECTION_ID( 0u ); -typedef std::vector< DashRenderNode > DashRenderNodes; - } #endif // _types_h_ diff --git a/livre/lib/uploaders/DataUploadProcessor.cpp b/livre/lib/uploaders/DataUploadProcessor.cpp deleted file mode 100644 index cef54d96..00000000 --- a/livre/lib/uploaders/DataUploadProcessor.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project - * Ahmet Bilgili - * Daniel Nachbaur - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace livre -{ - -#ifdef _ITT_DEBUG_ -#include -__itt_domain* ittDataLoadDomain = __itt_domain_create("Data Loading"); -__itt_string_handle* ittDataComputationTask = __itt_string_handle_create("Data loading computation"); -__itt_string_handle* ittDataLoadTask = __itt_string_handle_create("Data loading task"); -#endif // _ITT_DEBUG_ - -class DataLoaderVisitor : public RenderNodeVisitor -{ -public: - DataLoaderVisitor( DashTree& dashTree, TextureDataCache& textureDataCache, - ProcessorInputPtr processorInput, - ProcessorOutputPtr processorOutput ) - : RenderNodeVisitor( dashTree ), - _cache( textureDataCache ), - _input( processorInput ), - _output( processorOutput ) - {} - - void visit( DashRenderNode& renderNode, VisitState& state ); - -private: - TextureDataCache& _cache; - ProcessorInputPtr _input; - ProcessorOutputPtr _output; - lunchbox::Clock _clock; -}; - -class DepthCollectorVisitor : public RenderNodeVisitor -{ -public: - DepthCollectorVisitor( DashTree& dashTree, - TextureDataCache& textureDataCache, - ProcessorOutputPtr processorOutput, - DashNodeVector& refLevelCollection ) - : RenderNodeVisitor( dashTree ), - _cache( textureDataCache ), - _output( processorOutput ), - _collection( refLevelCollection ) - {} - void visit( DashRenderNode& node, VisitState& state ) final; - -private: - TextureDataCache& _cache; - ProcessorOutputPtr _output; - DashNodeVector& _collection; -}; - -class DepthSortedDataLoaderVisitor : public RenderNodeVisitor -{ -public: - DepthSortedDataLoaderVisitor( DashTree& dashTree, - TextureDataCache& textureDataCache, - ProcessorInputPtr processorInput, - ProcessorOutputPtr processorOutput ) - : RenderNodeVisitor( dashTree ) - , _cache( textureDataCache ) - , _input( processorInput ) - , _output( processorOutput ) - {} - - void visit( DashRenderNode& renderNode, VisitState& state ) final; -private: - TextureDataCache& _cache; - ProcessorInputPtr _input; - ProcessorOutputPtr _output; -}; - -// Sort helper function for sorting the textures to load the front texture data first -struct DepthCompare -{ - explicit DepthCompare( const Frustum& frustum ) - : frustum_( frustum ) { } - - bool operator()( dash::NodePtr node1, - dash::NodePtr node2 ) - { - DashRenderNode renderNode1( node1 ); - DashRenderNode renderNode2( node2 ); - - const LODNode& lodNode1 = renderNode1.getLODNode(); - const LODNode& lodNode2 = renderNode2.getLODNode(); - - const float depth1 = ( frustum_.getEyePos() - - lodNode1.getWorldBox().getCenter( )).length(); - const float depth2 = ( frustum_.getEyePos() - - lodNode2.getWorldBox().getCenter( )).length(); - return depth1 < depth2; - } - const Frustum& frustum_; -}; - -DataUploadProcessor::DataUploadProcessor( DashTree& dashTree, - GLContextPtr shareContext, - TextureDataCache& textureDataCache ) - : _dashTree( dashTree ) - , _glContext( shareContext->clone( )) - , _sharedContext( shareContext ) - , _textureDataCache( textureDataCache ) - , _currentFrameID( 0 ) - , _threadOp( TO_NONE ) -{ - setDashContext( dashTree.createContext( )); -} - -bool DataUploadProcessor::initializeThreadRun_() -{ - setName( "DataUp" ); - DataSource& dataSource = _textureDataCache.getDataSource(); - dataSource.initializeGL(); - return DashProcessor::initializeThreadRun_(); -} - -void DataUploadProcessor::runLoop_() -{ - LBASSERT( _glContext ); - if( GLContext::getCurrent() != _glContext.get( )) - { - _glContext->share( *_sharedContext ); - _glContext->makeCurrent(); - } - - processorInputPtr_->applyAll( CONNECTION_ID ); - -#ifdef _ITT_DEBUG_ - __itt_task_begin ( ittDataLoadDomain, __itt_null, __itt_null, ittDataComputationTask ); -#endif //_ITT_DEBUG_ - - _checkThreadOperation(); - _loadData(); - -#ifdef _ITT_DEBUG_ - __itt_task_end( ittDataLoadDomain ); -#endif //_ITT_DEBUG_ - -} - -void DataUploadProcessor::_loadData() -{ - const DashRenderStatus& renderStatus = _dashTree.getRenderStatus(); - - const Frustum& frustum = renderStatus.getFrustum(); - _currentFrameID = renderStatus.getFrameID(); - - DashNodeVector dashNodeList; - DepthCollectorVisitor depthCollectorVisitor( _dashTree, - _textureDataCache, - processorOutputPtr_, - dashNodeList ); - - const RootNode& rootNode = _dashTree.getDataSource().getVolumeInfo().rootNode; - - DFSTraversal traverser; - traverser.traverse( rootNode, depthCollectorVisitor, _currentFrameID ); - - std::sort( dashNodeList.begin( ), dashNodeList.end( ), - DepthCompare( frustum )); - CollectionTraversal collectionTraverser; - DepthSortedDataLoaderVisitor dataLoader( _dashTree, _textureDataCache, - processorInputPtr_, - processorOutputPtr_ ); - collectionTraverser.traverse( dashNodeList, dataLoader ); - processorOutputPtr_->commit( CONNECTION_ID ); - - DataLoaderVisitor loadVisitor( _dashTree, _textureDataCache, - processorInputPtr_, processorOutputPtr_ ); - - traverser.traverse( rootNode, loadVisitor, _currentFrameID ); - processorOutputPtr_->commit( CONNECTION_ID ); -} - -void DataUploadProcessor::_checkThreadOperation() -{ - DashRenderStatus& renderStatus = _dashTree.getRenderStatus(); - ThreadOperation op = renderStatus.getThreadOp(); - if( op != _threadOp ) - { - _threadOp = op; - renderStatus.setThreadOp( op ); - processorOutputPtr_->commit( CONNECTION_ID ); - } - - if( _threadOp == TO_EXIT ) - exit(); -} - -void DataLoaderVisitor::visit( DashRenderNode& renderNode, VisitState& state ) -{ - const LODNode& node = renderNode.getLODNode(); - - if( !node.isValid() ) - return; - - state.setBreakTraversal( _input->dataWaitingOnInput( CONNECTION_ID )); - - if( !renderNode.isInFrustum( )) - { - state.setVisitChild( false ); - return; - } - - if( !renderNode.isLODVisible( )) - return; - - state.setVisitChild( false ); - - const ConstCacheObjectPtr texture = renderNode.getTextureObject(); - if( texture && texture->isLoaded( )) - return; - - const ConstCacheObjectPtr tData = _cache.get( node.getNodeId().getId( )); - if( tData->isLoaded( )) - return; - -#ifdef _ITT_DEBUG_ - __itt_task_begin( ittDataLoadDomain, __itt_null, __itt_null, - ittDataLoadTask ); -#endif //_ITT_DEBUG_ - CacheObjectPtr textureData = _cache.load( node.getNodeId().getId( )); - if( _clock.getTime64() > 1000 ) // commit once every second - { - _clock.reset(); - _output->commit( CONNECTION_ID ); - } -#ifdef _ITT_DEBUG_ - __itt_task_end( ittDataLoadDomain ); -#endif //_ITT_DEBUG_ -} - -void DepthCollectorVisitor::visit( DashRenderNode& renderNode, VisitState& state ) -{ - const LODNode& lodNode = renderNode.getLODNode(); - - if( !lodNode.isValid( )) - return; - - if( !renderNode.isInFrustum( )) - { - state.setVisitChild( false ); - return; - } - - if( !renderNode.isLODVisible( )) - return; - - state.setVisitChild( false ); - - const ConstCacheObjectPtr texture = renderNode.getTextureObject(); - if( texture && texture->isLoaded( )) - return; - - const ConstCacheObjectPtr tData = renderNode.getTextureDataObject(); - if( tData && tData->isLoaded( )) - return; - - // Triggers creation of the cache object. - const ConstCacheObjectPtr textureData = _cache.get( lodNode.getNodeId().getId( )); - if( textureData && textureData->isLoaded( )) - { - renderNode.setTextureDataObject( textureData ); - _output->commit( CONNECTION_ID ); - return; - } - - _collection.push_back( renderNode.getDashNode()); -} - -void DepthSortedDataLoaderVisitor::visit( DashRenderNode& renderNode, - VisitState& state ) -{ - const LODNode& lodNode = renderNode.getLODNode(); - -#ifdef _ITT_DEBUG_ - __itt_task_begin( ittDataLoadDomain, __itt_null, __itt_null, - ittDataLoadTask ); -#endif //_ITT_DEBUG_ - - CacheObjectPtr textureData = _cache.load( lodNode.getNodeId().getId( )); -#ifdef _ITT_DEBUG_ - __itt_task_end( ittDataLoadDomain ); -#endif //_ITT_DEBUG_ - - renderNode.setTextureDataObject( textureData ); - -#ifdef _DEBUG_ - const ConstCacheObjectPtr tData = renderNode.getTextureDataObject(); - if( !tData->isLoaded() ) - { - LBERROR << "Texture data loaded but no in the render node : " - << textureData.getLODNode()->getNodeId().getId(); - << std::endl; - } -#endif //_DEBUG_ - - _output->commit( CONNECTION_ID ); - state.setBreakTraversal( _input->dataWaitingOnInput( CONNECTION_ID )); - -} - -} diff --git a/livre/lib/uploaders/DataUploadProcessor.h b/livre/lib/uploaders/DataUploadProcessor.h deleted file mode 100644 index 831ed2d9..00000000 --- a/livre/lib/uploaders/DataUploadProcessor.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project - * Ahmet.Bilgili@epfl.ch - * Daniel.Nachbaur@epfl.ch - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _DataLoadProcessor_h_ -#define _DataLoadProcessor_h_ - -#include - -#include -#include -#include - -#include -#include -#include - -namespace livre -{ - -/** - * The DataUploadProcessor class is responsible for loading data into CPU memory. - * It is derived from GLContextTrait class because some algorithms may need OpenGL - * to generate the data. - */ -class DataUploadProcessor : public DashProcessor -{ -public: - /** - * @param dashTree The dash node hierarchy. - * @param shareContext the context which this processors shares against. - * @param context the context used by this processor. - * @param textureDataCache Texture data cache holds the data in the CPU memory. - */ - LIVRE_API DataUploadProcessor( DashTree& dashTree, - GLContextPtr shareContext, - TextureDataCache& textureDataCache ); - -private: - bool initializeThreadRun_( ) final; - void runLoop_( ) final; - void _loadData(); - - DashTree& _dashTree; - GLContextPtr _glContext; - GLContextPtr _sharedContext; - TextureDataCache& _textureDataCache; - uint64_t _currentFrameID; - void _checkThreadOperation( ); - ThreadOperation _threadOp; -}; - -} - -#endif // _DataLoadProcessor_h_ diff --git a/livre/lib/uploaders/TextureUploadProcessor.cpp b/livre/lib/uploaders/TextureUploadProcessor.cpp deleted file mode 100644 index 9abd0f12..00000000 --- a/livre/lib/uploaders/TextureUploadProcessor.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project - * Ahmet Bilgili - * Daniel Nachbaur - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -namespace livre -{ - -#ifdef _ITT_DEBUG_ -#include "ittnotify.h" -__itt_domain* ittTextureLoadDomain = __itt_domain_create("Texture Loading"); -__itt_string_handle* ittTextureComputationTask = - __itt_string_handle_create("Texture loading computation"); -__itt_string_handle* ittTextureLoadTask = __itt_string_handle_create("Texture loading task"); -#endif // _ITT_DEBUG_ - - -// Dont forget to apply cache policy after each traversal -class TextureLoaderVisitor : public RenderNodeVisitor -{ -public: - TextureLoaderVisitor( DashTree& dashTree, - TextureCache& textureCache, - ProcessorInputPtr processorInput, - ProcessorOutputPtr processorOutput, - bool& needRedraw ) - : RenderNodeVisitor( dashTree ) - , _cache( textureCache ) - , _input( processorInput ) - , _output( processorOutput ) - , _allLoaded( true ) // be optimistic; will be set to false on first - // non-loaded data during visit - , _synchronous( false ) - , _needRedraw( needRedraw ) - {} - - void visit( DashRenderNode& renderNode, VisitState& state ) final; - - bool isAllDataLoaded() const { return _allLoaded; } - - bool isSynchronous() const { return _synchronous; } - void setSynchronous( const bool synchronous ) { _synchronous = synchronous;} - -private: - TextureCache& _cache; - ProcessorInputPtr _input; - ProcessorOutputPtr _output; - bool _allLoaded; - bool _synchronous; - bool& _needRedraw; -}; - -class CollectVisiblesVisitor : public RenderNodeVisitor -{ -public: - CollectVisiblesVisitor( DashTree& dashTree ) - : RenderNodeVisitor( dashTree ) {} - - void visit( DashRenderNode& renderNode, VisitState& state ) final - { - if( !renderNode.isInFrustum( ) || renderNode.isLODVisible( )) - state.setVisitChild( false ); - } -}; - -TextureUploadProcessor::TextureUploadProcessor( DashTree& dashTree, - GLContextPtr shareContext, - TextureDataCache& dataCache, - const VolumeRendererParameters& vrParameters ) - : _dashTree( dashTree ) - , _glContext( shareContext->clone( )) - , _sharedContext( shareContext ) - , _currentFrameID( 0 ) - , _threadOp( TO_NONE ) - , _vrParameters( vrParameters ) - , _textureCache( dataCache, - _vrParameters.getMaxGPUCacheMemoryMB() * LB_1MB, - GL_LUMINANCE8 ) - , _allDataLoaded( false ) - , _needRedraw( false ) -{ - setDashContext( dashTree.createContext()); -} - -TextureUploadProcessor::~TextureUploadProcessor() -{ -} - -const TextureCache& TextureUploadProcessor::getTextureCache() const -{ - return _textureCache; -} - -bool TextureUploadProcessor::initializeThreadRun_() -{ - setName( "TexUp" ); - LBASSERT( _glContext ); - return DashProcessor::initializeThreadRun_(); -} - -bool TextureUploadProcessor::onPreCommit_( const uint32_t outputConnection LB_UNUSED ) -{ - const bool ret = _allDataLoaded; - - _allDataLoaded = false; - return ret; -} - -void TextureUploadProcessor::_loadData() -{ - TextureLoaderVisitor loadVisitor( _dashTree, _textureCache, - processorInputPtr_, processorOutputPtr_, - _needRedraw ); - - loadVisitor.setSynchronous( _vrParameters.getSynchronousMode( )); - - DFSTraversal traverser; - const RootNode& rootNode = _dashTree.getDataSource().getVolumeInfo().rootNode; - traverser.traverse( rootNode, loadVisitor, _currentFrameID ); - - if( _vrParameters.getSynchronousMode( )) - _allDataLoaded = loadVisitor.isAllDataLoaded(); - else - _allDataLoaded = true; -} - -void TextureUploadProcessor::runLoop_() -{ - _needRedraw = false; - if( GLContext::getCurrent() != _glContext.get( )) - { - _glContext->share( *_sharedContext ); - _glContext->makeCurrent(); - } - - processorInputPtr_->applyAll( CONNECTION_ID ); - _checkThreadOperation(); - -#ifdef _ITT_DEBUG_ - __itt_task_begin ( ittTextureLoadDomain, __itt_null, __itt_null, ittTextureComputationTask ); -#endif //_ITT_DEBUG_ - - const DashRenderStatus& renderStatus = _dashTree.getRenderStatus(); - if( renderStatus.getFrameID() != _currentFrameID ) - { - _protectUnloading.clear(); - CollectVisiblesVisitor collectVisibles( _dashTree ); - DFSTraversal traverser; - const RootNode& rootNode = - _dashTree.getDataSource().getVolumeInfo().rootNode; - traverser.traverse( rootNode, collectVisibles, renderStatus.getFrameID( )); - _currentFrameID = renderStatus.getFrameID(); - } - _loadData(); - processorOutputPtr_->commit( CONNECTION_ID ); - -#ifdef _ITT_DEBUG_ - __itt_task_end( ittTextureLoadDomain ); -#endif //_ITT_DEBUG_ -} - -void TextureUploadProcessor::_checkThreadOperation() -{ - DashRenderStatus& renderStatus = _dashTree.getRenderStatus(); - ThreadOperation op = renderStatus.getThreadOp(); - if( op != _threadOp ) - { - _threadOp = op; - renderStatus.setThreadOp( op ); - processorOutputPtr_->commit( CONNECTION_ID ); - } - - if( _threadOp == TO_EXIT ) - exit(); -} - -void TextureLoaderVisitor::visit( DashRenderNode& renderNode, VisitState& state ) -{ - const LODNode& lodNode = renderNode.getLODNode(); - if( !lodNode.isValid( )) - return; - - if( !renderNode.isInFrustum( )) - { - state.setVisitChild( false ); - return; - } - - if( !renderNode.isLODVisible( )) - return; - - state.setVisitChild( false ); - - const ConstCacheObjectPtr texPtr = renderNode.getTextureObject(); - if( texPtr && texPtr->isLoaded( )) - return; - - ConstCacheObjectPtr texture = _cache.get( lodNode.getNodeId().getId( )); - if( texture && texture->isLoaded() ) - { - renderNode.setTextureObject( texture ); - _output->commit( CONNECTION_ID ); - return; - } - else - { - const ConstCacheObjectPtr textureData = renderNode.getTextureDataObject(); - if( textureData && textureData->isLoaded( )) - { -#ifdef _ITT_DEBUG_ - __itt_task_begin ( ittTextureLoadDomain, __itt_null, __itt_null, - ittTextureLoadTask ); -#endif //_ITT_DEBUG_ - CacheObjectPtr lodTexture = _cache.load( lodNode.getNodeId().getId( )); - -#ifdef _ITT_DEBUG_ - __itt_task_end( ittTextureLoadDomain ); -#endif //_ITT_DEBUG_ - renderNode.setTextureObject( lodTexture ); - renderNode.setTextureDataObject( textureData ); - _output->commit( CONNECTION_ID ); - _needRedraw = true; - } - else - { - _allLoaded = false; - LBVERB << "Texture data not loaded:" << lodNode.getNodeId() << std::endl; - } - } - - if( !isSynchronous( )) - // only in asynchronous mode - state.setBreakTraversal( _input->dataWaitingOnInput( CONNECTION_ID )); -} - -} diff --git a/livre/lib/uploaders/TextureUploadProcessor.h b/livre/lib/uploaders/TextureUploadProcessor.h deleted file mode 100644 index 837b512b..00000000 --- a/livre/lib/uploaders/TextureUploadProcessor.h +++ /dev/null @@ -1,82 +0,0 @@ - -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet.Bilgili@epfl.ch - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _TextureLoadProcessor_h_ -#define _TextureLoadProcessor_h_ - -#include -#include - -#include -#include -#include - -namespace livre -{ - -/** - * The TextureLoadProcessor class is responsible for loading texture data to GPU. - */ -class TextureUploadProcessor : public DashProcessor -{ -public: - /** - * @param dashTree The dash node hierarchy. - * @param shareContext the context which this processors shares against. - * @param context the context used by this processor. - * @param vrParameters the volume rendering parameters. - */ - LIVRE_API TextureUploadProcessor( DashTree& dashTree, - GLContextPtr shareContext, - TextureDataCache& dataCache, - const VolumeRendererParameters& vrParameters ); - - LIVRE_API ~TextureUploadProcessor(); - - /** @return the texture cache */ - LIVRE_API const TextureCache& getTextureCache() const; - -protected: - LIVRE_API bool onPreCommit_( uint32_t connection ) override; - bool needRedraw() const { return _needRedraw; } - -private: - LIVRE_API bool initializeThreadRun_( ) final; - LIVRE_API void runLoop_( ) final; - - void _loadData(); - void _checkThreadOperation( ); - - DashTree& _dashTree; - GLContextPtr _glContext; - GLContextPtr _sharedContext; - - uint64_t _currentFrameID; - ThreadOperation _threadOp; - CacheIdSet _protectUnloading; - const VolumeRendererParameters& _vrParameters; - TextureCache _textureCache; - bool _allDataLoaded; - bool _needRedraw; -}; - -} - -#endif // _TextureLoadProcessor_h_ diff --git a/livre/lib/visitor/CollectionTraversal.cpp b/livre/lib/visitor/CollectionTraversal.cpp deleted file mode 100644 index e2c77735..00000000 --- a/livre/lib/visitor/CollectionTraversal.cpp +++ /dev/null @@ -1,63 +0,0 @@ - -/* Copyright (c) 2011-2015, EPFL/Blue Brain Project - * Ahmet.Bilgili@epfl.ch - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - -#include -#include -#include - -namespace livre -{ - -bool CollectionTraversal::traverse( DashNodeVector& dashNodeVector, - RenderNodeVisitor& visitor, - const bool reverse ) -{ - DashNodeVector::const_iterator begin; - DashNodeVector::const_iterator end; - - if( reverse ) - { - begin = dashNodeVector.end(); - end = dashNodeVector.begin(); - } - else - { - begin = dashNodeVector.begin(); - end = dashNodeVector.end(); - } - - VisitState state; - visitor.visitPre(); - - for( DashNodeVector::const_iterator i = begin; - i != end && !state.getBreakTraversal(); - reverse ? --i : ++i ) - { - DashRenderNode renderNode( *i ); - visitor.visit( renderNode, state ); - } - - visitor.visitPost(); - return state.getBreakTraversal(); -} - -} diff --git a/livre/lib/visitor/CollectionTraversal.h b/livre/lib/visitor/CollectionTraversal.h deleted file mode 100644 index de0dea42..00000000 --- a/livre/lib/visitor/CollectionTraversal.h +++ /dev/null @@ -1,49 +0,0 @@ - -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet.Bilgili@epfl.ch - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _CollectionTraversal_h_ -#define _CollectionTraversal_h_ - -#include -#include - -namespace livre -{ -/** - * The CollectionTraversal class is used to traverse the DashNodeVector with a given visitor. - */ -class CollectionTraversal -{ -public: - /** - * Traverse a collection with the given visitor. Visitor can decide to end traversal. - * @param dashNodeVector the (backward-)iterable dash node collection. - * @param visitor Visitor object. - * @param reverse If reverse given, the dash vector is traversed in reverse (default: false) - * @return True if traversal is completed, without being aborted/ended. - */ - bool traverse( DashNodeVector& dashNodeVector, - RenderNodeVisitor& visitor, - const bool reverse = false ); -}; - -} - -#endif // _CollectionTraversal_h_ diff --git a/livre/uvf/UVFDataSource.cpp b/livre/uvf/UVFDataSource.cpp index a05b470a..da3aba83 100644 --- a/livre/uvf/UVFDataSource.cpp +++ b/livre/uvf/UVFDataSource.cpp @@ -19,7 +19,6 @@ #include -#include #include #include diff --git a/tests/lib/lodSelection.cpp b/tests/lib/lodSelection.cpp index 03b44469..971897f7 100644 --- a/tests/lib/lodSelection.cpp +++ b/tests/lib/lodSelection.cpp @@ -18,19 +18,18 @@ */ #define BOOST_TEST_MODULE LodSelection -#include - -#include -#include #include -#include -#include +#include +#include +#include #include #include +#include + // Explicit registration required because the folder of the data source plugin is not // in the LD_LIBRARY_PATH of the test executable. lunchbox::PluginRegisterer< livre::MemoryDataSource > registerer; @@ -43,8 +42,6 @@ Identifiers getVisibles( const livre::DataSource& dataSource, const uint32_t minLOD, const uint32_t maxLOD ) { - livre::DashTree dashTree( dataSource ); - dashTree.createContext()->setCurrent(); const float projArray[] = { 2.0, 0, 0, 0, 0, 2.0, 0, 0, 0, 0, -1.01342285, -1, @@ -60,7 +57,7 @@ Identifiers getVisibles( const livre::DataSource& dataSource, const livre::Matrix4f mvMat( mvArray, mvArray + 16 ); const livre::Frustum frustum( mvMat, projMat ); - livre::SelectVisibles selectVisibles( dashTree, + livre::SelectVisibles selectVisibles( dataSource, frustum, windowHeight, screenSpaceError, @@ -74,8 +71,8 @@ Identifiers getVisibles( const livre::DataSource& dataSource, Identifiers visibles; - for( const livre::DashRenderNode& dashNode: selectVisibles.getVisibles( )) - visibles.push_back( dashNode.getLODNode().getNodeId().getId( )); + for( const livre::NodeId& nodeId: selectVisibles.getVisibles( )) + visibles.push_back( nodeId.getId( )); std::sort( visibles.begin(), visibles.end( )); return visibles; diff --git a/tests/pipeline/pipeline.cpp b/tests/pipeline/pipeline.cpp index 9cf33c1f..abd2adaa 100644 --- a/tests/pipeline/pipeline.cpp +++ b/tests/pipeline/pipeline.cpp @@ -26,8 +26,7 @@ #include #include #include -#include -#include +#include #include @@ -73,18 +72,12 @@ class TestFilter : public livre::Filter livre::DataInfos getInputDataInfos() const final { - return - { - { "TestInputData", livre::getType< InputData >( )} - }; + return {{ "TestInputData", livre::getType< InputData >( ) }}; } livre::DataInfos getOutputDataInfos() const final { - return - { - { "TestOutputData", livre::getType< OutputData >( )} - }; + return {{ "TestOutputData", livre::getType< OutputData >( ) }}; } }; @@ -105,19 +98,13 @@ class ConvertFilter : public livre::Filter livre::DataInfos getInputDataInfos() const final { - return - { - { "ConvertInputData", livre::getType< OutputData >( )} - }; + return {{ "ConvertInputData", livre::getType< OutputData >( ) }}; } livre::DataInfos getOutputDataInfos() const final { - return - { - { "ConvertOutputData", livre::getType< InputData >( )} - }; + return {{ "ConvertOutputData", livre::getType< InputData >( )}}; } }; @@ -128,12 +115,11 @@ BOOST_AUTO_TEST_CASE( testFilterNoInput ) livre::PipeFilterT< TestFilter > pipeFilter( "Producer" ); // Execute will fail because there are no inputs where data is retrieved - BOOST_CHECK_EXCEPTION( pipeFilter.execute(), std::runtime_error, check_error ); + BOOST_CHECK_THROW( pipeFilter.execute(), std::logic_error ); const livre::UniqueFutureMap portFutures( pipeFilter.getPostconditions( )); // Results of the filter will be empty. - BOOST_CHECK_EXCEPTION( portFutures.get< OutputData >( "TestOutputData" ), - std::runtime_error, check_error ); + BOOST_CHECK_THROW( portFutures.get< OutputData >( "TestOutputData" ), std::runtime_error ); } BOOST_AUTO_TEST_CASE( testFilterWithInput ) @@ -156,12 +142,11 @@ BOOST_AUTO_TEST_CASE( testSetAndGetWrongParameters ) livre::PipeFilterT< TestFilter > pipeFilter( "Producer" ); pipeFilter.getPromise( "TestInputData" ).set( InputData()); - BOOST_CHECK_EXCEPTION( pipeFilter.getPromise( "InputData" ).set( OutputData( 0 )), - std::runtime_error, check_error ); + BOOST_CHECK_THROW( pipeFilter.getPromise( "InputData" ).set( OutputData( 0 )), + std::runtime_error ); pipeFilter.execute(); const livre::UniqueFutureMap portFutures( pipeFilter.getPostconditions()); - BOOST_CHECK_EXCEPTION( portFutures.get( "TestOutputData" ), - std::runtime_error, check_error ); + BOOST_CHECK_THROW( portFutures.get( "TestOutputData" ), std::runtime_error ); } BOOST_AUTO_TEST_CASE( testInvalidConnection ) @@ -169,10 +154,8 @@ BOOST_AUTO_TEST_CASE( testInvalidConnection ) livre::PipeFilterT< TestFilter > pipeFilter1( "Producer" ); livre::PipeFilterT< TestFilter > pipeFilter2( "Consumer" ); - BOOST_CHECK_EXCEPTION( pipeFilter1.connect( "TestOutputData", - pipeFilter2, - "Helloworld" ), - std::runtime_error, check_error ); + BOOST_CHECK_THROW( pipeFilter1.connect( "TestOutputData", pipeFilter2, "NotExistingConnection" ), + std::runtime_error ); } BOOST_AUTO_TEST_CASE( testConnection ) @@ -253,7 +236,7 @@ BOOST_AUTO_TEST_CASE( testAsynchronousPipeline ) livre::Pipeline pipeline = createPipeline( inputValue, 1 ); livre::SimpleExecutor executor( 2 ); - const livre::FutureMap pipelineFutures( pipeline.schedule( executor )); + pipeline.schedule( executor ); const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); @@ -270,7 +253,7 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) livre::Pipeline pipeline = createPipeline( inputValue, convertFilterCount ); livre::SimpleExecutor executor( 2 ); - const livre::FutureMap pipelineFutures( pipeline.schedule( executor )); + pipeline.schedule( executor ); const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); const livre::UniqueFutureMap portFutures( pipeOutput.getPostconditions( )); const OutputData& outputData = portFutures.get< OutputData >( "TestOutputData" ); @@ -286,7 +269,6 @@ BOOST_AUTO_TEST_CASE( testOneToManyManyToOnePipeline ) livre::SimpleExecutor executor( 8 ); const livre::Futures& futures = pipeline.schedule( executor ); const livre::Executable& pipeOutput = pipeline.getExecutable( "Consumer" ); - const livre::UniqueFutureMap portFutures1( pipeOutput.getPostconditions( )); const OutputData& outputData1 = portFutures1.get< OutputData >( "TestOutputData" ); BOOST_CHECK_EQUAL( outputData1.thanksForAllTheFish, 1761 ); @@ -317,25 +299,22 @@ BOOST_AUTO_TEST_CASE( testPromiseFuture ) BOOST_CHECK( future1 == future2 ); // Promise only be set with the right type - BOOST_CHECK_EXCEPTION( promise.set( 12.0f );, - std::runtime_error, check_error ); + BOOST_CHECK_THROW( promise.set( 12.0f ), std::runtime_error ); promise.set( 42u ); BOOST_CHECK_EQUAL( future1.get< uint32_t >(), 42u ); BOOST_CHECK_EQUAL( future2.get< uint32_t >(), 42u ); // Promise only can be set once - BOOST_CHECK_EXCEPTION( promise.set( 42u );, - std::runtime_error, check_error ); + BOOST_CHECK_THROW( promise.set( 42u ), std::runtime_error ); promise.reset(); livre::Future future3 = promise.getFuture(); BOOST_CHECK( future1 != future3 ); - BOOST_CHECK_EQUAL( future1.get< uint32_t >(), 42u ); // Promise is set with explicit conversion promise.set< uint32_t >( 43.0f ); - + BOOST_CHECK_EQUAL( future1.get< uint32_t >(), 42u ); BOOST_CHECK_EQUAL( future3.get< uint32_t >(), 43u ); } @@ -350,7 +329,7 @@ BOOST_AUTO_TEST_CASE( testFutureMaps ) livre::Futures nonUniqueFutures = { uniqueFutures.front(), uniqueFutures.front() }; - BOOST_CHECK_EXCEPTION( const livre::UniqueFutureMap portFuturesNonUnique( nonUniqueFutures ), - std::runtime_error, check_error ); + BOOST_CHECK_THROW( const livre::UniqueFutureMap portFuturesNonUnique( nonUniqueFutures ), + std::logic_error ); const livre::FutureMap portFutures2( nonUniqueFutures ); } From 2b1ea97384417e8861910bb3333d6d222ab0ef65 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Fri, 13 May 2016 13:44:59 +0200 Subject: [PATCH 13/17] Renderer interface uses NodeIds for rendering --- livre/lib/pipeline/RenderFilter.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/livre/lib/pipeline/RenderFilter.cpp b/livre/lib/pipeline/RenderFilter.cpp index 2bedc903..e01bed1a 100644 --- a/livre/lib/pipeline/RenderFilter.cpp +++ b/livre/lib/pipeline/RenderFilter.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include @@ -39,7 +38,7 @@ struct RenderFilter::Impl void execute( const FutureMap& input, PromiseMap&) const { - RenderBricks renderBricks; + NodeIds renderBricks; for( const auto& cacheObjects: input.getFutures( "CacheObjects" )) for( const auto& cacheObject: cacheObjects.get< ConstCacheObjects >( )) { @@ -47,9 +46,7 @@ struct RenderFilter::Impl std::static_pointer_cast< const TextureObject >( cacheObject ); - renderBricks.emplace_back( - _dataSource.getNode( NodeId( texture->getId( ))), - texture->getTextureState( )); + renderBricks.emplace_back( texture->getId( )); } const auto& frustums = input.get< Frustum >( "Frustum" ); From dc26b7e45b237ab69ea7c1ea6b76e33aec0018b4 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Wed, 25 May 2016 16:19:35 +0200 Subject: [PATCH 14/17] Minor changes for thread count --- livre/eq/Window.cpp | 2 +- livre/lib/pipeline/RenderPipeline.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/livre/eq/Window.cpp b/livre/eq/Window.cpp index 73660c9f..e4efa467 100644 --- a/livre/eq/Window.cpp +++ b/livre/eq/Window.cpp @@ -72,7 +72,7 @@ struct Window::Impl _textureCache.reset( new TextureCache( node->getTextureDataCache(), maxGpuMemory * LB_1MB, GL_LUMINANCE8 )); - const size_t computeThreads = 2; + const size_t computeThreads = 4; const size_t uploadThreads = 4; _renderPipeline.reset( new RenderPipeline( *_textureCache, computeThreads, diff --git a/livre/lib/pipeline/RenderPipeline.cpp b/livre/lib/pipeline/RenderPipeline.cpp index b6896bfe..45116cd1 100644 --- a/livre/lib/pipeline/RenderPipeline.cpp +++ b/livre/lib/pipeline/RenderPipeline.cpp @@ -48,7 +48,7 @@ struct RenderPipeline::Impl void createAndConnectUploaders( Pipeline& uploadPipeline, PipeFilter& visibleSetGenerator, - PipeFilter& output ) const + PipeFilter& output ) const { for( size_t i = 0; i < _nUploadThreads; ++i ) { From d6d544f214447958916327da8cd7a024225f4388 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Wed, 25 May 2016 16:55:55 +0200 Subject: [PATCH 15/17] Fix naming the types --- livre/core/pipeline/FuturePromise.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/livre/core/pipeline/FuturePromise.cpp b/livre/core/pipeline/FuturePromise.cpp index 845ee2e8..a00d0f09 100644 --- a/livre/core/pipeline/FuturePromise.cpp +++ b/livre/core/pipeline/FuturePromise.cpp @@ -26,13 +26,13 @@ namespace livre { -typedef boost::shared_future< PortDataPtr > ConstPortDataFuture; -typedef boost::promise< PortDataPtr > ConstPortDataPromise; -typedef std::vector< ConstPortDataFuture > ConstPortDataFutures; +typedef boost::shared_future< PortDataPtr > PortDataFuture; +typedef boost::promise< PortDataPtr > PortDataPromise; +typedef std::vector< PortDataFuture > PortDataFutures; struct Future::Impl { - Impl( const ConstPortDataFuture& future, + Impl( const PortDataFuture& future, const std::string& name, const servus::uint128_t& uuid ) : _name( name ) @@ -69,7 +69,7 @@ struct Future::Impl } std::string _name; - mutable ConstPortDataFuture _future; + mutable PortDataFuture _future; servus::uint128_t _uuid; }; @@ -121,7 +121,7 @@ struct Promise::Impl { } - ConstPortDataPromise promise; + PortDataPromise promise; _promise.swap( promise ); _uuid = servus::make_UUID(); _futureImpl->_future = _promise.get_future(); @@ -138,7 +138,7 @@ struct Promise::Impl {} } - ConstPortDataPromise _promise; + PortDataPromise _promise; const DataInfo _dataInfo; servus::uint128_t _uuid; std::shared_ptr< Future::Impl > _futureImpl; @@ -235,7 +235,7 @@ void waitForAny( const Futures& futures ) if( futures.empty( )) return; - ConstPortDataFutures boostFutures; + PortDataFutures boostFutures; boostFutures.reserve( futures.size( )); for( const auto& future: futures ) boostFutures.push_back( future._impl->_future ); From e225dbcb8c36b8d68489311ffe4d141ae95fa2a9 Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Thu, 26 May 2016 17:11:51 +0200 Subject: [PATCH 16/17] Fixes according to comments --- livre/core/pipeline/Executable.h | 5 ++- livre/core/pipeline/Executor.h | 4 +- livre/core/pipeline/Filter.h | 7 +-- livre/core/pipeline/FutureMap.cpp | 1 - livre/core/pipeline/FutureMap.h | 43 ++++++++++--------- livre/core/pipeline/FuturePromise.h | 13 +++--- livre/core/pipeline/InputPort.h | 17 ++++---- livre/core/pipeline/OutputPort.h | 17 ++++---- livre/core/pipeline/PipeFilter.h | 17 ++++---- livre/core/pipeline/Pipeline.h | 16 +++---- livre/core/pipeline/PromiseMap.h | 15 ++++--- livre/core/pipeline/SimpleExecutor.h | 11 ++--- livre/core/pipeline/Workers.h | 11 ++--- livre/core/render/SelectVisibles.h | 3 +- livre/eq/Channel.cpp | 2 +- .../pipeline/RenderingSetGeneratorFilter.cpp | 4 +- .../pipeline/RenderingSetGeneratorFilter.h | 2 +- .../pipeline/VisibleSetGeneratorFilter.cpp | 2 +- .../lib/pipeline/VisibleSetGeneratorFilter.h | 2 +- 19 files changed, 99 insertions(+), 93 deletions(-) diff --git a/livre/core/pipeline/Executable.h b/livre/core/pipeline/Executable.h index f60c584f..8121b37d 100644 --- a/livre/core/pipeline/Executable.h +++ b/livre/core/pipeline/Executable.h @@ -20,6 +20,7 @@ #ifndef _Executable_h_ #define _Executable_h_ +#include #include #include #include @@ -45,7 +46,7 @@ class Executable * @param executor schedules the executable * @return the post conditions */ - Futures schedule( Executor& executor ); + LIVRECORE_API Futures schedule( Executor& executor ); /** * @return the output conditions for getting the outputs of the executable. The post @@ -64,7 +65,7 @@ class Executable * Resets the executable by setting all pre and post conditions to an clean state * ( The futures are not ready ) */ - virtual void reset() {} + LIVRECORE_API virtual void reset() {} /** * @return returns a copy diff --git a/livre/core/pipeline/Executor.h b/livre/core/pipeline/Executor.h index dd6b8469..497de0e7 100644 --- a/livre/core/pipeline/Executor.h +++ b/livre/core/pipeline/Executor.h @@ -36,7 +36,7 @@ class Executor { public: - virtual ~Executor() {} + LIVRECORE_API virtual ~Executor() {} /** * Schedules the executables for execution. The deriving class should implement a @@ -52,7 +52,7 @@ class Executor /** * Clears the executor ( i.e : Implementation can empty the work queue ) */ - virtual void clear() {} + LIVRECORE_API virtual void clear() {} }; diff --git a/livre/core/pipeline/Filter.h b/livre/core/pipeline/Filter.h index 0ebfe01d..98c8466f 100644 --- a/livre/core/pipeline/Filter.h +++ b/livre/core/pipeline/Filter.h @@ -20,6 +20,7 @@ #ifndef _Filter_h_ #define _Filter_h_ +#include #include #include #include @@ -51,16 +52,16 @@ class Filter * communication. In execution time using these names and types, * data can be set. */ - virtual DataInfos getInputDataInfos() const { return DataInfos(); } + LIVRECORE_API virtual DataInfos getInputDataInfos() const { return DataInfos(); } /** * @return map for the name and data types for the filter * communication. In execution time using these names and types, * data can be retrieved. */ - virtual DataInfos getOutputDataInfos() const { return DataInfos(); } + LIVRECORE_API virtual DataInfos getOutputDataInfos() const { return DataInfos(); } - virtual ~Filter() {} + LIVRECORE_API virtual ~Filter() {} }; } diff --git a/livre/core/pipeline/FutureMap.cpp b/livre/core/pipeline/FutureMap.cpp index 810eda5a..1f6d2bfc 100644 --- a/livre/core/pipeline/FutureMap.cpp +++ b/livre/core/pipeline/FutureMap.cpp @@ -150,7 +150,6 @@ struct FutureMap::Impl: public FutureMapImpl { for( const auto& future: futures ) addFuture( future.getName(), future ); - } }; diff --git a/livre/core/pipeline/FutureMap.h b/livre/core/pipeline/FutureMap.h index b328c7cb..799119d1 100644 --- a/livre/core/pipeline/FutureMap.h +++ b/livre/core/pipeline/FutureMap.h @@ -20,6 +20,7 @@ #ifndef _FutureMap_h_ #define _FutureMap_h_ +#include #include #include @@ -30,8 +31,8 @@ namespace livre * FutureMap is a wrapper class to query the map of ( name, future ) * futures with for data and state. In the map there can be multiple futures * with the same name. i.e. if there are multiple futures with the same name - * "x", the get() function will block until all the futures with name "x" are - * ready and get() will return a vector of results. + * "FutureName", the get() function will block until all the futures with + * name "FutureName" are ready and get() will return a vector of results. * * Filters has named ports to communicate with other filters and those ports * are communicated through promise/future couples. The futures are named @@ -47,8 +48,8 @@ class FutureMap * @param futures is the list of futures * future names are used for name-future association. */ - explicit FutureMap( const Futures& futures ); - ~FutureMap(); + LIVRECORE_API explicit FutureMap( const Futures& futures ); + LIVRECORE_API ~FutureMap(); /** * Gets a copy of value(s) with the given type T. Until all @@ -97,12 +98,12 @@ class FutureMap * @param name of the future. * @return the futures with the given name */ - Futures getFutures( const std::string& name ) const; + LIVRECORE_API Futures getFutures( const std::string& name ) const; /** * @return the futures */ - Futures getFutures() const; + LIVRECORE_API Futures getFutures() const; /** * Queries if futures are ready with a given name @@ -111,7 +112,7 @@ class FutureMap * @throw std::logic_error when there is no future associated with the * given name */ - bool isReady( const std::string& name ) const; + LIVRECORE_API bool isReady( const std::string& name ) const; /** * Queries if all futures are ready @@ -119,7 +120,7 @@ class FutureMap * @throw std::runtime_error when there is no future associated with the * given name */ - bool isReady() const; + LIVRECORE_API bool isReady() const; /** * Waits all futures associated with a given name @@ -127,14 +128,14 @@ class FutureMap * @throw std::logic_error when there is no future associated with the * given name */ - void wait( const std::string& name ) const; + LIVRECORE_API void wait( const std::string& name ) const; /** * Waits all futures * @throw std::runtime_error when there is no future associated with the * given name */ - void wait() const; + LIVRECORE_API void wait() const; /** * Waits all futures associated with a given name. @@ -142,14 +143,14 @@ class FutureMap * @throw std::logic_error when there is no future associated with the * given name */ - void waitForAny( const std::string& name ) const; + LIVRECORE_API void waitForAny( const std::string& name ) const; /** * Waits all futures. * @throw std::logic_error when there is no future associated with the * given name */ - void waitForAny() const; + LIVRECORE_API void waitForAny() const; private: @@ -170,8 +171,8 @@ class UniqueFutureMap * @param futures the list of futures. * @throw std::logic_error when futures are not unique in names */ - explicit UniqueFutureMap( const Futures& futures ); - ~UniqueFutureMap(); + LIVRECORE_API explicit UniqueFutureMap( const Futures& futures ); + LIVRECORE_API ~UniqueFutureMap(); /** * Gets the copy of value(s) with the given type T. If input @@ -196,12 +197,12 @@ class UniqueFutureMap * @throw std::logic_error when there is no future associated with the * given name */ - Future getFuture( const std::string& name ) const; + LIVRECORE_API Future getFuture( const std::string& name ) const; /** * @return all the futures. */ - Futures getFutures() const; + LIVRECORE_API Futures getFutures() const; /** * Queries if future is ready for a given name @@ -210,7 +211,7 @@ class UniqueFutureMap * @throw std::logic_error when there is no future associated with the * given name */ - bool isReady( const std::string& name ) const; + LIVRECORE_API bool isReady( const std::string& name ) const; /** * Queries if future is ready for a given name @@ -218,7 +219,7 @@ class UniqueFutureMap * @throw std::logic_error when there is no future associated with the * given name */ - bool isReady() const; + LIVRECORE_API bool isReady() const; /** * Waits for the future associated with a given name @@ -226,19 +227,19 @@ class UniqueFutureMap * @throw std::logic_error when there is no future associated with the * given name */ - void wait( const std::string& name ) const; + LIVRECORE_API void wait( const std::string& name ) const; /** * Waits for all the futures * @throw std::logic_error when there is no future associated with the * given name */ - void wait() const; + LIVRECORE_API void wait() const; /** * Waits for any future to be ready. */ - void waitForAny() const; + LIVRECORE_API void waitForAny() const; private: diff --git a/livre/core/pipeline/FuturePromise.h b/livre/core/pipeline/FuturePromise.h index 4d421c6b..3af12381 100644 --- a/livre/core/pipeline/FuturePromise.h +++ b/livre/core/pipeline/FuturePromise.h @@ -20,6 +20,7 @@ #ifndef _Promise_h_ #define _Promise_h_ +#include #include #include @@ -37,18 +38,18 @@ class Promise /** * @param dataInfo is the name and type information for the data. */ - Promise( const DataInfo& dataInfo ); - ~Promise(); + LIVRECORE_API Promise( const DataInfo& dataInfo ); + LIVRECORE_API ~Promise(); /** * @return the name of the connection */ - std::type_index getDataType() const; + LIVRECORE_API std::type_index getDataType() const; /** * @return the name of the connection */ - std::string getName() const; + LIVRECORE_API std::string getName() const; /** * Sets the port with the value. @@ -73,7 +74,7 @@ class Promise * If such behaviour is needed Future has a Future( const Promise& ) * consttructor */ - Future getFuture() const; + LIVRECORE_API Future getFuture() const; /** * @resets the promise.( If related future is constructed using @@ -82,7 +83,7 @@ class Promise * The behavior of the function is undefined when multiple threads * execute query/get from future. */ - void reset(); + LIVRECORE_API void reset(); private: diff --git a/livre/core/pipeline/InputPort.h b/livre/core/pipeline/InputPort.h index b21a7868..906d34df 100644 --- a/livre/core/pipeline/InputPort.h +++ b/livre/core/pipeline/InputPort.h @@ -20,6 +20,7 @@ #ifndef _InputPort_h_ #define _InputPort_h_ +#include #include namespace livre @@ -35,34 +36,34 @@ class InputPort /** * @param dataInfo is the name and type information for the data. */ - explicit InputPort( const DataInfo& dataInfo ); - ~InputPort(); + LIVRECORE_API explicit InputPort( const DataInfo& dataInfo ); + LIVRECORE_API ~InputPort(); /** * @return name of the port */ - std::string getName() const; + LIVRECORE_API std::string getName() const; /** * @return data type of the port */ - std::type_index getDataType() const; + LIVRECORE_API std::type_index getDataType() const; /** * @return the number of the connected outputs to the port */ - size_t getSize() const; + LIVRECORE_API size_t getSize() const; /** * @return Return all the futures this port has. */ - const Futures& getFutures() const; + LIVRECORE_API const Futures& getFutures() const; /** * Connects an output port to input port * @param port is the connected output port. */ - void connect( const OutputPort& port ); + LIVRECORE_API void connect( const OutputPort& port ); /** * Disconnects an output port from input port @@ -70,7 +71,7 @@ class InputPort * @return true if output port is found as a connection and removed * for the connections */ - bool disconnect( const OutputPort& port ); + LIVRECORE_API bool disconnect( const OutputPort& port ); private: diff --git a/livre/core/pipeline/OutputPort.h b/livre/core/pipeline/OutputPort.h index 7252ba63..192cf984 100644 --- a/livre/core/pipeline/OutputPort.h +++ b/livre/core/pipeline/OutputPort.h @@ -20,6 +20,7 @@ #ifndef _OutputPort_h_ #define _OutputPort_h_ +#include #include namespace livre @@ -30,40 +31,38 @@ namespace livre */ class OutputPort { - public: - /** * @param dataInfo is the name and type information for the data. */ - OutputPort( const DataInfo& dataInfo ); - ~OutputPort(); + LIVRECORE_API explicit OutputPort( const DataInfo& dataInfo ); + LIVRECORE_API ~OutputPort(); /** * @return name of the port */ - std::string getName() const; + LIVRECORE_API std::string getName() const; /** * @return data type of the port */ - std::type_index getDataType() const; + LIVRECORE_API std::type_index getDataType() const; /** * @return the promise, that data can be written to */ - Promise getPromise() const; + LIVRECORE_API Promise getPromise() const; /** * Connects an output port to input port * @param port input port */ - void connect( InputPort& port ); + LIVRECORE_API void connect( InputPort& port ); /** * Resets the promise/future */ - void reset(); + LIVRECORE_API void reset(); private: diff --git a/livre/core/pipeline/PipeFilter.h b/livre/core/pipeline/PipeFilter.h index dfdf9956..fadb82b1 100644 --- a/livre/core/pipeline/PipeFilter.h +++ b/livre/core/pipeline/PipeFilter.h @@ -20,6 +20,7 @@ #ifndef _PipeFilter_h_ #define _PipeFilter_h_ +#include #include #include @@ -36,12 +37,12 @@ class PipeFilter : public Executable { public: - ~PipeFilter(); + LIVRECORE_API ~PipeFilter(); /** * @return the unique name of the filter. */ - std::string getName() const; + LIVRECORE_API std::string getName() const; /** * Connects to given pipe filter with the given port names. Both filters @@ -51,7 +52,7 @@ class PipeFilter : public Executable * @param dstPortName connection port name. * @throw std::runtime_error if connection can not be established */ - void connect( const std::string& srcPortName, + LIVRECORE_API void connect( const std::string& srcPortName, PipeFilter& dst, const std::string& dstPortName ); @@ -62,27 +63,27 @@ class PipeFilter : public Executable * @throw std::logic_error if there is already a connection if there is * no input port or it is a notification port. */ - Promise getPromise( const std::string& portName ); + LIVRECORE_API Promise getPromise( const std::string& portName ); /** * @copydoc Executable::execute */ - void execute() final; + LIVRECORE_API void execute() final; /** * @copydoc Executable::getPostconditions */ - Futures getPostconditions() const final; + LIVRECORE_API Futures getPostconditions() const final; /** * @copydoc Executable::getPreconditions */ - Futures getPreconditions() const final; + LIVRECORE_API Futures getPreconditions() const final; /** * @copydoc Executable::reset */ - void reset() final; + LIVRECORE_API void reset() final; protected: diff --git a/livre/core/pipeline/Pipeline.h b/livre/core/pipeline/Pipeline.h index a54f62b5..04b1e9c2 100644 --- a/livre/core/pipeline/Pipeline.h +++ b/livre/core/pipeline/Pipeline.h @@ -20,6 +20,7 @@ #ifndef _Pipeline_h_ #define _Pipeline_h_ +#include #include #include #include @@ -33,13 +34,12 @@ namespace livre */ class Pipeline : public Executable { - public: typedef std::unique_ptr< Executable > UniqueExecutablePtr; - Pipeline(); - ~Pipeline(); + LIVRECORE_API Pipeline(); + LIVRECORE_API ~Pipeline(); /** * Adds a pipeline to be executed. @@ -83,27 +83,27 @@ class Pipeline : public Executable * @return the executable * @throw std::runtime_error if a pipe filter or pipeline does not exist */ - const Executable& getExecutable( const std::string& name ) const; + LIVRECORE_API const Executable& getExecutable( const std::string& name ) const; /** * @copydoc Executable::execute */ - void execute() final; + LIVRECORE_API void execute() final; /** * @copydoc Executable::getPostconditions */ - Futures getPostconditions() const final; + LIVRECORE_API Futures getPostconditions() const final; /** * @copydoc Executable::getPreconditions */ - Futures getPreconditions() const final; + LIVRECORE_API Futures getPreconditions() const final; /** * @copydoc Executable::reset */ - void reset() final; + LIVRECORE_API void reset() final; private: diff --git a/livre/core/pipeline/PromiseMap.h b/livre/core/pipeline/PromiseMap.h index 3b320d59..33dc58a0 100644 --- a/livre/core/pipeline/PromiseMap.h +++ b/livre/core/pipeline/PromiseMap.h @@ -20,6 +20,7 @@ #ifndef _PromiseMap_h_ #define _PromiseMap_h_ +#include #include #include @@ -35,14 +36,14 @@ class PromiseMap public: - explicit PromiseMap( const Promises& promises ); - ~PromiseMap(); + LIVRECORE_API explicit PromiseMap( const Promises& promises ); + LIVRECORE_API ~PromiseMap(); /** * @param name of the promise * @return the promise related to the port name. */ - Promise getPromise( const std::string& name ) const; + LIVRECORE_API Promise getPromise( const std::string& name ) const; /** * Sets the port with the value. @@ -65,14 +66,14 @@ class PromiseMap * @throw std::logic_error when there is no promise associated with the * given name */ - void flush( const std::string& name ) const; + LIVRECORE_API void flush( const std::string& name ) const; /** * Writes empty values to promises which are not set already. * @throw std::logic_error when there is no promise associated with the * given name */ - void flush() const; + LIVRECORE_API void flush() const; /** * Resets the promise after they are done. @@ -80,14 +81,14 @@ class PromiseMap * @throw std::logic_error when there is no promise associated with the * given name */ - void reset( const std::string& name ) const; + LIVRECORE_API void reset( const std::string& name ) const; /** * Resets the promises after they are done. * @throw std::logic_error when there is no promise associated with the * given name */ - void reset() const; + LIVRECORE_API void reset() const; private: diff --git a/livre/core/pipeline/SimpleExecutor.h b/livre/core/pipeline/SimpleExecutor.h index 7f6c2e7a..ec4a03f4 100644 --- a/livre/core/pipeline/SimpleExecutor.h +++ b/livre/core/pipeline/SimpleExecutor.h @@ -20,6 +20,7 @@ #ifndef _SimpleExecutor_h_ #define _SimpleExecutor_h_ +#include #include #include @@ -43,20 +44,20 @@ class SimpleExecutor : public Executor * @param glContext if a gl context is provided, a new context will be created and * the worker threads will share the context with the given context */ - SimpleExecutor( size_t threadCount, - ConstGLContextPtr glContext = ConstGLContextPtr( )); + LIVRECORE_API SimpleExecutor( size_t threadCount, + ConstGLContextPtr glContext = ConstGLContextPtr( )); - virtual ~SimpleExecutor(); + LIVRECORE_API virtual ~SimpleExecutor(); /** * @copydoc Executor::schedule */ - void schedule( ExecutablePtr executable ) final; + LIVRECORE_API void schedule( ExecutablePtr executable ) final; /** * @copydoc Executor::clear */ - void clear() final; + LIVRECORE_API void clear() final; private: diff --git a/livre/core/pipeline/Workers.h b/livre/core/pipeline/Workers.h index 33494553..294e19db 100644 --- a/livre/core/pipeline/Workers.h +++ b/livre/core/pipeline/Workers.h @@ -20,6 +20,7 @@ #ifndef _Workers_h_ #define _Workers_h_ +#include #include namespace livre @@ -38,21 +39,21 @@ class Workers * @param glContext if given, the threads can share this * context. */ - Workers( size_t nThreads = 4, - ConstGLContextPtr glContext = ConstGLContextPtr( )); - ~Workers(); + LIVRECORE_API Workers( size_t nThreads = 4, + ConstGLContextPtr glContext = ConstGLContextPtr( )); + LIVRECORE_API ~Workers(); /** * Submitted executable is scheduled to the execution * queue. * @param executable is executed by thread pool. */ - void schedule( ExecutablePtr executable ); + LIVRECORE_API void schedule( ExecutablePtr executable ); /** * @return the size of thread pool. */ - size_t getSize() const; + LIVRECORE_API size_t getSize() const; private: diff --git a/livre/core/render/SelectVisibles.h b/livre/core/render/SelectVisibles.h index d5d7ab87..f20fb213 100644 --- a/livre/core/render/SelectVisibles.h +++ b/livre/core/render/SelectVisibles.h @@ -60,8 +60,7 @@ class SelectVisibles : public DataSourceVisitor void visit( const LODNode& lodNode, VisitState& state ) final { const Boxf& worldBox = lodNode.getWorldBox(); - const bool isInFrustum = _frustum.boxInFrustum( worldBox ); - if( !isInFrustum ) + if( !_frustum.boxInFrustum( worldBox ) ) { state.setVisitChild( false ); return; diff --git a/livre/eq/Channel.cpp b/livre/eq/Channel.cpp index b06551cf..6e85415e 100644 --- a/livre/eq/Channel.cpp +++ b/livre/eq/Channel.cpp @@ -67,7 +67,7 @@ struct RedrawFilter : public Filter public: - RedrawFilter( Channel* channel ) + explicit RedrawFilter( Channel* channel ) : _channel( channel ) {} diff --git a/livre/lib/pipeline/RenderingSetGeneratorFilter.cpp b/livre/lib/pipeline/RenderingSetGeneratorFilter.cpp index 2f3ee37a..12039cb0 100644 --- a/livre/lib/pipeline/RenderingSetGeneratorFilter.cpp +++ b/livre/lib/pipeline/RenderingSetGeneratorFilter.cpp @@ -30,7 +30,7 @@ namespace livre struct RenderingSetGenerator { - RenderingSetGenerator( const TextureCache& textureCache ) + explicit RenderingSetGenerator( const TextureCache& textureCache ) : _textureCache( textureCache ) {} @@ -110,7 +110,7 @@ struct RenderingSetGenerator struct RenderingSetGeneratorFilter::Impl { - Impl( const TextureCache& cache ) + explicit Impl( const TextureCache& cache ) : _cache( cache ) {} diff --git a/livre/lib/pipeline/RenderingSetGeneratorFilter.h b/livre/lib/pipeline/RenderingSetGeneratorFilter.h index 9ed53a15..98d0b9ac 100644 --- a/livre/lib/pipeline/RenderingSetGeneratorFilter.h +++ b/livre/lib/pipeline/RenderingSetGeneratorFilter.h @@ -40,7 +40,7 @@ class RenderingSetGeneratorFilter : public Filter * Constructor * @param textureCache the texture cache */ - RenderingSetGeneratorFilter( const TextureCache& textureCache ); + explicit RenderingSetGeneratorFilter( const TextureCache& textureCache ); ~RenderingSetGeneratorFilter(); /** diff --git a/livre/lib/pipeline/VisibleSetGeneratorFilter.cpp b/livre/lib/pipeline/VisibleSetGeneratorFilter.cpp index 10c022ef..81902175 100644 --- a/livre/lib/pipeline/VisibleSetGeneratorFilter.cpp +++ b/livre/lib/pipeline/VisibleSetGeneratorFilter.cpp @@ -31,7 +31,7 @@ namespace livre struct VisibleSetGeneratorFilter::Impl { - Impl( const DataSource& dataSource ) + explicit Impl( const DataSource& dataSource ) : _dataSource( dataSource ) {} diff --git a/livre/lib/pipeline/VisibleSetGeneratorFilter.h b/livre/lib/pipeline/VisibleSetGeneratorFilter.h index 00c30dc1..39e6837e 100644 --- a/livre/lib/pipeline/VisibleSetGeneratorFilter.h +++ b/livre/lib/pipeline/VisibleSetGeneratorFilter.h @@ -41,7 +41,7 @@ class VisibleSetGeneratorFilter : public Filter * Constructor * @param dataSource the data source */ - VisibleSetGeneratorFilter( const DataSource& dataSource ); + explicit VisibleSetGeneratorFilter( const DataSource& dataSource ); ~VisibleSetGeneratorFilter(); /** From 234a4e446b0a5f9165da9516c2b8d625a6f7720e Mon Sep 17 00:00:00 2001 From: Ahmet Bilgili Date: Fri, 27 May 2016 10:15:12 +0200 Subject: [PATCH 17/17] Changelog is updated --- doc/Changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/Changelog.md b/doc/Changelog.md index 850b8530..0a9207b6 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -3,6 +3,10 @@ Changelog {#Changelog} # master {#master} +* [#256](https://github.com/BlueBrain/Livre/pull/256): + A new architecture for loading data, executing rendering + is implemented. There are preformance gains 2x to 10x + in frame rate and data upload. * [#291](https://github.com/BlueBrain/Livre/pull/291): Livre uses OpenGL 4.2 for rendering ( removed copying-from-to CPU memory )