add throughput to progress display
authorNicolas Pitre <nico@cam.org>
Tue, 30 Oct 2007 18:57:34 +0000 (14:57 -0400)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 Oct 2007 23:08:40 +0000 (16:08 -0700)
This adds the ability for the progress code to also display transfer
throughput when that makes sense.

The math was inspired by commit c548cf4ee0737a321ffe94f6a97c65baf87281be
from Linus.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
progress.c
progress.h

index c342e39c5d2e5673fc95e0cdc91856b0bc3cdd35..15197fbe6c1bbf1159252026a97baf1ea64c433a 100644 (file)
@@ -1,6 +1,19 @@
 #include "git-compat-util.h"
 #include "progress.h"
 
+#define TP_IDX_MAX      8
+
+struct throughput {
+       struct timeval prev_tv;
+       unsigned long count;
+       unsigned long avg_bytes;
+       unsigned long last_bytes[TP_IDX_MAX];
+       unsigned int avg_misecs;
+       unsigned int last_misecs[TP_IDX_MAX];
+       unsigned int idx;
+       char display[20];
+};
+
 struct progress {
        const char *title;
        int last_value;
@@ -8,6 +21,7 @@ struct progress {
        unsigned last_percent;
        unsigned delay;
        unsigned delayed_percent_treshold;
+       struct throughput *throughput;
 };
 
 static volatile sig_atomic_t progress_update;
@@ -46,7 +60,7 @@ static void clear_progress_signal(void)
 
 static int display(struct progress *progress, unsigned n, int done)
 {
-       char *eol;
+       char *eol, *tp;
 
        if (progress->delay) {
                if (!progress_update || --progress->delay)
@@ -64,18 +78,20 @@ static int display(struct progress *progress, unsigned n, int done)
        }
 
        progress->last_value = n;
+       tp = (progress->throughput) ? progress->throughput->display : "";
        eol = done ? ", done.   \n" : "   \r";
        if (progress->total) {
                unsigned percent = n * 100 / progress->total;
                if (percent != progress->last_percent || progress_update) {
                        progress->last_percent = percent;
-                       fprintf(stderr, "%s: %3u%% (%u/%u)%s", progress->title,
-                               percent, n, progress->total, eol);
+                       fprintf(stderr, "%s: %3u%% (%u/%u)%s%s",
+                               progress->title, percent, n,
+                               progress->total, tp, eol);
                        progress_update = 0;
                        return 1;
                }
        } else if (progress_update) {
-               fprintf(stderr, "%s: %u%s", progress->title, n, eol);
+               fprintf(stderr, "%s: %u%s%s", progress->title, n, tp, eol);
                progress_update = 0;
                return 1;
        }
@@ -83,6 +99,60 @@ static int display(struct progress *progress, unsigned n, int done)
        return 0;
 }
 
+void display_throughput(struct progress *progress, unsigned long n)
+{
+       struct throughput *tp;
+       struct timeval tv;
+       unsigned int misecs;
+
+       if (!progress)
+               return;
+       tp = progress->throughput;
+
+       gettimeofday(&tv, NULL);
+
+       if (!tp) {
+               progress->throughput = tp = calloc(1, sizeof(*tp));
+               if (tp)
+                       tp->prev_tv = tv;
+               return;
+       }
+
+       tp->count += n;
+
+       /*
+        * We have x = bytes and y = microsecs.  We want z = KiB/s:
+        *
+        *      z = (x / 1024) / (y / 1000000)
+        *      z = x / y * 1000000 / 1024
+        *      z = x / (y * 1024 / 1000000)
+        *      z = x / y'
+        *
+        * To simplify things we'll keep track of misecs, or 1024th of a sec
+        * obtained with:
+        *
+        *      y' = y * 1024 / 1000000
+        *      y' = y / (1000000 / 1024)
+        *      y' = y / 977
+        */
+       misecs = (tv.tv_sec - tp->prev_tv.tv_sec) * 1024;
+       misecs += (int)(tv.tv_usec - tp->prev_tv.tv_usec) / 977;
+
+       if (misecs > 512) {
+               tp->prev_tv = tv;
+               tp->avg_bytes += tp->count;
+               tp->avg_misecs += misecs;
+               snprintf(tp->display, sizeof(tp->display),
+                        ", %lu KiB/s", tp->avg_bytes / tp->avg_misecs);
+               tp->avg_bytes -= tp->last_bytes[tp->idx];
+               tp->avg_misecs -= tp->last_misecs[tp->idx];
+               tp->last_bytes[tp->idx] = tp->count;
+               tp->last_misecs[tp->idx] = misecs;
+               tp->idx = (tp->idx + 1) % TP_IDX_MAX;
+               tp->count = 0;
+       }
+}
+
 int display_progress(struct progress *progress, unsigned n)
 {
        return progress ? display(progress, n, 0) : 0;
@@ -103,6 +173,7 @@ struct progress *start_progress_delay(const char *title, unsigned total,
        progress->last_percent = -1;
        progress->delayed_percent_treshold = percent_treshold;
        progress->delay = delay;
+       progress->throughput = NULL;
        set_progress_signal();
        return progress;
 }
@@ -124,5 +195,6 @@ void stop_progress(struct progress **p_progress)
                display(progress, progress->last_value, 1);
        }
        clear_progress_signal();
+       free(progress->throughput);
        free(progress);
 }
index 4c6d53524b5ebc6bec4fd4c569776802816dfdbc..61cb68dfa512bb3668d7e6060262041937aa82d3 100644 (file)
@@ -3,6 +3,7 @@
 
 struct progress;
 
+void display_throughput(struct progress *progress, unsigned long n);
 int display_progress(struct progress *progress, unsigned n);
 struct progress *start_progress(const char *title, unsigned total);
 struct progress *start_progress_delay(const char *title, unsigned total,