From 16b0f63c5f0841c9de7fbf6dd334fa6a22a8cd42 Mon Sep 17 00:00:00 2001 From: Sebastian Eibl <sebastian.eibl@fau.de> Date: Mon, 3 Jun 2019 13:02:31 +0200 Subject: [PATCH] added reduction to Timer --- src/core/timing/Timer.h | 156 ++++++++++++++++++------ tests/core/CMakeLists.txt | 3 + tests/core/timing/ParallelTimerTest.cpp | 79 ++++++++++++ 3 files changed, 198 insertions(+), 40 deletions(-) create mode 100644 tests/core/timing/ParallelTimerTest.cpp diff --git a/src/core/timing/Timer.h b/src/core/timing/Timer.h index 0352ebf59..f25602bfa 100644 --- a/src/core/timing/Timer.h +++ b/src/core/timing/Timer.h @@ -25,10 +25,12 @@ #pragma once #include "CpuPolicy.h" +#include "ReduceType.h" #include "WcPolicy.h" #include "core/DataTypes.h" #include "core/mpi/RecvBuffer.h" +#include "core/mpi/Reduce.h" #include "core/mpi/SendBuffer.h" #include <iomanip> @@ -155,7 +157,7 @@ public: //@} //******************************************************************************************************************* - private: +private: uint_t counter_; //!< Number of performed time measurements. double start_; //!< Start of the current time measurement. @@ -211,14 +213,14 @@ inline Timer<TP>::Timer() template< typename TP> inline Timer<TP>::Timer( uint_t _counter, double _min, double _max, double _total, double _sumOfSquares ) - : counter_ ( _counter ) - , start_ ( 0.0 ) - , end_ ( 0.0 ) - , time_ ( _total ) - , sumOfSquares_( _sumOfSquares ) - , min_ ( _min ) - , max_ ( _max ) - , last_ ( 0.0 ) + : counter_ ( _counter ) + , start_ ( 0.0 ) + , end_ ( 0.0 ) + , time_ ( _total ) + , sumOfSquares_( _sumOfSquares ) + , min_ ( _min ) + , max_ ( _max ) + , last_ ( 0.0 ) { } //********************************************************************************************************************** @@ -455,6 +457,80 @@ inline void Timer<TP>::merge( const Timer<TP> & other ) //********************************************************************************************************************** +//====================================================================================================================== +// +// REDUCTION +// +//====================================================================================================================== + +//********************************************************************************************************************** +/*! Returns a reduced Timer, holding information from all processes + * + * \param timer Timer which should be reduced + * \param rt Specified the method how the reduction is done. See documentation for ReduceType + * \param targetRank the world rank of the target process. Or negative value for an all-reduction + * operation + * + * \return a nonzero shared pointer to a Timer on the process with rank "targetRank" + * and a zero pointer otherwise. For the all-reduction a valid timer is returned on all processes. + **********************************************************************************************************************/ +template< typename TP > +shared_ptr<Timer<TP> > getReduced( Timer<TP>& timer, ReduceType rt, int targetRank ) +{ + WALBERLA_NON_MPI_SECTION() { + return make_shared<Timer<TP> >( timer ); + } + + double val; //value to be reduced + switch (rt) + { + case REDUCE_MIN : + val = timer.min(); + break; + case REDUCE_AVG : + val = timer.average(); + break; + + case REDUCE_MAX : + val = timer.max(); + break; + + case REDUCE_TOTAL: + val = timer.total(); + break; + + default: + WALBERLA_ABORT( "Unknown reduce type" ); + break; + } + + double min; + double max; + double total; + double sumOfSquares; + + if (targetRank >= 0) + { + min = mpi::reduce(val, mpi::MIN, targetRank); + max = mpi::reduce(val, mpi::MAX, targetRank); + total = mpi::reduce(val, mpi::SUM, targetRank); + sumOfSquares = mpi::reduce(val*val, mpi::SUM, targetRank); + } else + { + min = mpi::allReduce(val, mpi::MIN); + max = mpi::allReduce(val, mpi::MAX); + total = mpi::allReduce(val, mpi::SUM); + sumOfSquares = mpi::allReduce(val*val, mpi::SUM); + } + + //uint_t counter, double min, double max, double total, double sumOfSquares + if ( targetRank < 0 || targetRank == MPIManager::instance()->worldRank() ) + return make_shared<Timer<TP> >( mpi::MPIManager::instance()->numProcesses(), min, max, total, sumOfSquares ); + + return nullptr; +} + + //====================================================================================================================== // // OSTREAM OVERLOAD @@ -478,38 +554,38 @@ std::ostream & operator<< ( std::ostream & os, const Timer<TP> & timer ) // //====================================================================================================================== - template< typename T, // Element type of SendBuffer - typename G, // Growth policy of SendBuffer - typename TP > // Element type of vector - mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, const Timer<TP> & t ) - { - buf.addDebugMarker( "ti" ); - buf << t.counter_; - buf << t.start_; - buf << t.end_; - buf << t.time_; - buf << t.sumOfSquares_; - buf << t.min_; - buf << t.max_; - buf << t.last_; - return buf; - } +template< typename T, // Element type of SendBuffer + typename G, // Growth policy of SendBuffer + typename TP > // Element type of vector +mpi::GenericSendBuffer<T,G>& operator<<( mpi::GenericSendBuffer<T,G> & buf, const Timer<TP> & t ) +{ + buf.addDebugMarker( "ti" ); + buf << t.counter_; + buf << t.start_; + buf << t.end_; + buf << t.time_; + buf << t.sumOfSquares_; + buf << t.min_; + buf << t.max_; + buf << t.last_; + return buf; +} - template< typename T, // Element type of RecvBuffer - typename TP > // Element type of vector - mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, Timer<TP> & t ) - { - buf.readDebugMarker( "ti" ); - buf >> t.counter_; - buf >> t.start_; - buf >> t.end_; - buf >> t.time_; - buf >> t.sumOfSquares_; - buf >> t.min_; - buf >> t.max_; - buf >> t.last_; - return buf; - } +template< typename T, // Element type of RecvBuffer + typename TP > // Element type of vector +mpi::GenericRecvBuffer<T>& operator>>( mpi::GenericRecvBuffer<T> & buf, Timer<TP> & t ) +{ + buf.readDebugMarker( "ti" ); + buf >> t.counter_; + buf >> t.start_; + buf >> t.end_; + buf >> t.time_; + buf >> t.sumOfSquares_; + buf >> t.min_; + buf >> t.max_; + buf >> t.last_; + return buf; +} } //namespace timing diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt index 5f7d18a88..185fc8be0 100644 --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -159,6 +159,9 @@ waLBerla_execute_test( NAME SetSelectableObjectTest ) # timing # ########## +waLBerla_compile_test( FILES timing/ParallelTimerTest.cpp ) +waLBerla_execute_test( NAME ParallelTimerTest PROCESSES 2 ) + waLBerla_compile_test( FILES timing/TimerTest.cpp ) waLBerla_execute_test( NAME TimerTest ) diff --git a/tests/core/timing/ParallelTimerTest.cpp b/tests/core/timing/ParallelTimerTest.cpp new file mode 100644 index 000000000..76a4c9001 --- /dev/null +++ b/tests/core/timing/ParallelTimerTest.cpp @@ -0,0 +1,79 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla 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 General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file ParallelTimerTest.cpp +//! \author Sebastian Eibl <sebastian.eibl@web.de> +// +//====================================================================================================================== + + +#include "core/debug/TestSubsystem.h" +#include "core/Environment.h" +#include "core/math/Constants.h" +#include "core/timing/StaticPolicy.h" +#include "core/timing/Timer.h" + +#include <cmath> + +namespace walberla { + +void reductionTest() +{ + using namespace timing; + StaticPolicy::setTime(0.0); + Timer<StaticPolicy> t0; + + t0.start(); + StaticPolicy::setTime(2.0); + t0.end(); + + t0.start(); + StaticPolicy::setTime(6.0); + t0.end(); + + WALBERLA_CHECK_FLOAT_EQUAL( t0.min(), 2.0 ); + WALBERLA_CHECK_FLOAT_EQUAL( t0.max(), 4.0 ); + WALBERLA_CHECK_FLOAT_EQUAL( t0.average(), 3.0 ); + WALBERLA_CHECK_EQUAL( t0.getCounter(), 2 ); + + auto timer_reduced = getReduced(t0, REDUCE_TOTAL, -1); //allreduce + WALBERLA_CHECK_FLOAT_EQUAL( timer_reduced->min(), 6.0 ); + WALBERLA_CHECK_FLOAT_EQUAL( timer_reduced->max(), 6.0 ); + WALBERLA_CHECK_FLOAT_EQUAL( timer_reduced->average(), 6.0 ); + WALBERLA_CHECK_EQUAL( timer_reduced->getCounter(), 2 ); + + timer_reduced = getReduced(t0, REDUCE_TOTAL, 0); + if (mpi::MPIManager::instance()->worldRank() == 0) + { + WALBERLA_CHECK_FLOAT_EQUAL( timer_reduced->min(), 6.0 ); + WALBERLA_CHECK_FLOAT_EQUAL( timer_reduced->max(), 6.0 ); + WALBERLA_CHECK_FLOAT_EQUAL( timer_reduced->average(), 6.0 ); + WALBERLA_CHECK_EQUAL( timer_reduced->getCounter(), 2 ); + } else + { + WALBERLA_CHECK_EQUAL( timer_reduced, nullptr ); + } +} + +} + +int main( int argc, char ** argv ) +{ + walberla::debug::enterTestMode(); + walberla::Environment env(argc, argv); + WALBERLA_UNUSED(env); + + walberla::reductionTest(); +} -- GitLab