Single file progress + speedometer

This commit is contained in:
Marcus Holland-Moritz 2023-07-04 02:34:35 +02:00
parent dd07da1156
commit 86ff4db32b
5 changed files with 133 additions and 18 deletions

View File

@ -29,6 +29,7 @@
#include <string> #include <string>
#include "dwarfs/logger.h" #include "dwarfs/logger.h"
#include "dwarfs/speedometer.h"
namespace dwarfs { namespace dwarfs {
@ -66,5 +67,7 @@ class console_writer : public logger {
bool const color_; bool const color_;
bool const with_context_; bool const with_context_;
bool const debug_progress_; bool const debug_progress_;
bool writing_{false};
speedometer<uint64_t> read_speed_;
}; };
} // namespace dwarfs } // namespace dwarfs

View File

@ -55,6 +55,9 @@ class progress {
std::string status(size_t max_len) const; std::string status(size_t max_len) const;
std::atomic<object const*> current{nullptr}; std::atomic<object const*> current{nullptr};
std::atomic<uint64_t> total_bytes_read{0};
std::atomic<size_t> current_size{0};
std::atomic<size_t> current_offset{0};
std::atomic<size_t> files_found{0}; std::atomic<size_t> files_found{0};
std::atomic<size_t> files_scanned{0}; std::atomic<size_t> files_scanned{0};
std::atomic<size_t> dirs_found{0}; std::atomic<size_t> dirs_found{0};

View File

@ -0,0 +1,65 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/**
* \author Marcus Holland-Moritz (github@mhxnet.de)
* \copyright Copyright (c) Marcus Holland-Moritz
*
* This file is part of dwarfs.
*
* dwarfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dwarfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dwarfs. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <chrono>
#include <deque>
namespace dwarfs {
template <typename T>
class speedometer {
public:
speedometer(std::chrono::milliseconds window_length) : window_length_{window_length} {}
void put(T s) {
auto now = std::chrono::steady_clock::now();
auto old = now - window_length_;
while (!samples_.empty() && samples_.front().first < old) {
samples_.pop_front();
}
samples_.emplace_back(now, s);
}
T num_per_second() const {
if (samples_.size() < 2) {
return T();
}
auto const& first = samples_.front();
auto const& last = samples_.back();
auto dt = last.first - first.first;
auto dv = last.second - first.second;
return (1000 * dv) / std::chrono::duration_cast<std::chrono::milliseconds>(dt).count();
}
void clear() {
samples_.clear();
}
private:
std::deque<std::pair<std::chrono::steady_clock::time_point, T>> samples_;
std::chrono::milliseconds window_length_;
};
} // namespace dwarfs

View File

@ -608,6 +608,10 @@ void block_manager_<LoggerPolicy>::segment_and_add_data(inode& ino, mmif& mm,
std::vector<segment_match> matches; std::vector<segment_match> matches;
const bool single_block_mode = cfg_.max_active_blocks == 1; const bool single_block_mode = cfg_.max_active_blocks == 1;
auto total_bytes_read_before = prog_.total_bytes_read.load();
prog_.current_offset.store(offset);
prog_.current_size.store(size);
while (offset < size) { while (offset < size) {
++stats_.bloom_lookups; ++stats_.bloom_lookups;
if (DWARFS_UNLIKELY(filter_.test(hasher()))) { if (DWARFS_UNLIKELY(filter_.test(hasher()))) {
@ -677,6 +681,9 @@ void block_manager_<LoggerPolicy>::segment_and_add_data(inode& ino, mmif& mm,
hasher.update(p[offset]); hasher.update(p[offset]);
} }
prog_.current_offset.store(offset);
prog_.total_bytes_read.store(total_bytes_read_before + offset);
next_hash_offset = next_hash_offset =
written + lookback_size + blocks_.back().next_hash_distance(); written + lookback_size + blocks_.back().next_hash_distance();
} }
@ -697,12 +704,17 @@ void block_manager_<LoggerPolicy>::segment_and_add_data(inode& ino, mmif& mm,
add_data(ino, mm, written, num_to_write); add_data(ino, mm, written, num_to_write);
written += num_to_write; written += num_to_write;
next_hash_offset += window_step_; next_hash_offset += window_step_;
prog_.current_offset.store(offset);
prog_.total_bytes_read.store(total_bytes_read_before + offset);
} }
hasher.update(p[offset - window_size_], p[offset]); hasher.update(p[offset - window_size_], p[offset]);
++offset; ++offset;
} }
prog_.current_offset.store(size);
prog_.total_bytes_read.store(total_bytes_read_before + size);
add_data(ino, mm, written, size - written); add_data(ino, mm, written, size - written);
finish_chunk(ino); finish_chunk(ino);
} }

View File

@ -55,6 +55,27 @@ bool is_debug_progress() {
return false; return false;
} }
std::string progress_bar(size_t width, double frac, bool unicode) {
size_t barlen = 8 * width * frac;
size_t w = barlen / 8;
size_t c = barlen % 8;
auto bar = unicode ? uni_bar.data() : asc_bar.data();
std::string rv;
for (size_t i = 0; i < width; ++i) {
if (i == (width - 1)) {
rv.append(bar[0]);
} else if (i == w) {
rv.append(bar[c]);
} else {
rv.append(i < w ? bar[7] : " ");
}
}
return rv;
}
} // namespace } // namespace
console_writer::console_writer(std::ostream& os, progress_mode pg_mode, console_writer::console_writer(std::ostream& os, progress_mode pg_mode,
@ -69,7 +90,8 @@ console_writer::console_writer(std::ostream& os, progress_mode pg_mode,
, mode_(mode) , mode_(mode)
, color_(stream_is_fancy_terminal(os)) , color_(stream_is_fancy_terminal(os))
, with_context_(with_context) , with_context_(with_context)
, debug_progress_(is_debug_progress()) { , debug_progress_(is_debug_progress())
, read_speed_{std::chrono::seconds(5)} {
if (threshold > level_type::INFO) { if (threshold > level_type::INFO) {
set_policy<debug_logger_policy>(); set_policy<debug_logger_policy>();
} else { } else {
@ -83,7 +105,7 @@ void console_writer::rewind() {
switch (mode_) { switch (mode_) {
case NORMAL: case NORMAL:
lines = 8; lines = 9;
break; break;
case REWRITE: case REWRITE:
lines = 4; lines = 4;
@ -175,11 +197,31 @@ void console_writer::update(const progress& p, bool last) {
switch (mode_) { switch (mode_) {
case NORMAL: case NORMAL:
if (writing_) {
read_speed_.put(p.total_bytes_read.load());
} else {
if (p.total_bytes_read.load() > 0) {
read_speed_.clear();
writing_ = true;
} else {
read_speed_.put(p.similarity_bytes.load());
}
}
if (fancy) { if (fancy) {
oss << terminal_colored(p.status(width_), termcolor::BOLD_CYAN, color_) oss << terminal_colored(p.status(width_), termcolor::BOLD_CYAN, color_)
<< newline; << newline;
} }
{
auto cur_size = p.current_size.load();
double cur_offs = std::min(p.current_offset.load(), cur_size);
double cur_frac = cur_size > 0 ? cur_offs / cur_size : 0.0;
oss << progress_bar(64, cur_frac, pg_mode_ == UNICODE)
<< size_with_unit(read_speed_.num_per_second()) << "/s" << newline;
}
oss << p.dirs_scanned << " dirs, " << p.symlinks_scanned << "/" oss << p.dirs_scanned << " dirs, " << p.symlinks_scanned << "/"
<< p.hardlinks << " soft/hard links, " << p.files_scanned << "/" << p.hardlinks << " soft/hard links, " << p.files_scanned << "/"
<< p.files_found << " files, " << p.specials_found << " other" << p.files_found << " files, " << p.specials_found << " other"
@ -244,16 +286,14 @@ void console_writer::update(const progress& p, bool last) {
p.block_count > 0 ? double(p.blocks_written) / p.block_count : 0.0; p.block_count > 0 ? double(p.blocks_written) / p.block_count : 0.0;
double frac = mode_ == NORMAL ? (frac_fs + frac_comp) / 2.0 : frac_comp; double frac = mode_ == NORMAL ? (frac_fs + frac_comp) / 2.0 : frac_comp;
if (last) {
frac = 1.0;
}
if (frac > frac_) { if (frac > frac_) {
frac_ = frac; frac_ = frac;
} }
size_t barlen = 8 * (width_ - 6) * frac_;
size_t w = barlen / 8;
size_t c = barlen % 8;
auto bar = pg_mode_ == UNICODE ? uni_bar.data() : asc_bar.data();
if (pg_mode_ == SIMPLE) { if (pg_mode_ == SIMPLE) {
std::string tmp = std::string tmp =
fmt::format(" ==> {0:.0f}% done, {1} blocks/{2} written", 100 * frac_, fmt::format(" ==> {0:.0f}% done, {1} blocks/{2} written", 100 * frac_,
@ -269,16 +309,8 @@ void console_writer::update(const progress& p, bool last) {
os_ << oss.str(); os_ << oss.str();
} }
} else { } else {
for (size_t i = 0; i < width_ - 6; ++i) { oss << progress_bar(width_ - 6, frac_, pg_mode_ == UNICODE)
if (i == (width_ - 7)) { << fmt::format("{:3.0f}% ", 100 * frac_) << "-\\|/"[counter_ % 4]
oss << bar[0];
} else if (i == w && !last) {
oss << bar[c];
} else {
oss << (i < w ? bar[7] : " ");
}
}
oss << fmt::format("{:3.0f}% ", 100 * frac_) << "-\\|/"[counter_ % 4]
<< '\n'; << '\n';
++counter_; ++counter_;