Print average download speed for multi-file downloads

Hrvoje Niksic <[email protected]> Sun, 26 Jun 2005 02:17:53 +0200
Newsgroups gmane.comp.web.wget.patches
Message-ID <[email protected]>
This patch adds output like this one:

FINISHED --02:04:40--
Downloaded: 2 files, 354K in 9s (38.61 KB/s)

It also changes the "ETA" information at the end of the download to
indicate how long the download took:

100%[=====================================>] 10,926,430    39.31K/s   in 4m 33s


2005-06-26  Hrvoje Niksic  <[email protected]>

	* main.c (main): Ditto here.

	* progress.c (create_image): When the download is finished, print
	how long it took.

Index: src/http.c
===================================================================
--- src/http.c	(revision 1827)
+++ src/http.c	(working copy)
@@ -59,7 +59,6 @@
 #include "convert.h"
 
 extern char *version_string;
-extern SUM_SIZE_INT total_downloaded_bytes;
 
 extern FILE *output_stream;
 extern bool output_stream_regular;
@@ -1970,7 +1969,8 @@
   bool use_ts, got_head = false;/* time-stamping info */
   char *filename_plus_orig_suffix;
   char *local_filename = NULL;
-  char *tms, *locf, *tmrate;
+  char *tms, *locf;
+  const char *tmrate;
   uerr_t err;
   time_t tml = -1, tmr = -1;	/* local and remote time-stamps */
   wgint local_size = 0;		/* the size of the local file */
@@ -2360,7 +2360,8 @@
 	  return RETROK;
 	}
 
-      tmrate = retr_rate (hstat.rd_size, hstat.dltime, 0);
+      tmrate = retr_rate (hstat.rd_size, hstat.dltime);
+      total_download_time += hstat.dltime;
 
       if (hstat.len == hstat.contlen)
 	{
Index: src/ftp.c
===================================================================
--- src/ftp.c	(revision 1827)
+++ src/ftp.c	(working copy)
@@ -50,8 +50,6 @@
 #include "convert.h"		/* for downloaded_file */
 #include "recur.h"		/* for INFINITE_RECURSION */
 
-extern SUM_SIZE_INT total_downloaded_bytes;
-
 /* File where the "ls -al" listing will be saved.  */
 #define LIST_FILENAME ".listing"
 
@@ -240,7 +238,8 @@
   uerr_t err = RETROK;		/* appease the compiler */
   FILE *fp;
   char *user, *passwd, *respline;
-  char *tms, *tmrate;
+  char *tms;
+  const char *tmrate;
   int cmd = con->cmd;
   bool pasv_mode_open = false;
   wgint expected_bytes = 0;
@@ -585,7 +584,7 @@
   else /* do not CWD */
     logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
 
-  if ((cmd & DO_RETR) && restval && *len == 0)
+  if ((cmd & DO_RETR) && *len == 0)
     {
       if (opt.verbose)
 	{
@@ -598,7 +597,7 @@
       switch (err)
 	{
 	case FTPRERR:
-	case FTPSRVERR :
+	case FTPSRVERR:
 	  logputs (LOG_VERBOSE, "\n");
 	  logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
@@ -612,7 +611,8 @@
 	  abort ();
 	}
 	if (!opt.server_response)
-	  logputs (LOG_VERBOSE, _("done.\n"));
+	  logprintf (LOG_VERBOSE, *len ? "%s\n" : _("done.\n"),
+		     number_to_static_string (*len));
     }
 
   /* If anything is to be retrieved, PORT (or PASV) must be sent.  */
@@ -975,7 +975,9 @@
 		      restval, &rd_size, len, &con->dltime, flags);
 
   tms = time_str (NULL);
-  tmrate = retr_rate (rd_size, con->dltime, 0);
+  tmrate = retr_rate (rd_size, con->dltime);
+  total_download_time += con->dltime;
+
   /* Close data connection socket.  */
   fd_close (dtsock);
   fd_close (local_sock);
@@ -1092,7 +1094,7 @@
   int count, orig_lp;
   wgint restval, len = 0;
   char *tms, *locf;
-  char *tmrate = NULL;
+  const char *tmrate = NULL;
   uerr_t err;
   struct_stat st;
 
@@ -1228,7 +1230,7 @@
 	}
       tms = time_str (NULL);
       if (!opt.spider)
