-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathezRateProgressBar.hpp
258 lines (234 loc) · 6.97 KB
/
ezRateProgressBar.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
Copyright (C) 2011,2012 Remik Ziemlinski. See MIT-LICENSE.
CHANGELOG
v0.0.0 20110502 rsz Created.
V1.0.0 20110522 rsz Extended to show eta with growing bar.
v2.0.0 20110525 rsz Added time elapsed.
v2.0.0 20110525 rsz Fix minutes value.
v2.0.1 20111006 rsz Added default constructor value.
v2.0.2 20111011 rsz Fix minutes value (for real this time). Show decimal rate if less than one.
v2.0.3 20111109 rsz Fix overwrite previous line if longer than new line.
v2.1.0 20111130 rsz Templatized counter to make increments possible with reals. Replaced cout with faster printf.
*/
#ifndef EZ_RATEPROGRESSBAR_H
#define EZ_RATEPROGRESSBAR_H
#include <iostream>
#include <sstream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <iomanip>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
namespace ez {
/*
Display progress on two lines with rate update.
Done | Elapsed | Remaining | Processed | Unprocessed | Rate
90% | 23:45:56 | 23:45:56 | 1 MB | 1,299 MB | 124 MB/s
*/
template <typename T>
class ezRateProgressBar {
public:
ezRateProgressBar(T _n=0) : n(_n), pct(0), cur(0), unitsWidth(0), width(0), done(0) {}
void reset() { pct = 0; cur = 0; done = 0; }
void start() {
#ifdef WIN32
assert(QueryPerformanceFrequency(&g_llFrequency) != 0);
#endif
startTime = osQueryPerfomance();
prevTime = startTime;
printHeader();
}
void commaNumber(T v, std::string & str) {
std::ostringstream stm;
if (v >= 1) {
stm << (long long)v;
str = stm.str();
for(int i=str.size()-3; i>0; i-=3) str.insert(i, 1, ',');
} else {
stm << std::fixed << std::setprecision(3) << v;
str = stm.str();
}
}
// http://stackoverflow.com/questions/3283804/c-get-milliseconds-since-some-date
long long osQueryPerfomance() {
#ifdef WIN32
LARGE_INTEGER llPerf = {0};
QueryPerformanceCounter(&llPerf);
return llPerf.QuadPart * 1000ll / ( g_llFrequency.QuadPart / 1000ll);
#else
struct timeval stTimeVal;
gettimeofday(&stTimeVal, NULL);
return stTimeVal.tv_sec * 1000000ll + stTimeVal.tv_usec;
#endif
}
void printHeader() {
//Done | Elapsed | Remaining | Processed | Unprocessed | Rate
std::string out;
out.reserve(80);
out.assign("Done | Elapsed | Remaining | ");
// Compute how many max characters 'n' would take when formatted.
std::string str;
commaNumber(n, str);
int i;
// Width of "123,456".
int nWidth = str.size();
unitsWidth = strlen(units);
// Width of "123,456 MB".
int nUnitsWidth = nWidth + unitsWidth + 1;
// "Processed" is 9 chars.
if (nUnitsWidth > 9)
procColWidth = nUnitsWidth;
else
procColWidth = 9;
if (nUnitsWidth > 11)
unprocColWidth = nUnitsWidth;
else
unprocColWidth = 11;
out.append(procColWidth-9, ' ');
out.append("Processed | ");
out.append(unprocColWidth-11, ' ');
out.append("Unprocessed | Rate\n");
printf("%s", out.c_str());
}
void secondsToString(unsigned int t, std::string & out) {
unsigned int days = t/86400;
unsigned int sec = t-days*86400;
unsigned int hours = sec/3600+days*24;
sec = t - hours*3600;
sec = (sec > 0 ? sec : 0);
unsigned int mins = sec/60;
sec -= mins*60;
char tmp[8];
out.clear();
sprintf(tmp, "%02u:", hours);
out.append(tmp);
sprintf(tmp, "%02u:", mins);
out.append(tmp);
sprintf(tmp, "%02u", sec);
out.append(tmp);
}
void operator++() {
update( cur++ );
};
T operator+=(const T delta) {
cur += delta;
update( cur );
return cur;
};
void update(T newvalue) {
// Nothing to update if already maxed out.
if (done) return;
endTime = osQueryPerfomance();
// Abort if at least 1 second didn't elapse, unless newvalue will get us to 100%.
if ( ((endTime-prevTime)/1000000.0 < 1.0) && (newvalue < n) ) return;
prevTime = endTime;
float dt = (endTime-startTime)/1000000.0;
//if (dt < 1) return; // Was meant to avoid division by zero when time was in whole numbers.
cur = newvalue;
char pctstr[8];
float Pct = ((double)cur)/n;
sprintf(pctstr, "%3d%%", (int)(100*Pct));
std::string out;
out.reserve(80);
out.append(pctstr);
// Seconds.
std::string tstr;
out.append(" | ");
secondsToString( (unsigned int)dt, tstr);
out.append(tstr);
int pad, newwidth;
if (Pct >= 1.0) {
// Print overall time and newline.
out.append(" | 00:00:00 | ");
commaNumber(n, tstr);
pad = procColWidth-tstr.size()-unitsWidth-1;
if (pad > 0) out.append(pad, ' ');
out.append(tstr);
out.append(" ");
out.append(units);
out.append(" | ");
pad = unprocColWidth-1-unitsWidth-1;
if (pad > 0) out.append(pad, ' ');
out.append("0 ");
out.append(units);
out.append(" | ");
commaNumber( (unsigned int)(n/dt), tstr);
out.append(tstr);
out.append(" ");
out.append(units);
out.append("/s");
newwidth = out.size();
if (newwidth < width)
out.append(width-newwidth,' ');
// Store length of this string so we know how much to blank out later.
width = newwidth;
out.append("\n");
printf("%s", out.c_str());
fflush(stdout);
done = 1;
} else {
float eta=0.;
if (Pct > 0.0) {
eta = dt*(1.0-Pct)/Pct;
}
out.append(" | ");
secondsToString((unsigned int)eta, tstr);
out.append(tstr);
out.append(" | ");
commaNumber(cur, tstr);
pad = procColWidth-tstr.size()-unitsWidth-1;
if (pad > 0) out.append(pad,' ');
out.append(tstr);
out.append(" ");
out.append(units);
out.append(" | ");
commaNumber(n-cur, tstr);
pad = unprocColWidth-tstr.size()-unitsWidth-1;
if (pad > 0) out.append(pad,' ');
out.append(tstr);
out.append(" ");
out.append(units);
out.append(" | ");
eta = cur/dt;
if (eta > 1.0)
commaNumber((unsigned int)eta, tstr);
else {
std::ostringstream stm;
stm << eta;
tstr = stm.str();
}
out.append(tstr);
out.append(" ");
out.append(units);
out.append("/s");
// Pad end with spaces to overwrite previous string that may have been longer.
newwidth = out.size();
if (newwidth < width)
out.append(width-newwidth,' ');
width = newwidth;
out.append("\r");
printf("%s", out.c_str());
fflush(stdout);
}
}
T n;
T cur;
char done;
unsigned short pct; // Stored as 0-1000, so 2.5% is encoded as 25.
unsigned char width; // Length of previously printed line we need to overwrite.
unsigned int unitsWidth;
unsigned int procColWidth;
unsigned int unprocColWidth;
const char * units; // Unit string to show for processed data.
long long startTime, prevTime, endTime;
#ifdef WIN32
LARGE_INTEGER g_llFrequency;
#endif
};
}
#endif // EZ_RATEPROGRESSBAR_H