From a3250426f3aba40ccb699fb18dda8278a0c2c54c Mon Sep 17 00:00:00 2001 From: vmobilis <75476228+vmobilis@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:35:57 +0300 Subject: [PATCH 1/7] util.cpp: display remaining time --- src/core/util.cpp | 55 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index b90f70ed3f..4e5540ead9 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -550,31 +550,46 @@ bool parse_strict_bool(const std::string& text, bool& value) { return false; } -static std::string build_progress_bar(int step, int steps, char progress_char = '=', bool show_head = true) { - std::string progress = " |"; - int max_progress = 50; - int32_t current = 0; +static std::string build_progress_bar(int step, int steps, char progress_char = '=', bool show_head = true, const std::string& annot_text = "") { + std::string progress = " |"; + constexpr int max_progress = 50; + int32_t current = 0; + int annot_length = annot_text.length(); if (steps > 0) { current = (int32_t)(step * 1.f * max_progress / steps); } - for (int i = 0; i < 50; i++) { - if (i > current) { - progress += " "; - } else if (show_head && i == current && i != max_progress - 1) { - progress += ">"; - } else { - progress += progress_char; + if (step <= steps >> 1) { + for (int i = 0; i < max_progress - annot_length - 2; i++) { + if (i > current) { + progress += " "; + } else if (show_head && i == current && i != max_progress - 1) { + progress += ">"; + } else { + progress += progress_char; + } } + progress += annot_text + " |"; + } else { + progress += std::string(2, progress_char) + annot_text; + for (int i = annot_length + 2; i < max_progress; i++) { + if (i > current) { + progress += " "; + } else if (show_head && i == current && i != max_progress - 1) { + progress += ">"; + } else { + progress += progress_char; + } + } + progress += "|"; } - progress += "|"; return progress; } -static void print_progress_line(int step, int steps, const std::string& speed_text, char progress_char = '=', bool show_head = true) { +static void print_progress_line(int step, int steps, const std::string& speed_text, char progress_char = '=', bool show_head = true, const std::string& annot_text = "") { if (step == 0) { return; } - std::string progress = build_progress_bar(step, steps, progress_char, show_head); + std::string progress = build_progress_bar(step, steps, progress_char, show_head, annot_text); const char* lf = (step == steps ? "\n" : ""); printf("\r%s %i/%i - %s\033[K%s", progress.c_str(), step, steps, speed_text.c_str(), lf); fflush(stdout); // for linux @@ -588,13 +603,23 @@ void pretty_progress(int step, int steps, float time) { if (step == 0) { return; } + std::string remainder_text; + if (step == steps) { + remainder_text = ""; + } else { + float remainder = time * (steps - step); + remainder_text = (remainder < 60.f) ? sd_format(" %.0fs left ", std::min(remainder, 59.f)) + : (remainder < 3600.f) ? sd_format(" %.0fm %02.0fs left ", std::floor(remainder / 60.f), std::min(fmod(remainder, 60.f), 59.f)) + : (remainder < 86400.f) ? sd_format(" %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 3600.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(fmod(remainder, 60.f), 59.f)) + : sd_format(" %.0fd %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 86400.f), std::fmod(std::floor(remainder / 3600.f), 24.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(fmod(remainder, 60.f), 59.f)); + } const char* unit = "s/it"; float speed = time; if (speed < 1.0f && speed > 0.f) { speed = 1.0f / speed; unit = "it/s"; } - print_progress_line(step, steps, sd_format("%.2f%s", speed, unit)); + print_progress_line(step, steps, sd_format("%.2f%s", speed, unit), '=', true, remainder_text); } void pretty_bytes_progress(int step, int steps, uint64_t bytes_processed, float elapsed_seconds) { From 1ce17cc1cc5a88fcec58551280cb3b401f6da710 Mon Sep 17 00:00:00 2001 From: vmobilis <75476228+vmobilis@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:21:30 +0300 Subject: [PATCH 2/7] fix: use std::fmod --- src/core/util.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index 4e5540ead9..14bb050e91 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -609,9 +609,9 @@ void pretty_progress(int step, int steps, float time) { } else { float remainder = time * (steps - step); remainder_text = (remainder < 60.f) ? sd_format(" %.0fs left ", std::min(remainder, 59.f)) - : (remainder < 3600.f) ? sd_format(" %.0fm %02.0fs left ", std::floor(remainder / 60.f), std::min(fmod(remainder, 60.f), 59.f)) - : (remainder < 86400.f) ? sd_format(" %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 3600.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(fmod(remainder, 60.f), 59.f)) - : sd_format(" %.0fd %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 86400.f), std::fmod(std::floor(remainder / 3600.f), 24.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(fmod(remainder, 60.f), 59.f)); + : (remainder < 3600.f) ? sd_format(" %.0fm %02.0fs left ", std::floor(remainder / 60.f), std::min(std::fmod(remainder, 60.f), 59.f)) + : (remainder < 86400.f) ? sd_format(" %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 3600.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.f)) + : sd_format(" %.0fd %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 86400.f), std::fmod(std::floor(remainder / 3600.f), 24.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.f)); } const char* unit = "s/it"; float speed = time; From d1b39a72ae83beefb8f171f2e5cba569272c6be8 Mon Sep 17 00:00:00 2001 From: vmobilis <75476228+vmobilis@users.noreply.github.com> Date: Tue, 29 Sep 2026 12:11:43 +0300 Subject: [PATCH 3/7] util.cpp: hide counter for short generations --- src/core/util.cpp | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index 14bb050e91..7c7c0a8af1 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -558,7 +558,13 @@ static std::string build_progress_bar(int step, int steps, char progress_char = if (steps > 0) { current = (int32_t)(step * 1.f * max_progress / steps); } - if (step <= steps >> 1) { + if (!annot_length) { + int head_length = (current == max_progress) ? 0 : 1; + progress += std::string(current, progress_char) // + + std::string(head_length, show_head ? '>' : progress_char) // + + std::string(max_progress - current - head_length, ' ') // + + "|"; + } else if (step <= steps >> 1) { for (int i = 0; i < max_progress - annot_length - 2; i++) { if (i > current) { progress += " "; @@ -595,23 +601,41 @@ static void print_progress_line(int step, int steps, const std::string& speed_te fflush(stdout); // for linux } +int hide_annot = -1; // -1 - check, 0 - show, 1 - hide +float passed_time = 0.f; +#define PRETTY_PRECISE_TIME 0 // 0/1 for integer/rational seconds + void pretty_progress(int step, int steps, float time) { if (sd_progress_cb) { sd_progress_cb(step, steps, time, sd_progress_cb_data); return; } if (step == 0) { + hide_annot = -1; // reinitialize for batch generations + passed_time = 0.f; return; } std::string remainder_text; - if (step == steps) { + if (hide_annot == 1 || step == steps) { remainder_text = ""; - } else { - float remainder = time * (steps - step); - remainder_text = (remainder < 60.f) ? sd_format(" %.0fs left ", std::min(remainder, 59.f)) - : (remainder < 3600.f) ? sd_format(" %.0fm %02.0fs left ", std::floor(remainder / 60.f), std::min(std::fmod(remainder, 60.f), 59.f)) - : (remainder < 86400.f) ? sd_format(" %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 3600.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.f)) - : sd_format(" %.0fd %.0fh %02.0fm %02.0fs left ", std::floor(remainder / 86400.f), std::fmod(std::floor(remainder / 3600.f), 24.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.f)); + } else { // either check the duration or make the string + if (step == 1) // estimate the total time once + hide_annot = (time * steps < 15.f) ? 1 : 0; // hide the timer if total is less than 15 seconds +#if PRETTY_PRECISE_TIME + float remainder = (passed_time += time) / step * (steps - step); // average speed; time*(steps-step) for current + remainder_text = hide_annot ? "" // for the 1st step, because it will be evaluated always + : (remainder < 60.f) ? sd_format(" %.1fs left ", std::min(remainder, 59.9f)) + : (remainder < 3600.f) ? sd_format(" %.0fm %04.1fs left ", std::floor(remainder / 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)) + : (remainder < 86400.f) ? sd_format(" %.0fh %02.0fm %04.1fs left ", std::floor(remainder / 3600.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)) + : sd_format(" %.0fd %2.0fh %02.0fm %04.1fs left ", std::floor(remainder / 86400.f), std::fmod(std::floor(remainder / 3600.f), 24.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)); +#else + unsigned remainder = (passed_time += time) / step * (steps - step); // average speed; time*(steps-step) for current + remainder_text = hide_annot ? "" + : (remainder < 60) ? sd_format(" %us left ", remainder) + : (remainder < 3600) ? sd_format(" %um %02us left ", remainder / 60, remainder % 60) + : (remainder < 86400) ? sd_format(" %uh %02um %02us left ", remainder / 3600, (remainder / 60) % 60, remainder % 60) + : sd_format(" %ud %2uh %02um %02us left ", remainder / 86400, (remainder / 3600) % 24, (remainder / 60) % 60, remainder % 60); +#endif } const char* unit = "s/it"; float speed = time; From f1c8412160aa4785afe04d4f1c812a9d839c496e Mon Sep 17 00:00:00 2001 From: vmobilis <75476228+vmobilis@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:49:43 +0300 Subject: [PATCH 4/7] util.cpp: allow to start from arbitrary step --- src/core/util.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index 7c7c0a8af1..22e0cba088 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -601,8 +601,8 @@ static void print_progress_line(int step, int steps, const std::string& speed_te fflush(stdout); // for linux } -int hide_annot = -1; // -1 - check, 0 - show, 1 - hide -float passed_time = 0.f; +static int hide_annot = -1; // -1 - check, 0 - show, 1 - hide +static float passed_time = 0.f; #define PRETTY_PRECISE_TIME 0 // 0/1 for integer/rational seconds void pretty_progress(int step, int steps, float time) { @@ -618,9 +618,9 @@ void pretty_progress(int step, int steps, float time) { std::string remainder_text; if (hide_annot == 1 || step == steps) { remainder_text = ""; - } else { // either check the duration or make the string - if (step == 1) // estimate the total time once - hide_annot = (time * steps < 15.f) ? 1 : 0; // hide the timer if total is less than 15 seconds + } else { // either check the duration or make the string + if (hide_annot == -1 && step > 0) // estimate the total time once + hide_annot = (std::abs(time * steps / step) < 15.f) ? 1 : 0; // hide the timer if total is less than 15 seconds #if PRETTY_PRECISE_TIME float remainder = (passed_time += time) / step * (steps - step); // average speed; time*(steps-step) for current remainder_text = hide_annot ? "" // for the 1st step, because it will be evaluated always From 4693ff2b508c55e0bcce490a85083e2329affad0 Mon Sep 17 00:00:00 2001 From: vmobilis <75476228+vmobilis@users.noreply.github.com> Date: Fri, 16 Oct 2026 19:46:30 +0300 Subject: [PATCH 5/7] Clarification --- src/core/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index 22e0cba088..da66a15494 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -601,7 +601,7 @@ static void print_progress_line(int step, int steps, const std::string& speed_te fflush(stdout); // for linux } -static int hide_annot = -1; // -1 - check, 0 - show, 1 - hide +static int hide_annot = -1; // -1 - estimate duration, 0 - show, 1 - hide static float passed_time = 0.f; #define PRETTY_PRECISE_TIME 0 // 0/1 for integer/rational seconds From e3130bd9c63f1e5b55630f669187a52755114e03 Mon Sep 17 00:00:00 2001 From: vmobilis <75476228+vmobilis@users.noreply.github.com> Date: Fri, 16 Oct 2026 21:59:11 +0300 Subject: [PATCH 6/7] Simplification Avoid inverted logic and uninitialized annotation. --- src/core/util.cpp | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index da66a15494..bab53ba7dc 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -601,7 +601,7 @@ static void print_progress_line(int step, int steps, const std::string& speed_te fflush(stdout); // for linux } -static int hide_annot = -1; // -1 - estimate duration, 0 - show, 1 - hide +static int show_annot = -1; // -1 - estiimate duration, 0 - hide, 1 - show static float passed_time = 0.f; #define PRETTY_PRECISE_TIME 0 // 0/1 for integer/rational seconds @@ -611,31 +611,29 @@ void pretty_progress(int step, int steps, float time) { return; } if (step == 0) { - hide_annot = -1; // reinitialize for batch generations + show_annot = -1; // reinitialize for batch generations passed_time = 0.f; return; } - std::string remainder_text; - if (hide_annot == 1 || step == steps) { - remainder_text = ""; - } else { // either check the duration or make the string - if (hide_annot == -1 && step > 0) // estimate the total time once - hide_annot = (std::abs(time * steps / step) < 15.f) ? 1 : 0; // hide the timer if total is less than 15 seconds + std::string remainder_text = ""; + if (show_annot && step != steps) { // if timer is not disabled and bar is not filled, + if (show_annot == -1 && step) // estimate the total time once, then + show_annot = (std::abs(time * steps / step) < 15.f) ? 0 : 1; // hide the timer if total is less than 15 seconds + if (show_annot) { #if PRETTY_PRECISE_TIME - float remainder = (passed_time += time) / step * (steps - step); // average speed; time*(steps-step) for current - remainder_text = hide_annot ? "" // for the 1st step, because it will be evaluated always - : (remainder < 60.f) ? sd_format(" %.1fs left ", std::min(remainder, 59.9f)) - : (remainder < 3600.f) ? sd_format(" %.0fm %04.1fs left ", std::floor(remainder / 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)) - : (remainder < 86400.f) ? sd_format(" %.0fh %02.0fm %04.1fs left ", std::floor(remainder / 3600.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)) - : sd_format(" %.0fd %2.0fh %02.0fm %04.1fs left ", std::floor(remainder / 86400.f), std::fmod(std::floor(remainder / 3600.f), 24.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)); + float remainder = (passed_time += time) / step * (steps - step); // average speed; time*(steps-step) for current + remainder_text = (remainder < 60.f) ? sd_format(" %.1fs left ", std::min(remainder, 59.9f)) + : (remainder < 3600.f) ? sd_format(" %.0fm %04.1fs left ", std::floor(remainder / 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)) + : (remainder < 86400.f) ? sd_format(" %.0fh %02.0fm %04.1fs left ", std::floor(remainder / 3600.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)) + : sd_format(" %.0fd %2.0fh %02.0fm %04.1fs left ", std::floor(remainder / 86400.f), std::fmod(std::floor(remainder / 3600.f), 24.f), std::fmod(std::floor(remainder / 60.f), 60.f), std::min(std::fmod(remainder, 60.f), 59.9f)); #else - unsigned remainder = (passed_time += time) / step * (steps - step); // average speed; time*(steps-step) for current - remainder_text = hide_annot ? "" - : (remainder < 60) ? sd_format(" %us left ", remainder) - : (remainder < 3600) ? sd_format(" %um %02us left ", remainder / 60, remainder % 60) - : (remainder < 86400) ? sd_format(" %uh %02um %02us left ", remainder / 3600, (remainder / 60) % 60, remainder % 60) - : sd_format(" %ud %2uh %02um %02us left ", remainder / 86400, (remainder / 3600) % 24, (remainder / 60) % 60, remainder % 60); + unsigned remainder = (passed_time += time) / step * (steps - step); // average speed; time*(steps-step) for current + remainder_text = (remainder < 60) ? sd_format(" %us left ", remainder) + : (remainder < 3600) ? sd_format(" %um %02us left ", remainder / 60, remainder % 60) + : (remainder < 86400) ? sd_format(" %uh %02um %02us left ", remainder / 3600, (remainder / 60) % 60, remainder % 60) + : sd_format(" %ud %2uh %02um %02us left ", remainder / 86400, (remainder / 3600) % 24, (remainder / 60) % 60, remainder % 60); #endif + } } const char* unit = "s/it"; float speed = time; From 3128d7a4aba54485d9dcf9600da394cbd19083c2 Mon Sep 17 00:00:00 2001 From: vmobilis <75476228+vmobilis@users.noreply.github.com> Date: Sat, 17 Oct 2026 01:51:03 +0300 Subject: [PATCH 7/7] Avoid `step > steps` condition As @coderabbitai noted, it will produce negative remaining time. --- src/core/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/util.cpp b/src/core/util.cpp index bab53ba7dc..71b62d5c19 100644 --- a/src/core/util.cpp +++ b/src/core/util.cpp @@ -616,7 +616,7 @@ void pretty_progress(int step, int steps, float time) { return; } std::string remainder_text = ""; - if (show_annot && step != steps) { // if timer is not disabled and bar is not filled, + if (show_annot && step < steps) { // if timer is not disabled and bar is not filled, if (show_annot == -1 && step) // estimate the total time once, then show_annot = (std::abs(time * steps / step) < 15.f) ? 0 : 1; // hide the timer if total is less than 15 seconds if (show_annot) {