mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
ompLoopWatcher.hpp
Go to the documentation of this file.
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 the inner most loop!).
62  *
63  * The behavior of the output is controlled through template parameters. A different output-type can be specified, which needs to accept size_t, and optionally
64  * float, and character input using the << operator.
65  *
66  * \tparam outputT a type which accepts size_t, float, and character input via the << operator (default is std::ostream).
67  * \tparam _printPretty flag to control whether the output is nicely formatted, if false then just the numbers are sent to the output with no spaces or delimiters (default is true).
68  * \tparam _printLoops flag to control whether the number of loops is sent to the output each time (default is true).
69  * \tparam _printPercent flag to control whether the percentage complete is calculated (default is true).
70  * \tparam _printNLine flag to control whether the newline '\\n' is sent ot output (default is false). If false, '\\r' is written at end of output.
71  * \tparam _time flag to control whether time is tracked. Default is true.
72  * \ingroup mtutils
73  */
74 template<class _outputT=std::ostream, bool _printPretty=true, bool _printLoops=true, bool _printPercent=true, bool _printNLine=false, bool _time = true>
76 {
77 public:
78  typedef _outputT outputT;
79 
80 protected:
81  size_t _nLoops; ///< The total number of loops
82  size_t _counter; ///< The current counter
83 
84  double t0;
85  double t1;
86 
87  outputT * _output; ///< Pointer to the instance of type outputT
88 
89  ///Increment the counter
90  void _increment()
91  {
92  ++_counter;
93  if(_time) t1 = sys::get_curr_time();
94  }
95 
96  ///Advance the counter by a number of steps
97  void _advance( size_t diff_count)
98  {
99  _counter += diff_count;
100  if(_time) t1 = sys::get_curr_time();
101  }
102 
103  ///Perform the output
105  {
106  if(_printPretty)
107  {
108  (*_output) << _counter;
109  if(_printLoops) (*_output) << " / " << _nLoops;
110  if(_printPercent) (*_output) << " (" << 100.0*((float) _counter) / _nLoops << "%)";
111  if(_time)
112  {
113  (*_output) << " " << (t1-t0)/_counter << " s/loop ";
114  (*_output) << " ~" << (_nLoops - _counter)*(t1-t0)/_counter << " s left";
115  }
116 
117  if(_printNLine) (*_output) << '\n';
118  if(!_printNLine) (*_output) << " \r";
119 
120  (*_output) << std::flush;
121  }
122  else
123  {
124  (*_output) << _counter;
125  if(_printLoops) (*_output) << _nLoops;
126  if(_printPercent) (*_output) << 100.0*((float) _counter) / _nLoops;
127  if(_time) (*_output) << " " << t0 << " " << t1;
128  if(_printNLine) (*_output) << '\n';
129  }
130  }
131 
132 private:
133  //Default C'tor is private since you always have to give the number of loops.
135  {
136  }
137 
138 
139 public:
140 
141  ///Constructor
142  /** Registers the output and sets the number of loops.
143  *
144  * \param nLoops is the total number of loops.
145  * \param output is the instance of type outputT to which the output will be sent.
146  */
147  ompLoopWatcher( size_t nLoops,
148  outputT & output )
149  {
150  _output = &output;
151  _nLoops = nLoops;
152  _counter = 0;
153 
154  if(_time) t0 = sys::get_curr_time();
155  }
156 
157  ///Increment the counter.
158  /** Call this once per loop. It contains an omp critical directive.
159  */
160  void increment()
161  {
162  #pragma omp critical
163  _increment();
164  }
165 
166  ///Advance the counter by a number of steps.
167  /** Call this once per loop. It contains an omp critical directive.
168  */
169  void advance(size_t diff_count)
170  {
171  #pragma omp critical
172  _advance(diff_count);
173  }
174 
175  ///Output current status.
176  /** Call this whenever you want a status update. It contains an omp critical directive.
177  */
179  {
180  #pragma omp critical
181  _outputStatus();
182  }
183 
184  ///Increment and output status.
185  /** Call this to increment and then give a status update. Has only one omp critical directive for the two steps.
186  */
188  {
189  #pragma omp critical
190  {
191  _increment();
192  _outputStatus();
193  }
194  }
195 
196  ///Advance and output status.
197  /** Call this to advance and then give a status update. Has only one omp critical directive for the two steps.
198  */
199  void advanceAndOutputStatus(size_t diff_count)
200  {
201  #pragma omp critical
202  {
203  _advance(diff_count);
204  _outputStatus();
205  }
206  }
207 
208 };
209 
210 
211 
212 
213 } //namespace ipc
214 
215 } //namespace mx
216 
217 #endif //ompLoopWatcher_hpp
218 
A class to track the number of iterations in an OMP parallelized loop.
void increment()
Increment the counter.
void advanceAndOutputStatus(size_t diff_count)
Advance and output status.
void _increment()
Increment the counter.
size_t _nLoops
The total number of loops.
void outputStatus()
Output current status.
void _advance(size_t diff_count)
Advance the counter by a number of steps.
size_t _counter
The current counter.
outputT * _output
Pointer to the instance of type outputT.
void _outputStatus()
Perform the output.
void incrementAndOutputStatus()
Increment and output status.
ompLoopWatcher(size_t nLoops, outputT &output)
Constructor.
void advance(size_t diff_count)
Advance the counter by a number of steps.
typeT get_curr_time(timespec &tsp)
Get the current system time in seconds.
Definition: timeUtils.hpp:63
The mxlib c++ namespace.
Definition: mxError.hpp:107