vSMC
vSMC: Scalable Monte Carlo
progress.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/utility/progress.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013,2014, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_UTILITY_PROGRESS_HPP
33 #define VSMC_UTILITY_PROGRESS_HPP
34 
35 #include <vsmc/internal/common.hpp>
37 
38 #if VSMC_HAS_CXX11LIB_CHRONO && VSMC_HAS_CXX11LIB_THREAD
39 #include <chrono>
40 #include <thread>
41 #endif
42 
43 namespace vsmc {
44 
45 #if VSMC_HAS_CXX11LIB_CHRONO && VSMC_HAS_CXX11LIB_THREAD
46 namespace internal {
47 
49 {
50  static void sleep (double s)
51  {
52  double ms = std::floor(s * 1000);
53  if (s < 1.0)
54  s = 1.0;
55  std::this_thread::sleep_for(std::chrono::milliseconds(
56  static_cast<std::chrono::milliseconds::rep>(ms)));
57  }
58 }; // class ProgressThisThread
59 
60 } // namespace vsmc::internal
61 #endif
62 
94 #if VSMC_HAS_CXX11LIB_CHRONO && VSMC_HAS_CXX11LIB_THREAD
95 template <typename ThreadType = std::thread,
96  typename ThisThread = internal::ProgressThisThread>
97 #else
98 template <typename ThreadType, typename ThisThread>
99 #endif
100 class Progress
101 {
102  public :
103 
104  typedef ThreadType thread_type;
105 
107  Progress (std::ostream &os = std::cout) :
108  thread_ptr_(VSMC_NULLPTR), interval_(0), iter_(0), total_(0),
109  length_(0), show_iter_(false), print_first_(true), in_progress_(false),
110  num_equal_(0), percent_(0), seconds_(0), last_iter_(0),
111  cstr_bar_(), cstr_percent_(), cstr_time_(), cstr_iter_(), os_(os) {}
112 
122  void start (std::size_t total, const std::string &msg = std::string(),
123  std::size_t length = 0, bool show_iter = false,
124  double interval = 0.1)
125  {
126  total_ = total;
127  msg_ = msg;
128  length_ = length;
129  show_iter_ = show_iter;
130  interval_ = interval;
131 
132  iter_ = 0;
133  print_first_ = true;
134  in_progress_ = true;
135 
136  watch_.reset();
137  watch_.start();
138  fork();
139  }
140 
147  void stop (bool finished = false)
148  {
149  in_progress_ = false;
150  join();
151  if (finished && iter_ < total_)
152  iter_ = total_;
153  print_stop_(this);
154  watch_.stop();
155  }
156 
158  void increment (std::size_t step = 1) {iter_ += step;}
159 
160  private :
161 
162  StopWatch watch_;
163  thread_type *thread_ptr_;
164 
165  double interval_;
166  std::size_t iter_;
167  std::size_t total_;
168  std::size_t length_;
169  bool show_iter_;
170  bool print_first_;
171  bool in_progress_;
172 
173  std::size_t num_equal_;
174  std::size_t percent_;
175  std::size_t seconds_;
176  std::size_t last_iter_;
177 
178  std::string msg_;
179  char cstr_bar_[128];
180  char cstr_percent_[32];
181  char cstr_time_[32];
182  char cstr_iter_[64];
183 
184  std::ostream &os_;
185 
186  void fork ()
187  {
188  join();
189  thread_ptr_ = new thread_type(print_start_, this);
190  }
191 
192  void join ()
193  {
194  if (thread_ptr_ != VSMC_NULLPTR) {
195  if (thread_ptr_->joinable())
196  thread_ptr_->join();
197  delete thread_ptr_;
198  thread_ptr_ = VSMC_NULLPTR;
199  }
200  }
201 
202  static void print_start_ (void *context)
203  {
204  Progress *ptr = static_cast<Progress *>(context);
205  while (ptr->in_progress_) {
206  print_progress(context);
207  ptr->os_ << '\r' << std::flush;
208  ThisThread::sleep(ptr->interval_);
209  }
210  }
211 
212  static void print_stop_ (void *context)
213  {
214  Progress *ptr = static_cast<Progress *>(context);
215  print_progress(context);
216  ptr->os_ << '\n' << std::flush;
217  }
218 
219  static void print_progress (void *context)
220  {
221  Progress *ptr = static_cast<Progress *>(context);
222 
223  ptr->watch_.stop();
224  ptr->watch_.start();
225  const std::size_t seconds =
226  static_cast<std::size_t>(ptr->watch_.seconds());
227 
228  const std::size_t display_iter = ptr->iter_ <= ptr->total_ ?
229  ptr->iter_ : ptr->total_;
230  std::size_t num_equal = (ptr->total_ | ptr->length_) == 0 ?
231  ptr->length_ : ptr->length_ * display_iter / ptr->total_;
232  num_equal = num_equal <= ptr->length_ ? num_equal : ptr->length_;
233  std::size_t percent = ptr->total_ == 0 ? 100 :
234  100 * display_iter / ptr->total_;
235  percent = percent <= 100 ? percent : 100;
236 
237  if (ptr->print_first_) {
238  ptr->print_first_ = false;
239  ptr->num_equal_ = num_equal + 1;
240  ptr->percent_ = percent + 1;
241  ptr->seconds_ = seconds + 1;
242  ptr->last_iter_ = ptr->iter_ + 1;
243  }
244 
245  if (ptr->length_ != 0 && ptr->num_equal_ != num_equal) {
246  ptr->num_equal_ = num_equal;
247  std::size_t num_space = ptr->length_ - num_equal;
248  std::size_t num_dash = 0;
249  if (num_space > 0) {
250  num_dash = 1;
251  --num_space;
252  }
253 
254  char *cstr = ptr->cstr_bar_;
255  std::size_t offset = 0;
256  cstr[offset++] = '[';
257  for (std::size_t i = 0; i != num_equal; ++i)
258  cstr[offset++] = '=';
259  for (std::size_t i = 0; i != num_dash; ++i)
260  cstr[offset++] = '-';
261  for (std::size_t i = 0; i != num_space; ++i)
262  cstr[offset++] = ' ';
263  cstr[offset++] = ']';
264  cstr[offset++] = '\0';
265  }
266 
267  if (ptr->percent_ != percent) {
268  ptr->percent_ = percent;
269  const std::size_t num_space = 3 - uint_digit(percent);
270 
271  char *cstr = ptr->cstr_percent_;
272  std::size_t offset = 0;
273  cstr[offset++] = '[';
274  for (std::size_t i = 0; i != num_space; ++i)
275  cstr[offset++] = ' ';
276  uint_to_char(percent, cstr, offset);
277  cstr[offset++] = '%';
278  cstr[offset++] = ']';
279  cstr[offset++] = '\0';
280  }
281 
282  if (ptr->seconds_ != seconds) {
283  ptr->seconds_ = seconds;
284  const std::size_t display_second = seconds % 60;
285  const std::size_t display_minute = (seconds / 60) % 60;
286  const std::size_t display_hour = seconds / 3600;
287 
288  char *cstr = ptr->cstr_time_;
289  std::size_t offset = 0;
290  cstr[offset++] = '[';
291  if (display_hour > 0) {
292  uint_to_char(display_hour, cstr, offset);
293  cstr[offset++] = ':';
294  }
295  cstr[offset++] = '0' + static_cast<char>(display_minute / 10);
296  cstr[offset++] = '0' + static_cast<char>(display_minute % 10);
297  cstr[offset++] = ':';
298  cstr[offset++] = '0' + static_cast<char>(display_second / 10);
299  cstr[offset++] = '0' + static_cast<char>(display_second % 10);
300  cstr[offset++] = ']';
301  cstr[offset++] = '\0';
302  }
303 
304  if (ptr->show_iter_ && ptr->last_iter_ != ptr->iter_) {
305  ptr->last_iter_ = ptr->iter_;
306  const std::size_t dtotal = uint_digit(ptr->total_);
307  const std::size_t diter = uint_digit(ptr->iter_);
308  const std::size_t num_space = dtotal > diter ? dtotal - diter : 0;
309 
310  char *cstr = ptr->cstr_iter_;
311  std::size_t offset = 0;
312  cstr[offset++] = '[';
313  for (std::size_t i = 0; i < num_space; ++i)
314  cstr[offset++] = ' ';
315  uint_to_char(ptr->iter_, cstr, offset);
316  cstr[offset++] = '/';
317  uint_to_char(ptr->total_, cstr, offset);
318  cstr[offset++] = ']';
319  cstr[offset++] = '\0';
320  }
321 
322  ptr->os_ << ' ';
323  if (ptr->length_ != 0) ptr->os_ << ptr->cstr_bar_;
324  ptr->os_ << ptr->cstr_percent_;
325  ptr->os_ << ptr->cstr_time_;
326  if (ptr->show_iter_) ptr->os_ << ptr->cstr_iter_;
327  if (ptr->msg_.size() != 0) ptr->os_ << '[' << ptr->msg_ << ']';
328  }
329 
330  template <typename UIntType>
331  static void uint_to_char (UIntType num, char *cstr, std::size_t &offset)
332  {
333  if (num == 0) {
334  cstr[offset++] = '0';
335  return;
336  }
337 
338  char utmp[32];
339  std::size_t unum = 0;
340  while (num) {
341  utmp[unum++] = '0' + static_cast<char>(num % 10);
342  num /= 10;
343  }
344  for (std::size_t i = unum; i != 0; --i)
345  cstr[offset++] = utmp[i - 1];
346  }
347 
348  template <typename UIntType>
349  static std::size_t uint_digit (UIntType num)
350  {
351  if (num == 0)
352  return 1;
353 
354  std::size_t digit = 0;
355  while (num != 0) {
356  ++digit;
357  num /= 10;
358  }
359 
360  return digit;
361  }
362 }; // class Progress
363 
364 } // namespace vsmc
365 
366 #endif // VSMC_UTILITY_PROGRESS_HPP
Definition: adapter.hpp:37
Progress(std::ostream &os=std::cout)
Construct a Progress with an output stream.
Definition: progress.hpp:107
static void sleep(double s)
Definition: progress.hpp:50
void reset()
Stop and reset the elapsed time to zero.
Definition: stop_watch.hpp:167
void start(std::size_t total, const std::string &msg=std::string(), std::size_t length=0, bool show_iter=false, double interval=0.1)
Start to print the progress.
Definition: progress.hpp:122
void increment(std::size_t step=1)
Increment the iteration count.
Definition: progress.hpp:158
StopWatch as an adapter of C++11 clock.
Definition: stop_watch.hpp:117
bool stop()
Stop the watch, no effect if already stopped.
Definition: stop_watch.hpp:154
#define VSMC_NULLPTR
nullptr
Definition: defines.hpp:79
ThreadType thread_type
Definition: progress.hpp:104
bool start()
Start the watch, no effect if already started.
Definition: stop_watch.hpp:138
void stop(bool finished=false)
Stop to print the progress.
Definition: progress.hpp:147
Display a progress bar while algorithm proceed.
Definition: progress.hpp:100