-        tmrate = retr_rate (len - restval, con->dltime, 0);
+        tmrate = retr_rate (len - restval, con->dltime);
 
       /* If we get out of the switch above without continue'ing, we've
 	 successfully downloaded a file.  Remember this fact. */
Index: src/progress.c
===================================================================
--- src/progress.c	(revision 1827)
+++ src/progress.c	(working copy)
@@ -265,8 +265,8 @@
 static void
 print_download_speed (struct dot_progress *dp, wgint bytes, double dltime)
 {
-  logprintf (LOG_VERBOSE, " %s",
-	     retr_rate (bytes, dltime - dp->last_timer_value, 1));
+  logprintf (LOG_VERBOSE, " %7s",
+	     retr_rate (bytes, dltime - dp->last_timer_value));
   dp->last_timer_value = dltime;
 }
 
@@ -489,7 +489,7 @@
   int last_eta_value;
 };
 
-static void create_image (struct bar_progress *, double);
+static void create_image (struct bar_progress *, double, bool);
 static void display_image (char *);
 
 static void *
@@ -524,7 +524,7 @@
 
   logputs (LOG_VERBOSE, "\n");
 
-  create_image (bp, 0);
+  create_image (bp, 0, false);
   display_image (bp->buffer);
 
   return bp;
@@ -573,7 +573,7 @@
     /* Don't update more often than five times per second. */
     return;
 
-  create_image (bp, dltime);
+  create_image (bp, dltime, false);
   display_image (bp->buffer);
   bp->last_screen_update = dltime;
 }
@@ -588,7 +588,7 @@
     /* See bar_update() for explanation. */
     bp->total_length = bp->initial_length + bp->count;
 
-  create_image (bp, dltime);
+  create_image (bp, dltime, true);
   display_image (bp->buffer);
 
   logputs (LOG_VERBOSE, "\n\n");
@@ -700,7 +700,7 @@
 #endif
 }
 
-static const char *eta_to_human (int);
+static const char *eta_to_human_short (int);
 
 #define APPEND_LITERAL(s) do {			\
   memcpy (p, s, sizeof (s) - 1);		\
@@ -712,7 +712,7 @@
 #endif
 
 static void
