[PATCH 4/5] add throughput to progress display

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux