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@xxxxxxx> --- progress.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- progress.h | 1 + 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/progress.c b/progress.c index 7f9b00e..23ee9f3 100644 --- a/progress.c +++ b/progress.c @@ -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); } diff --git a/progress.h b/progress.h index 29780ce..7902ca5 100644 --- a/progress.h +++ b/progress.h @@ -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, -- 1.5.3.4.1463.gf79ad2 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html