LCOV - code coverage report
Current view: top level - include/ipc - ompLoopWatcher.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 100.0 % 69 69
Test Date: 2026-08-30 22:23:37 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /** \file ompLoopWatcher.hpp
       2              :  * \brief Track iterations in an OMP parallelized looop.
       3              :  *
       4              :  * \author Jared R. Males (jaredmales@gmail.com)
       5              :  *
       6              :  * \ingroup utils_files
       7              :  *
       8              :  */
       9              : 
      10              : //***********************************************************************//
      11              : // Copyright 2015, 2016, 2017 Jared R. Males (jaredmales@gmail.com)
      12              : //
      13              : // This file is part of mxlib.
      14              : //
      15              : // mxlib is free software: you can redistribute it and/or modify
      16              : // it under the terms of the GNU General Public License as published by
      17              : // the Free Software Foundation, either version 3 of the License, or
      18              : // (at your option) any later version.
      19              : //
      20              : // mxlib is distributed in the hope that it will be useful,
      21              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      22              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      23              : // GNU General Public License for more details.
      24              : //
      25              : // You should have received a copy of the GNU General Public License
      26              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      27              : //***********************************************************************//
      28              : 
      29              : #ifndef ompLoopWatcher_hpp
      30              : #define ompLoopWatcher_hpp
      31              : 
      32              : #include <iostream>
      33              : #include "../sys/timeUtils.hpp"
      34              : 
      35              : namespace mx
      36              : {
      37              : namespace ipc
      38              : {
      39              : 
      40              : /// A class to track the number of iterations in an OMP parallelized loop.
      41              : /** Uses omp critical directives to deconflict updates by different loops.  Example:
      42              :   * \code
      43              :     ompLoopWatcher<> watcher(1000, std::cout); //Uses defaults
      44              : 
      45              :     #pragma omp parallel for
      46              :     int( i=0; i<1000; ++i)
      47              :     {
      48              :        watcher.incrementAndOutputStatus();
      49              :        //Do loop work
      50              :        ...
      51              :     }
      52              :     \endcode
      53              :   * This will result in the following output
      54              :    \verbatim
      55              :    1 / 1000 (0.1%)
      56              :    2 / 1000 (0.2%)
      57              :    3 / 1000 (0.3%)
      58              :    \endverbatim
      59              :   * and so on.
      60              :   *
      61              :   * \note This can reduce performance due to critical points it creates if used in fast loops (i.e. do not use inside
      62              :   the inner most loop!).
      63              :   *
      64              :   * The behavior of the output is controlled through template parameters.  A different output-type can be specified,
      65              :   which needs to accept size_t, and optionally
      66              :   * float, and character input using the << operator.
      67              :   *
      68              :   * \tparam outputT a type which accepts size_t, float, and character input via the  << operator (default is
      69              :   std::ostream).
      70              :   * \tparam _printPretty flag to control whether the output is nicely formatted, if false then just the numbers are sent
      71              :   to the output with no spaces or delimiters (default is true).
      72              :   * \tparam _printLoops flag to control whether the number of loops is sent to the output each time (default is true).
      73              :   * \tparam _printPercent flag to control whether the percentage complete is calculated (default is true).
      74              :   * \tparam _printNLine flag to control whether the newline '\\n' is sent ot output (default is false).  If false, '\\r'
      75              :   is written at end of output.
      76              :   * \tparam _time flag to control whether time is tracked.  Default is true.
      77              :   * \ingroup mtutils
      78              :   */
      79              : template <class _outputT = std::ostream,
      80              :           bool _printPretty = true,
      81              :           bool _printLoops = true,
      82              :           bool _printPercent = true,
      83              :           bool _printNLine = false,
      84              :           bool _time = true>
      85              : class ompLoopWatcher
      86              : {
      87              :   public:
      88              :     typedef _outputT outputT;
      89              : 
      90              :   protected:
      91              :     size_t _nLoops;  ///< The total number of loops
      92              :     size_t _counter; ///< The current counter
      93              : 
      94              :     double t0;
      95              :     double t1;
      96              : 
      97              :     outputT *_output; ///< Pointer to the instance of type outputT
      98              : 
      99              :     size_t m_outputInterval {10};
     100              :     size_t m_outputCount {0};
     101              : 
     102              :     /// Increment the counter
     103           45 :     void _increment()
     104              :     {
     105           45 :         ++_counter;
     106              :         if( _time )
     107              :         {
     108           35 :             t1 = sys::get_curr_time();
     109              :         }
     110           45 :     }
     111              : 
     112              :     /// Advance the counter by a number of steps
     113           11 :     void _advance( size_t diff_count )
     114              :     {
     115           11 :         _counter += diff_count;
     116              :         if( _time )
     117              :         {
     118           11 :             t1 = sys::get_curr_time();
     119              :         }
     120           11 :     }
     121              : 
     122              :     /// Perform the output
     123           64 :     void _outputStatus()
     124              :     {
     125           64 :         if(m_outputInterval > 1)
     126              :         {
     127           64 :             if(m_outputCount < (m_outputInterval-1))
     128              :             {
     129           58 :                 ++m_outputCount;
     130           58 :                 return;
     131              :             }
     132              : 
     133            6 :             m_outputCount = 0;
     134              :         }
     135              : 
     136              :         if( _printPretty )
     137              :         {
     138            4 :             ( *_output ) << _counter;
     139              :             if( _printLoops )
     140              :             {
     141            4 :                 ( *_output ) << " / " << _nLoops;
     142              :             }
     143              :             if( _printPercent )
     144              :             {
     145            4 :                 ( *_output ) << " (" << 100.0 * ( (float)_counter ) / _nLoops << "%)";
     146              :             }
     147              :             if( _time )
     148              :             {
     149            4 :                 ( *_output ) << " " << ( t1 - t0 ) / _counter << " s/loop ";
     150            4 :                 ( *_output ) << " ~" << ( _nLoops - _counter ) * ( t1 - t0 ) / _counter << " s left";
     151              :             }
     152              : 
     153              :             if( _printNLine )
     154              :             {
     155            1 :                 ( *_output ) << '\n';
     156              :             }
     157              :             if( !_printNLine )
     158              :             {
     159            3 :                 ( *_output ) << "           \r";
     160              :             }
     161              : 
     162            4 :             ( *_output ) << std::flush;
     163              :         }
     164              :         else
     165              :         {
     166            2 :             ( *_output ) << _counter;
     167              :             if( _printLoops )
     168              :             {
     169            1 :                 ( *_output ) << _nLoops;
     170              :             }
     171              :             if( _printPercent )
     172              :             {
     173            1 :                 ( *_output ) << 100.0 * ( (float)_counter ) / _nLoops;
     174              :             }
     175              :             if( _time )
     176              :             {
     177            1 :                 ( *_output ) << " " << t0 << " " << t1;
     178              :             }
     179              :             if( _printNLine )
     180              :             {
     181            1 :                 ( *_output ) << '\n';
     182              :             }
     183              :         }
     184              :     }
     185              : 
     186              :   private:
     187              :     // Default C'tor is private since you always have to give the number of loops.
     188              :     ompLoopWatcher()
     189              :     {
     190              :     }
     191              : 
     192              :   public:
     193              :     /// Constructor
     194              :     /** Registers the output and sets the number of loops.
     195              :      *
     196              :      * \param nLoops is the total number of loops.
     197              :      * \param output is the instance of type outputT to which the output will be sent.
     198              :      */
     199            5 :     ompLoopWatcher( size_t nLoops, outputT &output )
     200            5 :     {
     201            5 :         _output = &output;
     202            5 :         _nLoops = nLoops;
     203            5 :         _counter = 0;
     204              : 
     205              :         if( _time )
     206            4 :             t0 = sys::get_curr_time();
     207            5 :     }
     208              : 
     209              :     /// Increment the counter.
     210              :     /** Call this once per loop.  It contains an omp critical directive.
     211              :      */
     212            1 :     void increment()
     213              :     {
     214            2 : #pragma omp critical
     215            1 :         _increment();
     216            1 :     }
     217              : 
     218              :     /// Advance the counter by a number of steps.
     219              :     /** Call this once per loop.  It contains an omp critical directive.
     220              :      */
     221            1 :     void advance( size_t diff_count )
     222              :     {
     223            2 : #pragma omp critical
     224            1 :         _advance( diff_count );
     225            1 :     }
     226              : 
     227              :     /// Output current status.
     228              :     /** Call this whenever you want a status update.  It contains an omp critical directive.
     229              :      */
     230           10 :     void outputStatus()
     231              :     {
     232           20 : #pragma omp critical
     233           10 :         _outputStatus();
     234           10 :     }
     235              : 
     236              :     /// Output a final report about elapsed time
     237            4 :     void outputFinalStatus()
     238              :     {
     239              :         if( _printPretty )
     240              :         {
     241              :             if( _time )
     242              :             {
     243            2 :                 ( *_output ) << ( t1 - t0 ) << " s elapsed ";
     244            2 :                 ( *_output ) << " (" << ( t1 - t0 ) / _counter << " s/loop) ";
     245              :             }
     246              : 
     247              :             if( _printNLine )
     248              :             {
     249            1 :                 ( *_output ) << '\n';
     250              :             }
     251              :             if( !_printNLine )
     252              :             {
     253            1 :                 ( *_output ) << "           \r";
     254              :             }
     255              : 
     256            2 :             ( *_output ) << std::flush;
     257              :         }
     258              :         else
     259              :         {
     260              :             if( _time )
     261              :             {
     262            1 :                 ( *_output ) << " " << t0 << " " << t1;
     263              :             }
     264              :             if( _printNLine )
     265              :             {
     266            1 :                 ( *_output ) << '\n';
     267              :             }
     268              :         }
     269            4 :     }
     270              : 
     271              :     /// Increment and output status.
     272              :     /** Call this to increment and then give a status update.  Has only one omp critical directive for the two steps.
     273              :      */
     274           44 :     void incrementAndOutputStatus()
     275              :     {
     276           88 : #pragma omp critical
     277              :         {
     278           44 :             _increment();
     279           44 :             _outputStatus();
     280              :         }
     281           44 :     }
     282              : 
     283              :     /// Advance and output status.
     284              :     /** Call this to advance and then give a status update.  Has only one omp critical directive for the two steps.
     285              :      */
     286           10 :     void advanceAndOutputStatus( size_t diff_count )
     287              :     {
     288           20 : #pragma omp critical
     289              :         {
     290           10 :             _advance( diff_count );
     291           10 :             _outputStatus();
     292              :         }
     293           10 :     }
     294              : 
     295              :     /// Clear the output line of any text
     296              :     /** If printing pretty and not printing new lines, this writes a line of blank
     297              :      *  spaces and carriage returns to clear out the last status update.
     298              :      */
     299            2 :     void clearOutput()
     300              :     {
     301              :         if( _printPretty )
     302              :         {
     303              :             if( !_printNLine )
     304              :             {
     305            1 :                 ( *_output ) << "                                                               \r";
     306            1 :                 ( *_output ) << std::flush;
     307              :             }
     308              :         }
     309            2 :     }
     310              : };
     311              : 
     312              : } // namespace ipc
     313              : 
     314              : } // namespace mx
     315              : 
     316              : #endif // ompLoopWatcher_hpp
        

Generated by: LCOV version 2.0-1