1 #ifndef DEBUG_H 2 #define DEBUG_H 3 4 #include <iostream> 5 #include "Util.h" 6 #include "Timer.h" 7 #include "MathUtil.h" 8 #include <unistd.h> 9 #include <stdlib.h> 10 #include <cstddef> 11 #include <sys/stat.h> 12 13 class TtyCheck { 14 public: TtyCheck()15 TtyCheck() { 16 tty = false; 17 18 bool stdoutIsTty = isatty(fileno(stdout)); 19 bool stderrtIsTty = isatty(fileno(stderr)); 20 struct stat stats; 21 fstat(fileno(stdin), &stats); 22 bool isChr = S_ISCHR (stats.st_mode) == true; // is terminal 23 bool isFifo = S_ISFIFO(stats.st_mode) == false; // is no pipe 24 bool isReg = S_ISREG(stats.st_mode) == false; 25 if (isFifo && stdoutIsTty && stderrtIsTty && isReg && isChr) { 26 tty = true; 27 } 28 29 char* ttyEnv = getenv("TTY"); 30 if(ttyEnv != NULL && strcasecmp(ttyEnv, "1") == 0) { 31 tty = true; 32 } 33 if(ttyEnv != NULL && strcasecmp(ttyEnv, "0") == 0) { 34 tty = false; 35 } 36 37 }; 38 bool tty; 39 }; 40 41 class Debug 42 { 43 44 public: 45 static const int NOTHING = 0; 46 static const int ERROR = 1; 47 static const int WARNING = 2; 48 static const int INFO = 3; 49 50 enum Color { 51 FG_RED = 31, 52 FG_GREEN = 32, 53 FG_YELLOW = 33, 54 FG_BLUE = 34, 55 FG_DEFAULT = 39, 56 BG_RED = 41, 57 BG_GREEN = 42, 58 BG_BLUE = 44, 59 BG_DEFAULT = 49 60 }; 61 62 static int debugLevel; 63 64 Debug(int level)65 explicit Debug( int level ) : level(level) { 66 static TtyCheck check; 67 interactive = check.tty; 68 }; 69 ~Debug()70 ~Debug(){ 71 if (level <= ERROR && level <= debugLevel){ 72 std::cout << std::flush; 73 if(interactive){ 74 std::cerr << "\033[" << Color::FG_RED << "m" << buffer << "\033[" << Color::FG_DEFAULT << "m";; 75 }else{ 76 std::cerr << buffer; 77 } 78 std::cerr << std::flush; 79 } else if(level == WARNING && level <= debugLevel){ 80 if(interactive){ 81 std::cout << "\033[" << Color::FG_YELLOW << "m" << buffer << "\033[" << Color::FG_DEFAULT << "m"; 82 }else{ 83 std::cout << buffer; 84 } 85 std::cout << std::flush; 86 } else if(level > WARNING && level <= debugLevel) { 87 std::cout << buffer; 88 // std::cout << std::flush; 89 } 90 } 91 92 93 template<typename T> 94 Debug& operator<<( T t) 95 { 96 buffer.append(SSTR(t)); 97 return *this; 98 } 99 100 Debug& operator<<(double val){ 101 char str[64]; 102 snprintf(str, sizeof(str), "%f", val); 103 buffer.append(str); 104 return *this; 105 } 106 107 Debug& operator<<(float val){ 108 char str[64]; 109 snprintf(str, sizeof(str), "%f", val); 110 buffer.append(str); 111 return *this; 112 } 113 static void setDebugLevel(int i); 114 115 class Progress{ 116 private: 117 size_t currentPos; 118 size_t prevPrintedId; 119 size_t totalEntries; 120 bool interactive; 121 Timer timer; 122 123 const static int BARWIDTH = 65; 124 buildItemString(size_t id)125 std::string buildItemString(size_t id){ 126 std::string line; 127 unsigned int exp = MathUtil::log10(static_cast<unsigned int>(id+1)); 128 unsigned int base = 100; 129 130 char appending=' '; 131 switch(exp){ 132 case 3: 133 case 4: 134 case 5: 135 base = MathUtil::log10base(1000); 136 appending = 'K'; 137 break; 138 case 6: 139 case 7: 140 case 8: 141 base = MathUtil::log10base(1000000); 142 appending = 'M'; 143 break; 144 case 9: 145 case 10: 146 case 11: 147 base = MathUtil::log10base(1000000000); 148 appending = 'B'; 149 } 150 char fmtbuffer[32]; 151 if(exp < 3){ 152 int fmtElm = sprintf(fmtbuffer, "%d", static_cast<int>(id+1)); 153 line.append(fmtbuffer, fmtElm); 154 }else{ 155 int fmtElm = sprintf(fmtbuffer, "%.2f", static_cast<float>(id+1)/ static_cast<float>(base)); 156 line.append(fmtbuffer, fmtElm); 157 line.push_back(appending); 158 } 159 return line; 160 } 161 162 public: Progress(size_t totalEntries)163 Progress(size_t totalEntries) 164 : currentPos(0), prevPrintedId(0), totalEntries(totalEntries){ 165 static TtyCheck check; 166 interactive = check.tty; 167 } 168 Progress()169 Progress() : currentPos(0), prevPrintedId(0), totalEntries(SIZE_MAX){ 170 static TtyCheck check; 171 interactive = check.tty; 172 } 173 reset(size_t totalEntries)174 void reset(size_t totalEntries) { 175 this->totalEntries = totalEntries; 176 currentPos = 0; 177 prevPrintedId = 0; 178 } 179 updateProgress()180 void updateProgress(){ 181 size_t id = __sync_fetch_and_add(¤tPos, 1); 182 // if no active terminal exists write dots 183 if(interactive == false){ 184 if(totalEntries==SIZE_MAX) { 185 if(id==0) { 186 Debug(INFO) << '['; 187 } 188 if (id % 1000000 == 0 && id > 0){ 189 Debug(INFO) << "\t" << (id / 1000000) << " Mio. sequences processed\n"; 190 fflush(stdout); 191 } 192 else if (id % 10000 == 0 && id > 0) { 193 Debug(INFO) << "="; 194 fflush(stdout); 195 } 196 }else{ 197 if(id==0) { 198 Debug(INFO) << '['; 199 } 200 float progress = (totalEntries==1) ? 1.0 : (static_cast<float>(id) / static_cast<float>(totalEntries-1)); 201 float prevPrintedProgress = (totalEntries==1 || id == 0) ? 0.0 : (static_cast<float>(id-1) / static_cast<float>(totalEntries-1)); 202 int prevPos = BARWIDTH * prevPrintedProgress; 203 int pos = BARWIDTH * progress; 204 for (int write = prevPos; write < pos; write++) { 205 Debug(INFO) << '='; 206 fflush(stdout); 207 } 208 209 if(id == (totalEntries - 1) ){ 210 Debug(INFO) << "] "; 211 Debug(INFO) << buildItemString(id); 212 Debug(INFO) << " "; 213 Debug(INFO) << timer.lapProgress(); 214 Debug(INFO) << "\n"; 215 } 216 } 217 }else{ 218 if(totalEntries==SIZE_MAX){ 219 if(id > prevPrintedId + 100) { 220 std::string line; 221 line.push_back('['); 222 line.append(SSTR(id+1)); 223 line.append("] "); 224 line.append(timer.lapProgress()); 225 line.push_back('\r'); 226 Debug(Debug::INFO) << line; 227 fflush(stdout); 228 prevPrintedId = id; 229 } 230 }else{ 231 float progress = (totalEntries==1) ? 1.0 : (static_cast<float>(id) / static_cast<float>(totalEntries-1)); 232 float prevPrintedProgress = (totalEntries==1) ? 0.0 : (static_cast<float>(prevPrintedId) / static_cast<float>(totalEntries-1)); 233 if(progress-prevPrintedProgress > 0.01 || id == (totalEntries - 1) || id == 0 ){ 234 std::string line; 235 line.push_back('['); 236 int pos = BARWIDTH * progress; 237 for (int i = 0; i < BARWIDTH; ++i) { 238 if (i < pos) { 239 line.push_back('='); 240 }else if (i == pos) { 241 line.push_back('>'); 242 } else { 243 line.push_back(' '); 244 } 245 } 246 char buffer[32]; 247 int n = sprintf(buffer, "%.2f", progress * 100.0f); 248 line.append("] "); 249 line.append(buffer, n); 250 line.append("% "); 251 line.append(buildItemString(id)); 252 line.push_back(' '); 253 if(id == 0){ 254 line.append("eta -"); 255 }else if(id == (totalEntries - 1) ){ 256 line.append(timer.lapProgress()); 257 }else{ 258 double timeDiff = timer.getTimediff(); 259 double eta = (timeDiff/progress * 1.0) - timeDiff; 260 long long sec = (time_t)eta; 261 // long long msec = (time_t)((eta - sec) * 1e3); 262 // std::cout << timeDiff << "\t" << progress << std::endl; 263 line.append("eta "); 264 if(sec >= 3600){ 265 line.append(SSTR(sec / 3600)); 266 line.append("h "); 267 } 268 if(sec >= 60){ 269 line.append(SSTR( (sec % 3600 / 60))); 270 line.append("m "); 271 } 272 line.append(SSTR(sec % 60)); 273 // need to overwrite the rest 274 line.append("s "); 275 } 276 //printf("%zu\t%zu\t%f\n", id, totalEntries, progress); 277 line.push_back((id == (totalEntries - 1) ) ? '\n' : '\r' ); 278 Debug(Debug::INFO) << line; 279 fflush(stdout); 280 prevPrintedId=id; 281 } 282 } 283 } 284 } 285 }; 286 287 288 289 290 private: 291 const int level; 292 std::string buffer; 293 bool interactive; 294 }; 295 296 297 298 #endif 299