Commit 939895f for stable-diffusion.cpp

commit 939895f00ecd733e8e9e751b63c39b57d0615123
Author: vmobilis <75476228+vmobilis@users.noreply.github.com>
Date:   Wed Oct 21 18:29:05 2026 +0300

    feat: display remaining time (#2076)

diff --git a/src/core/util.cpp b/src/core/util.cpp
index c1d463e..7bd5c0b 100644
--- a/src/core/util.cpp
+++ b/src/core/util.cpp
@@ -568,50 +568,59 @@ bool parse_strict_bool(const std::string& text, bool& value) {
 }

 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;
+    std::string progress       = "  |";
+    constexpr int max_progress = 50;
+    int32_t current            = 0;
     if (steps > 0) {
-        current = (int32_t)(step * 1.f * max_progress / steps);
+        current = (int32_t)(std::clamp(step, 0, steps) * 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;
-        }
-    }
-    progress += "|";
+    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, ' ') + "|";
     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& eta_text = "") {
     if (step == 0) {
         return;
     }
     std::string progress = build_progress_bar(step, steps, progress_char, show_head);
+    int step_width       = static_cast<int>(std::to_string(steps).size());
     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);
+    printf("\r%s %*i/%i - %10s%s%s\033[K%s", progress.c_str(), step_width, step, steps, speed_text.c_str(),
+           eta_text.empty() ? "" : " - ETA ", eta_text.c_str(), lf);
     fflush(stdout);  // for linux
 }

+static int show_eta      = -1;  // -1 - estimate duration, 0 - hide, 1 - show
+static float passed_time = 0.f;
+
 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) {
+        show_eta    = -1;  // reinitialize for batch generations
+        passed_time = 0.f;
         return;
     }
+    std::string remainder_text = "";
+    if (show_eta && step < steps) {                                     // if timer is not disabled and bar is not filled,
+        if (show_eta == -1 && step)                                     // estimate the total time once, then
+            show_eta = (std::abs(time * steps / step) < 15.f) ? 0 : 1;  // hide the timer if total is less than 15 seconds
+        if (show_eta) {
+            unsigned remainder = (passed_time += time) / step * (steps - step);  // average speed; time*(steps-step) for current
+            remainder_text     = remainder < 3600 ? sd_format("%02u:%02u", remainder / 60, remainder % 60)
+                                                  : sd_format("%u:%02u:%02u", remainder / 3600, (remainder / 60) % 60, remainder % 60);
+        }
+    }
     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) {