Commit cf84d51c authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Junio C Hamano

add throughput to progress display

This adds the ability for the progress code to also display transfer
throughput when that makes sense.

The math was inspired by commit c548cf4e
from Linus.
Signed-off-by: default avatarNicolas Pitre <nico@cam.org>
Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
parent 4d4fcc54
#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);
}
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment