SWE
|
00001 00028 #ifndef PROGRESSBAR_H 00029 #define PROGRESSBAR_H 00030 00031 #include <cassert> 00032 #include <cmath> 00033 #include <ctime> 00034 #include <algorithm> 00035 #include <iostream> 00036 #include <limits> 00037 00038 #include <unistd.h> 00039 #include <sys/ioctl.h> 00040 00041 namespace tools 00042 { 00043 00044 class ProgressBar 00045 { 00046 private: 00048 int m_rank; 00049 00051 float m_totalWork; 00052 00054 time_t m_startTime; 00055 00057 unsigned int m_terminalSize; 00058 00060 unsigned char m_rotatingBar; 00061 00062 public: 00063 ProgressBar(float totalWork = 1., int rank = 0) 00064 : m_rank(rank), 00065 m_totalWork(totalWork), 00066 m_startTime(time(0)), 00067 m_rotatingBar(0) 00068 { 00069 if (rank != 0) 00070 return; 00071 00072 #ifdef TIOCGSIZE 00073 struct ttysize ts; 00074 ioctl(STDIN_FILENO, TIOCGSIZE, &ts); 00075 m_terminalSize = ts.ts_cols; 00076 #elif defined(TIOCGWINSZ) 00077 struct winsize ts; 00078 ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); 00079 m_terminalSize = ts.ws_col; 00080 #else 00081 m_terminalSize = 0; 00082 #endif 00083 if (m_terminalSize > 300) 00084 // Probably an error due to MPI 00085 m_terminalSize = MIN_TERM_SIZE; 00086 } 00087 00091 void update(float done) 00092 { 00093 if (m_rank != 0 || m_terminalSize < MIN_TERM_SIZE) 00094 return; 00095 00096 unsigned int printed = 2; 00097 std::cout << '\r'; 00098 printed += printTimeLeft(done); 00099 std::cout << ' '; 00100 printed += printPercentage(done); 00101 std::cout << ' '; 00102 printProgressBar(done, m_terminalSize-printed-2); 00103 std::cout << ' '; 00104 printRotatingBar(); 00105 std::cout << std::flush; 00106 } 00107 00108 void clear() 00109 { 00110 if (m_rank != 0 || m_terminalSize < MIN_TERM_SIZE) 00111 return; 00112 00113 std::cout << '\r'; 00114 for (unsigned int i = 0; i < m_terminalSize; i++) 00115 std::cout << ' '; 00116 std::cout << '\r'; 00117 } 00118 00119 private: 00123 unsigned int printTimeLeft(float done) 00124 { 00125 float timeLeft; 00126 if (done <= 0) 00127 timeLeft = std::numeric_limits<float>::max(); 00128 else 00129 timeLeft = (time(0) - m_startTime) * (m_totalWork - done) / done; 00130 00131 std::cout << "Time left: "; 00132 00133 if (timeLeft < 1) { 00134 for (int i = 3; i < TIME_SIZE; i++) 00135 std::cout << ' '; 00136 std::cout << "< 1"; 00137 } else { 00138 int digits = ceil(log(timeLeft)/log(10)); 00139 if (digits > TIME_SIZE) { 00140 // Maximum number we can show 00141 for (int i = 0; i < TIME_SIZE; i++) 00142 std::cout << '9'; 00143 } else { 00144 streamsize oldPrec = std::cout.precision(); 00145 std::ios::fmtflags oldFlags = std::cout.flags(); 00146 streamsize oldWidth = std::cout.width(); 00147 00148 std::cout.precision(std::max(0, TIME_SIZE-digits-2)); 00149 std::cout.setf(std::ios::fixed); 00150 std::cout.width(TIME_SIZE); 00151 00152 std::cout << timeLeft; 00153 00154 std::cout.precision(oldPrec); 00155 std::cout.flags(oldFlags); 00156 std::cout.width(oldWidth); 00157 } 00158 } 00159 00160 std::cout << " sec"; 00161 00162 return 11+TIME_SIZE+4; 00163 } 00164 00168 unsigned int printPercentage(float done) 00169 { 00170 int per = floor(done/m_totalWork*100); 00171 00172 std::cout << '('; 00173 00174 streamsize oldWidth = std::cout.width(); 00175 00176 std::cout.width(3); 00177 std::cout << per; 00178 00179 std::cout.width(oldWidth); 00180 00181 std::cout << "% done)"; 00182 00183 return 1+3+7; 00184 } 00185 00186 void printProgressBar(float done, unsigned int size) 00187 { 00188 if (size < 3) 00189 return; 00190 00191 size -= 2; // leave space for [] 00192 unsigned int per = floor(done/m_totalWork * size); 00193 00194 std::cout << '['; 00195 00196 for (unsigned int i = 0; i < per; i++) 00197 std::cout << '='; 00198 00199 if (per < size) { 00200 std::cout << '>'; 00201 per++; 00202 } 00203 00204 for (unsigned int i = per; i < size; i++) 00205 std::cout << ' '; 00206 00207 std::cout << ']'; 00208 } 00209 00210 void printRotatingBar() 00211 { 00212 static const char* CHARS = "|/-\\"; 00213 00214 std::cout << CHARS[m_rotatingBar]; 00215 00216 m_rotatingBar = (m_rotatingBar + 1) % 4; 00217 } 00218 00219 static const unsigned int MIN_TERM_SIZE = 80; 00220 static const int TIME_SIZE = 8; 00221 }; 00222 00223 } 00224 00225 #endif // PROGRESSBAR_H