patch: better progress meter

Wayne Davison wayned at samba.org
Fri Feb 27 21:13:48 GMT 2004


On Fri, Feb 27, 2004 at 08:07:22PM +0200, Timo Sirainen wrote:
> Recently I figured out that rsync -P can be nicely used as resuming 
> scp. Only thing annoying me was that the kB/s and time left estimates 
> showed completely wrong values when resuming files. 

Yes, this had been mentioned before, but you were kind enough to include
a patch -- much appreciated!

I took your updated version and tweaked it a bit.  We still need to keep
track of the start info so that the final output shows the rate for the
entire transfer (or, at least, that's what I want it to show, since it's
showing the elapsed time for the entire transfer).

Attached is my modified version of your patch.  It applies to the CVS
version.

..wayne..
-------------- next part --------------
--- progress.c	27 Jan 2004 06:51:39 -0000	1.7
+++ progress.c	27 Feb 2004 21:06:36 -0000
@@ -24,14 +24,20 @@
 extern struct stats stats;
 extern int am_server;
 
-static OFF_T  last_ofs;
-static struct timeval print_time;
-static struct timeval start_time;
-static OFF_T  start_ofs;
+#define PROGRESS_HISTORY_SECS 5
+
+struct progress_history {
+	struct timeval time;
+	OFF_T ofs;
+};
+
+static struct progress_history h_start;
+static struct progress_history h_list[PROGRESS_HISTORY_SECS];
+static int newest_hpos, oldest_hpos;
 
 static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
 {
-	return (t2->tv_sec - t1->tv_sec) * 1000
+	return (t2->tv_sec - t1->tv_sec) * 1000L
 	     + (t2->tv_usec - t1->tv_usec) / 1000;
 }
 
@@ -47,19 +53,28 @@ static void rprint_progress(OFF_T ofs, O
 			    int is_last)
 {
 	char eol[256];
-	int pct = (ofs == size) ? 100 : (int)((100.0*ofs)/size);
-	unsigned long diff = msdiff(&start_time, now);
-	double rate = diff ? (double) (ofs-start_ofs) * 1000.0 / diff / 1024.0 : 0;
 	const char *units;
-	/* If we've finished transferring this file, show the time taken;
-	 * otherwise show expected time to complete.  That's kind of
-	 * inconsistent, but people can probably cope.  Hopefully we'll
-	 * get more consistent and complete progress reporting soon. --
-	 * mbp */
-	double remain = is_last ? (double) diff / 1000.0
-	              : rate ? (double) (size-ofs) / rate / 1000.0 : 0.0;
+	int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
+	unsigned long diff;
+	double rate, remain;
 	int remain_h, remain_m, remain_s;
 
+	if (is_last) {
+		/* Compute stats based on the starting info. */
+		diff = msdiff(&h_start.time, now);
+		if (!diff)
+			diff = 1;
+		rate = (double) (ofs - h_start.ofs) * 1000.0 / diff / 1024.0;
+		/* Switch to total time taken for our last update. */
+		remain = (double) diff / 1000.0;
+	} else {
+		/* Compute stats based on recent progress. */
+		diff = msdiff(&h_list[oldest_hpos].time, now);
+		rate = diff ? (double) (ofs - h_list[oldest_hpos].ofs) * 1000.0
+		    / diff / 1024.0 : 0;
+		remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
+	}
+
 	if (rate > 1024*1024) {
 		rate /= 1024.0 * 1024.0;
 		units = "GB/s";
@@ -94,34 +109,38 @@ void end_progress(OFF_T size)
 		gettimeofday(&now, NULL);
 		rprint_progress(size, size, &now, True);
 	}
-	last_ofs = 0;
-	start_ofs = 0;
-	print_time.tv_sec = print_time.tv_usec = 0;
-	start_time.tv_sec = start_time.tv_usec = 0;
+	memset(&h_start, 0, sizeof h_start);
 }
 
 void show_progress(OFF_T ofs, OFF_T size)
 {
 	struct timeval now;
 
-	if (!start_time.tv_sec) {
-		gettimeofday(&now, NULL);
-		start_time.tv_sec = now.tv_sec;
-		start_time.tv_usec = now.tv_usec;
-		start_ofs = ofs;
-		if (am_server)
-			return;
+	if (am_server)
+		return;
+
+	gettimeofday(&now, NULL);
+
+	if (!h_start.time.tv_sec) {
+		int i;
+
+		h_start.time.tv_sec = now.tv_sec;
+		h_start.time.tv_usec = now.tv_usec;
+		h_start.ofs = ofs;
+
+		for (i = 0; i < PROGRESS_HISTORY_SECS; i++)
+			h_list[i] = h_start;
 	}
 	else {
-		if (am_server)
+		if (msdiff(&h_list[newest_hpos].time, &now) < 1000)
 			return;
-		gettimeofday(&now, NULL);
-	}
 
-	if (ofs > last_ofs + 1000 && msdiff(&print_time, &now) > 250) {
-		rprint_progress(ofs, size, &now, False);
-		last_ofs = ofs;
-		print_time.tv_sec = now.tv_sec;
-		print_time.tv_usec = now.tv_usec;
+		newest_hpos = oldest_hpos;
+		oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS;
+		h_list[newest_hpos].time.tv_sec = now.tv_sec;
+		h_list[newest_hpos].time.tv_usec = now.tv_usec;
+		h_list[newest_hpos].ofs = ofs;
 	}
+
+	rprint_progress(ofs, size, &now, False);
 }


More information about the rsync mailing list