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