Belle II Software  release-05-02-19
ProgressBarModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2013 Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Christian Pulvermacher *
7  * *
8  **************************************************************************/
9 
10 #include <framework/modules/core/ProgressBarModule.h>
11 
12 #include <framework/core/Environment.h>
13 #include <framework/utilities/Utils.h>
14 
15 #include <iostream>
16 #include <iomanip>
17 #include <unistd.h>
18 
19 using namespace std;
20 using namespace Belle2;
21 
22 
23 REG_MODULE(ProgressBar)
24 
25 ProgressBarModule::ProgressBarModule() : Module(), m_evtNr(0), m_nTotal(0), m_startTime(0), m_lastPrint(0), m_isTTY{false}
26 {
27  setDescription(R"DOC(
28  Display a progress bar and an estimate of remaining time when number of
29  events is known (e.g. reading from file, or -n switch used).
30 
31  The progress bar uses stderr for its output, so it works best when stdout
32  is piped to a file. However it should also work when printing direct to a
33  terminal.
34 
35  .. versionchanged:: release-03-00-00
36  the module now detects if it outputs to a terminal or into a file and
37  will only update the bar if it has changed and not use any control
38  characters to make log files much more readable than before.
39  )DOC");
40 }
41 
42 void ProgressBarModule::initialize()
43 {
44  m_evtNr = 0;
45  m_nTotal = Environment::Instance().getNumberOfEvents();
46  m_startTime = 0;
47  m_progress = 0;
48  // Check if we run on a tty or if we are writing to a log file. In the second
49  // case we don't use carriage return but just new lines and only update if the progress bar changes.
50  // Done here in case someone fiddles with the file descriptor before we process
51  m_isTTY = isatty(STDERR_FILENO);
52 }
53 
54 void ProgressBarModule::event()
55 {
56  if (m_nTotal == 0)
57  return;
58 
59  double clockSec = Utils::getClock() / 1e9;
60 
61  // To not count intialization time we only print output starting one second
62  // after the first event is processed
63  if (m_startTime == 0) {
64  // first call, let's start here
65  m_startTime = clockSec;
66  m_lastPrint = m_startTime;
67  return;
68  }
69 
70  if (clockSec - m_lastPrint > 1) { //every second
71  double elapsedSec = clockSec - m_startTime;
72  double ratio = double(m_evtNr) / m_nTotal;
73  double time_per_event = elapsedSec / m_evtNr;
74  auto remainingSeconds = (int)std::round((m_nTotal - m_evtNr) * time_per_event);
75 
76  if (remainingSeconds >= 0) {
77  const int bar_length = 50; //characters for bar
78 
79  //If we don't write to a tty only update if the progress bar changes
80  if (!m_isTTY && int(ratio * bar_length) <= m_progress) return;
81  // remember where we were
82  m_progress = ratio * bar_length;
83 
84  cerr << '[';
85  for (int i = 0; i < m_progress; ++i) cerr << '=';
86  cerr << '>';
87  for (int i = m_progress + 1; i < bar_length; ++i) cerr << ' ';
88  cerr << "] " << setw(3) << int(ratio * 100) << "% ";
89  if (remainingSeconds > 3600) {
90  int hours = remainingSeconds / 3600;
91  remainingSeconds %= 3600;
92  cerr << hours << "h";
93  }
94  if (remainingSeconds > 60) {
95  int minutes = remainingSeconds / 60;
96  remainingSeconds %= 60;
97  cerr << minutes << "m";
98  }
99  cerr << remainingSeconds << "s remaining";
100  //some spaces to overwrite other stuff
101  cerr << " ";
102  if (m_isTTY) {
103  //carriage return to go back to beginning of the line
104  cerr << "\r";
105  } else {
106  //not a terminal, just make it an output line
107  cerr << endl;
108  }
109  // make sure it's printed
110  cerr << flush;
111 
112  m_lastPrint = clockSec;
113  }
114  }
115 
116  ++m_evtNr;
117 }
118 
119 void ProgressBarModule::terminate()
120 {
121  cerr << "\n";
122 }
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::ProgressBarModule
Display a progress bar and an estimate of remaining time when number of events is known (e....
Definition: ProgressBarModule.h:32