File NPProgressDisplay.cxx
File List > core > NPProgressDisplay.cxx
Go to the documentation of this file
#include "NPProgressDisplay.h"
// use to figure out the terminal window size
#include <iostream>
#include <sstream>
#include <sys/ioctl.h> //ioctl() and TIOCGWINSZ
#include <unistd.h> // for STDOUT_FILENO
using namespace nptool;
ProgressDisplay::ProgressDisplay(long long event_to_process, long long size_to_read, std::chrono::milliseconds interval)
: m_event_to_process(event_to_process), m_size_to_read(size_to_read), m_interval(interval), m_odd_even(true),
m_begin(std::chrono::system_clock::now()) {}
void ProgressDisplay::MakeLine(bool force) {
// Check the terminal window size
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
// reset the line
m_line.clear();
if (!m_odd_even)
m_line.resize(w.ws_col, '*');
else
m_line.resize(w.ws_col, '-');
// Event base progress display
if (m_event_to_process > 0) {
static std::string progress;
static std::stringstream prg;
// compute progress
static double ratio;
ratio = (double)(m_event_processed) / m_event_to_process;
// compute evt rate
static double rate_evt;
static long long previous_evt = 0;
static std::string rate_evt_unit = "";
// compute ETA
static int second_left, minute_left, hour_left = 0;
if (!force) {
rate_evt = 1000 * ((m_event_processed - previous_evt) / ((double)m_interval.count()));
second_left = (m_event_to_process - m_event_processed) / rate_evt;
minute_left = hour_left = 0;
if (second_left >= 3600) {
hour_left = second_left / 3600;
second_left -= 3600 * hour_left;
}
if (second_left >= 60) {
minute_left = second_left / 60;
second_left -= minute_left * 60;
}
previous_evt = m_event_processed;
if (rate_evt > 1e9) {
rate_evt /= 1e9;
rate_evt_unit = "G";
}
else if (rate_evt > 1e6) {
rate_evt /= 1e6;
rate_evt_unit = "M";
}
else if (rate_evt > 1e3) {
rate_evt /= 1e3;
rate_evt_unit = "k";
}
if (rate_evt > 1)
rate_evt = (int)(rate_evt);
}
// compute size rate
static double rate_size;
static long long previous_size = 0;
static std::string rate_size_unit = "";
if (!force && m_size_read > 0) {
rate_size = 1000 * ((m_size_read - previous_size) / ((double)m_interval.count()));
previous_size = m_size_read;
if (rate_size > 1e9) {
rate_size /= 1e9;
rate_size_unit = "G";
}
else if (rate_size > 1e6) {
rate_size /= 1e6;
rate_size_unit = "M";
}
else if (rate_size > 1e3) {
rate_size /= 1e3;
rate_size_unit = "k";
}
if (rate_size > 1)
rate_size = (int)(rate_size);
}
prg.str("");
prg << " Progress: " << (int)(ratio * 100) << "% (" << m_event_processed << "/" << m_event_to_process << ")";
prg << " | ETA: ";
if (hour_left)
prg << hour_left << "h";
if (minute_left || hour_left)
prg << minute_left << "m";
prg << second_left << "s";
prg << " | Rates: " << rate_evt << " " << rate_evt_unit << "evt/s";
if (m_size_read > 0)
prg << " (" << rate_size << " " << rate_size_unit << "b/s)";
prg << " ";
progress = prg.str();
// put progress in the middle
if (m_line.length() > progress.length())
m_line.replace(m_line.length() / 2 - progress.length() / 2, progress.length(), progress);
return;
}
// Size base progress display
else if (m_size_to_read > 0) {
static std::string progress;
static std::stringstream prg;
// compute progress
static double ratio;
ratio = (double)(m_size_read) / m_size_to_read;
// compute size rate
static double rate_size;
static long long size_read;
static long long previous_size = 0;
static std::string rate_size_unit = "";
// compute ETA
static int second_left, minute_left, hour_left = 0;
if (!force) {
rate_size = 1000 * ((m_size_read - previous_size) / ((double)m_interval.count()));
second_left = (m_size_to_read - m_size_read) / rate_size;
minute_left = hour_left = 0;
if (second_left >= 3600) {
hour_left = second_left / 3600;
second_left -= 3600 * hour_left;
}
if (second_left >= 60) {
minute_left = second_left / 60;
second_left -= minute_left * 60;
}
previous_size = m_size_read;
if (rate_size > 1e9) {
rate_size /= 1e9;
rate_size_unit = "G";
}
else if (rate_size > 1e6) {
rate_size /= 1e6;
rate_size_unit = "M";
}
else if (rate_size > 1e3) {
rate_size /= 1e3;
rate_size_unit = "k";
}
if (rate_size > 1)
rate_size = (int)(rate_size);
}
// compute evt rate
static double rate_evt;
static long long previous_evt = 0;
static std::string rate_evt_unit = "";
if (!force) {
rate_evt = 1000 * ((m_event_processed - previous_evt) / ((double)m_interval.count()));
previous_evt = m_event_processed;
if (rate_evt > 1e9) {
rate_evt /= 1e9;
rate_evt_unit = "G";
}
else if (rate_evt > 1e6) {
rate_evt /= 1e6;
rate_evt_unit = "M";
}
else if (rate_evt > 1e3) {
rate_evt /= 1e3;
rate_evt_unit = "k";
}
if (rate_evt > 1)
rate_evt = (int)(rate_evt);
}
prg.str("");
prg << " Progress: " << (int)(ratio * 100) << "% ";
prg << " | ETA: ";
if (hour_left)
prg << hour_left << "h";
if (minute_left || hour_left)
prg << minute_left << "m";
prg << second_left << "s";
prg << " | Rates: " << rate_evt << " " << rate_evt_unit << "evt/s";
if (m_size_read > 0)
prg << " (" << rate_size << " " << rate_size_unit << "b/s)";
prg << " ";
progress = prg.str();
// put progress in the middle
if (m_line.length() > progress.length())
m_line.replace(m_line.length() / 2 - progress.length() / 2, progress.length(), progress);
return;
}
// target less display (online case typically), only show running
else {
static std::string running = " Running ";
// put Running in the middle
m_line.replace(m_line.length() / 2 - running.length() / 2, running.length(), running);
return;
}
return;
}
void ProgressDisplay::AttemptDisplay(long long event_processed, long long size_read, bool force) {
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - m_begin);
static bool finished = false;
if (event_processed < 0)
m_event_processed++;
else
m_event_processed = event_processed;
if (size_read > 0)
m_size_read = size_read;
// do the display every interval
if (diff.count() > m_interval.count() || force) {
if ((m_event_to_process > 0 && m_event_processed >= m_event_to_process) ||
(m_size_to_read > 0 && size_read >= m_size_to_read))
finished = true;
if (!finished)
std::cout << "\r" << nptool::cli_yellow;
else
std::cout << "\r" << nptool::cli_green;
MakeLine(force);
std::cout << m_line << nptool::cli_restore_color << std::flush;
// reset the timer
m_begin = std::chrono::system_clock::now();
}
}
void ProgressDisplay::ForceDisplay(long long event_processed, long long size_read) {
AttemptDisplay(event_processed, size_read, true);
}