7std::string format_seconds(
double seconds) {
8 std::ostringstream oss;
10 oss << std::fixed << std::setprecision(1) << seconds <<
"s";
11 }
else if (seconds < 3600.0) {
12 const int minutes =
static_cast<int>(seconds / 60.0);
13 const int sec =
static_cast<int>(seconds) % 60;
14 oss << minutes <<
"m" << std::setw(2) << std::setfill(
'0')
15 << sec << std::setfill(
' ') <<
"s";
17 const int hours =
static_cast<int>(seconds / 3600.0);
18 const int minutes = (
static_cast<int>(seconds) / 60) % 60;
19 const int sec =
static_cast<int>(seconds) % 60;
21 << std::setw(2) << std::setfill(
'0') << minutes <<
"m"
22 << std::setw(2) << std::setfill(
'0') << sec
23 << std::setfill(
' ') <<
"s";
31 std::lock_guard<std::mutex> lock(mutex_);
33 latest_.
phase = phase;
39 std::lock_guard<std::mutex> lock(mutex_);
40 event.fraction = std::clamp(event.
fraction, 0.0, 1.0);
41 event.sequence = next_sequence_++;
42 latest_ = std::move(event);
46 std::lock_guard<std::mutex> lock(mutex_);
52 std::size_t probe_draws,
53 std::size_t update_every,
56 std::string item_label,
57 std::shared_ptr<StatisticProgressMonitor> monitor,
59 : enabled_(enabled), total_(total), probe_draws_(probe_draws == 0 ? 1 : probe_draws),
60 update_every_(update_every == 0 ? 1 : update_every), os_(&os),
61 start_(
std::chrono::steady_clock::now()), label_(
std::move(label)),
62 item_label_(
std::move(item_label)), monitor_(
std::move(monitor)), phase_(
std::move(phase))
64 publish(0, 0, 0,
false,
"Starting Monte-Carlo sampling");
67double StatisticProgressReporter::elapsed_seconds()
const {
68 return std::chrono::duration<double>(std::chrono::steady_clock::now() - start_).count();
71double StatisticProgressReporter::eta_seconds(std::size_t accepted_count)
const {
72 if (accepted_count == 0 || accepted_count < probe_draws_ || accepted_count >= total_)
return -1.0;
73 return (elapsed_seconds() /
static_cast<double>(accepted_count)) *
static_cast<double>(total_ - accepted_count);
76std::string StatisticProgressReporter::bar(std::size_t accepted_count)
const {
77 constexpr std::size_t width = 28;
78 const double raw_frac = total_ == 0 ? 1.0 :
static_cast<double>(accepted_count) /
static_cast<double>(total_);
79 const double frac = std::clamp(raw_frac, 0.0, 1.0);
80 const std::size_t filled =
static_cast<std::size_t
>(frac * width);
82 for (std::size_t i = 0; i < width; ++i) out.push_back(i < filled ?
'#' :
'.');
87std::string StatisticProgressReporter::eta_string(std::size_t accepted_count)
const {
88 const double eta = eta_seconds(accepted_count);
89 return eta < 0.0 ?
"estimating" : format_seconds(eta);
92void StatisticProgressReporter::publish(std::size_t accepted_count,
96 const std::string& message) {
97 if (!monitor_)
return;
105 ev.
fraction = total_ == 0 ? 1.0 :
static_cast<double>(accepted_count) /
static_cast<double>(total_);
107 ev.
eta_seconds = finished ? 0.0 : eta_seconds(accepted_count);
109 monitor_->update(std::move(ev));
113 if (!enabled_ && !monitor_)
return;
114 if (total_ == 0)
return;
115 if (accepted_count != total_ && accepted_count % update_every_ != 0 && accepted_count != probe_draws_)
return;
117 if (attempts == 0) attempts = accepted_count;
118 publish(accepted_count, attempts, failures,
false,
119 label_ +
": " + std::to_string(accepted_count) +
"/" + std::to_string(total_) +
" " + item_label_);
120 if (!enabled_)
return;
121 const double pct = 100.0 *
static_cast<double>(accepted_count) /
static_cast<double>(total_);
122 (*os_) <<
"\r\033[K[" << label_ <<
"] " << bar(accepted_count)
123 <<
" " << accepted_count <<
"/" << total_ <<
" " << item_label_
124 <<
" (" << std::fixed << std::setprecision(1) << pct <<
"%)"
125 <<
" | ETA " << eta_string(accepted_count) << std::flush;
129 publish(accepted_count, attempts, failures,
true,
130 label_ +
" completed: " + std::to_string(accepted_count) +
"/" + std::to_string(total_) +
" " + item_label_);
131 if (!enabled_)
return;
132 (*os_) <<
"\r\033[K[" << label_ <<
"] " << bar(accepted_count)
133 <<
" " << accepted_count <<
"/" << total_ <<
" " << item_label_
134 <<
" completed in " << format_seconds(elapsed_seconds())
135 <<
" (attempts=" << attempts <<
", rejected=" << failures <<
")\n";
140 std::size_t total_steps,
142 std::shared_ptr<StatisticProgressMonitor> monitor,
144 : enabled_(enabled), label_(
std::move(label)), total_steps_(total_steps == 0 ? 1 : total_steps),
145 os_(&os), start_(
std::chrono::steady_clock::now()), monitor_(
std::move(monitor)), phase_(
std::move(phase)) {}
147std::string StatisticStageProgressReporter::bar(std::size_t completed_steps)
const {
148 constexpr std::size_t width = 28;
149 const double frac = std::clamp(
static_cast<double>(completed_steps) /
static_cast<double>(total_steps_), 0.0, 1.0);
150 const std::size_t filled =
static_cast<std::size_t
>(frac * width);
151 std::string out(
"[");
152 for (std::size_t i = 0; i < width; ++i) out.push_back(i < filled ?
'#' :
'.');
157double StatisticStageProgressReporter::elapsed_seconds()
const {
158 return std::chrono::duration<double>(std::chrono::steady_clock::now() - start_).count();
161std::string StatisticStageProgressReporter::elapsed_string()
const {
return format_seconds(elapsed_seconds()); }
163void StatisticStageProgressReporter::publish(std::size_t completed_steps,
const std::string& message,
bool finished) {
164 if (!monitor_)
return;
168 ev.
completed = std::min(completed_steps, total_steps_);
169 ev.
total = total_steps_;
170 ev.
fraction =
static_cast<double>(ev.
completed) /
static_cast<double>(total_steps_);
177 monitor_->update(std::move(ev));
181 publish(0, message,
false);
182 if (enabled_) (*os_) <<
"[" << label_ <<
"] " << message <<
'\n';
186 publish(completed_steps, message,
false);
187 if (!enabled_)
return;
188 const std::size_t shown = std::min(completed_steps, total_steps_);
189 (*os_) <<
"[" << label_ <<
"] " << bar(shown) <<
" " << shown <<
"/" << total_steps_
190 <<
" | " << message <<
" | elapsed " << elapsed_string() <<
'\n';
194 publish(total_steps_, message,
true);
195 if (enabled_) (*os_) <<
"[" << label_ <<
"] " << bar(total_steps_) <<
" " << total_steps_ <<
"/" << total_steps_
196 <<
" | " << message <<
" | total " << elapsed_string() <<
'\n';
void update(StatisticProgressEvent event)
StatisticProgressEvent snapshot() const
void reset(const std::string &phase="preparing", const std::string &message="Preparing statistic workflow")
void accepted(std::size_t accepted_count, std::size_t attempts=0, std::size_t failures=0)
StatisticProgressReporter(bool enabled, std::size_t total, std::size_t probe_draws=5, std::size_t update_every=1, std::ostream &os=std::cout, std::string label="Monte-Carlo", std::string item_label="accepted", std::shared_ptr< StatisticProgressMonitor > monitor=nullptr, std::string phase="monte_carlo")
void finish(std::size_t accepted_count, std::size_t attempts, std::size_t failures)
void finish(const std::string &message)
StatisticStageProgressReporter(bool enabled, std::string label, std::size_t total_steps, std::ostream &os=std::cout, std::shared_ptr< StatisticProgressMonitor > monitor=nullptr, std::string phase="chi2_pipeline")
void start(const std::string &message)
void step(std::size_t completed_steps, const std::string &message)
Hash specialization for SymbolId<Tag>.