Belle II Software development
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
18using namespace std;
19using namespace Belle2;
20
21
22REG_MODULE(ProgressBar);
23
24ProgressBarModule::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.
STL namespace.