-create_image (struct bar_progress *bp, double dl_total_time)
+create_image (struct bar_progress *bp, double dl_total_time, bool done)
 {
   char *p = bp->buffer;
   wgint size = bp->initial_length + bp->count;
@@ -842,41 +842,50 @@
   else
     APPEND_LITERAL ("   --.--K/s");
 
-  /* "  ETA ..m ..s"; wait for three seconds before displaying the ETA.
-     That's because the ETA value needs a while to become
-     reliable.  */
-  if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000)
+  if (!done)
     {
-      int eta;
+      /* "  eta ..m ..s"; wait for three seconds before displaying the ETA.
+	 That's because the ETA value needs a while to become
+	 reliable.  */
+      if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000)
+	{
+	  int eta;
 
-      /* Don't change the value of ETA more than approximately once
-	 per second; doing so would cause flashing without providing
-	 any value to the user. */
-      if (bp->total_length != size
-	  && bp->last_eta_value != 0
-	  && dl_total_time - bp->last_eta_time < 900)
-	eta = bp->last_eta_value;
-      else
+	  /* Don't change the value of ETA more than approximately once
+	     per second; doing so would cause flashing without providing
+	     any value to the user. */
+	  if (bp->total_length != size
+	      && bp->last_eta_value != 0
+	      && dl_total_time - bp->last_eta_time < 900)
+	    eta = bp->last_eta_value;
+	  else
+	    {
+	      /* Calculate ETA using the average download speed to predict
+		 the future speed.  If you want to use a speed averaged
+		 over a more recent period, replace dl_total_time with
+		 hist->total_time and bp->count with hist->total_bytes.
+		 I found that doing that results in a very jerky and
+		 ultimately unreliable ETA.  */
+	      double time_sofar = (double) dl_total_time / 1000;
+	      wgint bytes_remaining = bp->total_length - size;
+	      eta = (int) (time_sofar * bytes_remaining / bp->count + 0.5);
+	      bp->last_eta_value = eta;
+	      bp->last_eta_time = dl_total_time;
+	    }
+
+	  sprintf (p, "  eta %s", eta_to_human_short (eta));
+	  p += strlen (p);
+	}
+      else if (bp->total_length > 0)
 	{
-	  /* Calculate ETA using the average download speed to predict
-	     the future speed.  If you want to use a speed averaged
-	     over a more recent period, replace dl_total_time with
-	     hist->total_time and bp->count with hist->total_bytes.
-	     I found that doing that results in a very jerky and
-	     ultimately unreliable ETA.  */
-	  double time_sofar = (double) dl_total_time / 1000;
-	  wgint bytes_remaining = bp->total_length - size;
-	  eta = (int) (time_sofar * bytes_remaining / bp->count + 0.5);
-	  bp->last_eta_value = eta;
-	  bp->last_eta_time = dl_total_time;
+	  APPEND_LITERAL ("             ");
 	}
-
-      sprintf (p, "  eta %s", eta_to_human (eta));
-      p += strlen (p);
     }
-  else if (bp->total_length > 0)
+  else
     {
-      APPEND_LITERAL ("             ");
+      /* When the download is done, print the elapsed time.  */
+      sprintf (p, _("   in %s"), eta_to_human_short (dl_total_time / 1000 + 0.5));
+      p += strlen (p);
     }
 
   assert (p - bp->buffer <= bp->width);
@@ -942,11 +951,11 @@
 }
 #endif
 
-/* Provide a human-readable rendition of the ETA.  It never occupies
-   more than 7 characters of screen space.  */
+/* Provide a short human-readable rendition of the ETA.  It never
+   occupies more than 7 characters of screen space.  */
 
 static const char *
-eta_to_human (int secs)
+eta_to_human_short (int secs)
 {
   static char buf[10];		/* 8 is enough, but just in case */
   static int last = -1;
@@ -959,16 +968,16 @@
   last = secs;
 
   if (secs < 100)
-    sprintf (buf, "%ds", secs);
+    sprintf (buf, _("%ds"), secs);
   else if (secs < 100 * 60)
-    sprintf (buf, "%dm %ds", secs / 60, secs % 60);
+    sprintf (buf, _("%dm %ds"), secs / 60, secs % 60);
   else if (secs < 100 * 3600)
-    sprintf (buf, "%dh %dm", secs / 3600, (secs / 60) % 60);
+    sprintf (buf, _("%dh %dm"), secs / 3600, (secs / 60) % 60);
   else if (secs < 100 * 86400)
-    sprintf (buf, "%dd %dh", secs / 86400, (secs / 3600) % 60);
+    sprintf (buf, _("%dd %dh"), secs / 86400, (secs / 3600) % 60);
   else
     /* (2^31-1)/86400 doesn't overflow BUF. */
-    sprintf (buf, "%dd", secs / 86400);
+    sprintf (buf, _("%dd"), secs / 86400);
 
   return buf;
 }
Index: src/retr.c
===================================================================
--- src/retr.c	(revision 1819)
+++ src/retr.c	(working copy)
@@ -54,6 +54,9 @@
 /* Total size of downloaded files.  Used to enforce quota.  */
 SUM_SIZE_INT total_downloaded_bytes;
 
