diff --git a/eo/src/mpi/eoMpi.cpp b/eo/src/mpi/eoMpi.cpp index f6e3b3c5..9ffc84bd 100644 --- a/eo/src/mpi/eoMpi.cpp +++ b/eo/src/mpi/eoMpi.cpp @@ -6,6 +6,7 @@ namespace eo namespace mpi { bmpi::communicator Node::_comm; + eoTimerStat timerStat; } } diff --git a/eo/src/mpi/eoMpi.h b/eo/src/mpi/eoMpi.h index 480bfbcb..a516b442 100644 --- a/eo/src/mpi/eoMpi.h +++ b/eo/src/mpi/eoMpi.h @@ -7,6 +7,7 @@ # include # include +# include # include # include "eoMpiNode.h" @@ -18,6 +19,8 @@ namespace eo { namespace mpi { + extern eoTimerStat timerStat; + namespace Channel { const int Commands = 0; @@ -70,6 +73,7 @@ namespace eo break; } + timerStat.start("master_wait_for_assignee"); int assignee = assignmentAlgo.get( ); while( assignee <= 0 ) { @@ -85,28 +89,34 @@ namespace eo assignmentAlgo.confirm( wrkRank ); assignee = assignmentAlgo.get( ); } + timerStat.stop("master_wait_for_assignee"); # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Assignee : " << assignee << std::endl; # endif + timerStat.start("master_wait_for_send"); comm.send( assignee, Channel::Commands, Message::Continue ); sendTask( assignee ); + timerStat.stop("master_wait_for_send"); } # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Frees all the idle." << std::endl; # endif // frees all the idle workers + timerStat.start("master_wait_for_idles"); std::vector idles = assignmentAlgo.idles(); for(unsigned int i = 0; i < idles.size(); ++i) { comm.send( idles[i], Channel::Commands, Message::Finish ); } + timerStat.stop("master_wait_for_idles"); # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Waits for all responses." << std::endl; # endif // wait for all responses + timerStat.start("master_wait_for_all_responses"); while( assignmentAlgo.availableWorkers() != totalWorkers ) { bmpi::status status = comm.probe( bmpi::any_source, bmpi::any_tag ); @@ -115,6 +125,7 @@ namespace eo comm.send( wrkRank, Channel::Commands, Message::Finish ); assignmentAlgo.confirm( wrkRank ); } + timerStat.stop("master_wait_for_all_responses"); # ifndef NDEBUG eo::log << "[M" << comm.rank() << "] Leaving master task." << std::endl; @@ -136,7 +147,9 @@ namespace eo # ifndef NDEBUG eo::log << "[W" << comm.rank() << "] Waiting for an order..." << std::endl; # endif + timerStat.start("worker_wait_for_order"); comm.recv( masterRank, Channel::Commands, order ); + timerStat.stop("worker_wait_for_order"); if ( order == Message::Finish ) { # ifndef NDEBUG diff --git a/eo/src/mpi/eoParallelApply.h b/eo/src/mpi/eoParallelApply.h index af0666cc..b89da73e 100644 --- a/eo/src/mpi/eoParallelApply.h +++ b/eo/src/mpi/eoParallelApply.h @@ -82,10 +82,12 @@ namespace eo int recvSize; comm.recv( masterRank, 1, recvSize ); comm.recv( masterRank, 1, tempArray, recvSize ); + timerStat.start("worker_processes"); for( int i = 0; i < recvSize ; ++i ) { func( tempArray[ i ] ); } + timerStat.stop("worker_processes"); comm.send( masterRank, 1, tempArray, recvSize ); } diff --git a/eo/src/utils/eoTimer.h b/eo/src/utils/eoTimer.h new file mode 100644 index 00000000..c97ab5d3 --- /dev/null +++ b/eo/src/utils/eoTimer.h @@ -0,0 +1,145 @@ +# ifndef __TIMER_H__ +# define __TIMER_H__ + +# include +# include + +# include +# include + +# ifdef WITH_MPI +# include +# include +# include +# endif + +// TODO TODOB commenter +class eoTimer +{ + public: + + eoTimer() + { + restart(); + } + + void restart() + { + uuremainder = 0; + usremainder = 0; + wc_start = time(NULL); + getrusage( RUSAGE_SELF, &_start ); + } + + long int usertime() + { + struct rusage _now; + getrusage( RUSAGE_SELF, &_now ); + long int result = _now.ru_utime.tv_sec - _start.ru_utime.tv_sec; + if( _now.ru_utime.tv_sec == _start.ru_utime.tv_sec ) + { + uuremainder += _now.ru_utime.tv_usec - _start.ru_utime.tv_usec; + if( uuremainder > 1000000) + { + ++result; + uuremainder = 0; + } + } + return result; + } + + long int systime() + { + struct rusage _now; + getrusage( RUSAGE_SELF, &_now ); + long int result = _now.ru_stime.tv_sec - _start.ru_stime.tv_sec; + if( _now.ru_stime.tv_sec == _start.ru_stime.tv_sec ) + { + usremainder += _now.ru_stime.tv_usec - _start.ru_stime.tv_usec; + if( usremainder > 1000000) + { + ++result; + usremainder = 0; + } + } + return result; + } + + double wallclock() + { + return std::difftime( std::time(NULL) , wc_start ); + } + + protected: + struct rusage _start; + long int uuremainder; + long int usremainder; + time_t wc_start; +}; + +class eoTimerStat +{ + public: + + struct Stat + { + std::vector utime; + std::vector stime; + std::vector wtime; +#ifdef WITH_MPI + // Gives access to boost serialization + friend class boost::serialization::access; + + /** + * Serializes the statistique in a boost archive (useful for boost::mpi) + */ + template + void serialize( Archive & ar, const unsigned int version ) + { + ar & utime & stime & wtime; + (void) version; // avoid compilation warning + } +# endif + }; + +#ifdef WITH_MPI + // Gives access to boost serialization + friend class boost::serialization::access; + + /** + * Serializes the map of statistics in a boost archive (useful for boost::mpi) + */ + template + void serialize( Archive & ar, const unsigned int version ) + { + ar & _stats; + (void) version; // avoid compilation warning + } +# endif + + void start( const std::string & key ) + { + _timers[ key ].restart(); + } + + void stop( const std::string& key ) + { + Stat & s = _stats[ key ]; + eoTimer & t = _timers[ key ]; + s.utime.push_back( t.usertime() ); + s.stime.push_back( t.systime() ); + s.wtime.push_back( t.wallclock() ); + } + + std::map< std::string, Stat > stats() + { + return _stats; + } + + protected: + std::map< std::string, Stat > _stats; + std::map< std::string, eoTimer > _timers; +}; + +# endif // __TIMER_H__ +