+/* Total download time in milliseconds. */
+double total_download_time;
+
 /* If non-NULL, the stream to which output should be written.  This
    stream is initialized when `-O' is used.  */
 FILE *output_stream;
@@ -495,18 +498,18 @@
   return fd_read_hunk (fd, line_terminator, 128, FD_READ_LINE_MAX);
 }
 
-/* Return a printed representation of the download rate, as
-   appropriate for the speed.  If PAD is true, strings will be padded
-   to the width of 7 characters (xxxx.xx).  */
-char *
-retr_rate (wgint bytes, double msecs, bool pad)
+/* Return a printed representation of the download rate, along with
+   the units appropriate for the download speed.  */
+
+const char *
+retr_rate (wgint bytes, double msecs)
 {
   static char res[20];
   static const char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s" };
   int units = 0;
 
   double dlrate = calc_rate (bytes, msecs, &units);
-  sprintf (res, pad ? "%7.2f %s" : "%.2f %s", dlrate, rate_names[units]);
+  sprintf (res, "%.2f %s", dlrate, rate_names[units]);
 
   return res;
 }
Index: src/retr.h
===================================================================
--- src/retr.h	(revision 1807)
+++ src/retr.h	(working copy)
@@ -30,6 +30,9 @@
 #ifndef RETR_H
 #define RETR_H
 
+extern SUM_SIZE_INT total_downloaded_bytes;
+extern double total_download_time;
+
 /* Flags for fd_read_body. */
 enum {
   rb_read_exactly  = 1,
@@ -46,7 +49,7 @@
 uerr_t retrieve_url (const char *, char **, char **, const char *, int *);
 uerr_t retrieve_from_file (const char *, bool, int *);
 
-char *retr_rate (wgint, double, bool);
+const char *retr_rate (wgint, double);
 double calc_rate (wgint, double, int *);
 void printwhat (int, int);
 
Index: src/main.c
===================================================================
--- src/main.c	(revision 1827)
+++ src/main.c	(working copy)
@@ -61,7 +61,6 @@
 
 struct options opt;
 
-extern SUM_SIZE_INT total_downloaded_bytes;
 extern char *version_string;
 
 extern struct cookie_jar *wget_cookie_jar;
@@ -638,6 +637,31 @@
   exit (0);
 }
 
+static char *
+secs_to_human_time (double secs_decimal)
+{
+  static char buf[32];
+  int secs = (int) (secs_decimal + 0.5);
+  int hours, mins, days;
+
+  days = secs / 86400, secs %= 86400;
+  hours = secs / 3600, secs %= 3600;
+  mins = secs / 60, secs %= 60;
+
+  if (days)
+    sprintf (buf, _("%dd %dh %dm %ds"), days, hours, mins, secs);
+  else if (hours)
+    sprintf (buf, _("%dh %dm %ds"), hours, mins, secs);
+  else if (mins)
+    sprintf (buf, _("%dm %ds"), mins, secs);
+  else if (secs_decimal >= 1)
+    sprintf (buf, _("%ds"), secs);
+  else
+    sprintf (buf, _("%.2fs"), secs_decimal);
+
+  return buf;
+}
+
 static void
 print_version (void)
 {
@@ -960,10 +984,12 @@
       || (opt.input_filename && total_downloaded_bytes != 0))
     {
       logprintf (LOG_NOTQUIET,
-		 _("\nFINISHED --%s--\nDownloaded: %s in %d files\n"),
+		 _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
 		 time_str (NULL),
+		 opt.numurls,
 		 human_readable (total_downloaded_bytes),
-		 opt.numurls);
+		 secs_to_human_time (total_download_time / 1000),
+		 retr_rate (total_downloaded_bytes, total_download_time));
       /* Print quota warning, if exceeded.  */
       if (opt.quota && total_downloaded_bytes > opt.quota)
 	logprintf (LOG_NOTQUIET,