]> sjero.net Git - wget/commitdiff
[svn] Print the current download speed, rather than the average.
authorhniksic <devnull@localhost>
Tue, 9 Apr 2002 22:10:01 +0000 (15:10 -0700)
committerhniksic <devnull@localhost>
Tue, 9 Apr 2002 22:10:01 +0000 (15:10 -0700)
Published in <sxs3cy4yacm.fsf@florida.arsdigita.de>.

src/ChangeLog
src/progress.c

index f68fe96463ab7fc8d3ddbe0d98104543ac51282e..fabacf4fc3b067c000741f3e8f7e31bf03fb2da7 100644 (file)
@@ -1,3 +1,12 @@
+2002-04-09  Hrvoje Niksic  <hniksic@arsdigita.com>
+
+       * progress.c (bar_update): Maintain an array of the time it took
+       to perform previous 30 network reads.
+       (create_image): Calculate the download speed and ETA based on the
+       last 30 reads, not the entire download.
+       (create_image): Make sure that the ETA is not changed more than
+       once per second.
+
 2002-04-09  Ian Abbott  <abbotti@mev.co.uk>
 
        * mswindows.c (borland_utime): New function conditionally defined
 2002-04-09  Ian Abbott  <abbotti@mev.co.uk>
 
        * mswindows.c (borland_utime): New function conditionally defined
index dc96763667e4831b78b32fbde4c187dc56122d68..2e889b1233fda16a6a241ea2e44dac967a73b984 100644 (file)
@@ -401,6 +401,9 @@ dot_set_params (const char *params)
    create_image will overflow the buffer.  */
 #define MINIMUM_SCREEN_WIDTH 45
 
    create_image will overflow the buffer.  */
 #define MINIMUM_SCREEN_WIDTH 45
 
+/* Number of recent packets we keep the stats for. */
+#define RECENT_ARRAY_SIZE 30
+
 static int screen_width = DEFAULT_SCREEN_WIDTH;
 
 struct bar_progress {
 static int screen_width = DEFAULT_SCREEN_WIDTH;
 
 struct bar_progress {
@@ -410,7 +413,7 @@ struct bar_progress {
                                   download finishes */
   long count;                  /* bytes downloaded so far */
 
                                   download finishes */
   long count;                  /* bytes downloaded so far */
 
-  long last_update;            /* time of the last screen update. */
+  long last_screen_update;     /* time of the last screen update. */
 
   int width;                   /* screen width we're using at the
                                   time the progress gauge was
 
   int width;                   /* screen width we're using at the
                                   time the progress gauge was
@@ -420,7 +423,27 @@ struct bar_progress {
                                   signal. */
   char *buffer;                        /* buffer where the bar "image" is
                                   stored. */
                                   signal. */
   char *buffer;                        /* buffer where the bar "image" is
                                   stored. */
-  int tick;
+  int tick;                    /* counter used for drawing the
+                                  progress bar where the total size
+                                  is not known. */
+
+  /* The following variables (kept in a struct for namespace reasons)
+     keep track of how long it took to read recent packets.  See
+     bar_update() for explanation.  */
+  struct {
+    long previous_time;
+    long times[RECENT_ARRAY_SIZE];
+    long bytes[RECENT_ARRAY_SIZE];
+    int count;
+    long summed_times;
+    long summed_bytes;
+  } recent;
+
+  /* create_image() uses these to make sure that ETA information
+     doesn't flash. */
+  long last_eta_time;          /* time of the last update to download
+                                  speed and ETA. */
+  long last_eta_value;
 };
 
 static void create_image PARAMS ((struct bar_progress *, long));
 };
 
 static void create_image PARAMS ((struct bar_progress *, long));
@@ -453,7 +476,8 @@ static void
 bar_update (void *progress, long howmuch, long dltime)
 {
   struct bar_progress *bp = progress;
 bar_update (void *progress, long howmuch, long dltime)
 {
   struct bar_progress *bp = progress;
-  int force_update = 0;
+  int force_screen_update = 0;
+  int rec_index;
 
   bp->count += howmuch;
   if (bp->total_length > 0
 
   bp->count += howmuch;
   if (bp->total_length > 0
@@ -465,21 +489,75 @@ bar_update (void *progress, long howmuch, long dltime)
        equal to the expected size doesn't abort.  */
     bp->total_length = bp->count + bp->initial_length;
 
        equal to the expected size doesn't abort.  */
     bp->total_length = bp->count + bp->initial_length;
 
+  /* The progress bar is supposed to display the "current download
+     speed".  The first version of the progress bar calculated it by
+     dividing the total amount of data with the total time needed to
+     download it.  The problem with this was that stalled or suspended
+     download could unduly influence the "current" time.  Taking just
+     the time needed to download the current packet would not work
+     either because packets arrive too fast and the varitions would be
+     too jerky.
+
+     It would be preferrable to show the speed that pertains to a
+     recent period, say over the past several seconds.  But to do this
+     accurately, we would have to record all the packets received
+     during the last five seconds.
+
+     What we do instead is maintain a history of a fixed number of
+     packets.  It actually makes sense if you think about it -- faster
+     downloads will have a faster response to speed changes.  */
+
+  rec_index = bp->recent.count % RECENT_ARRAY_SIZE;
+  ++bp->recent.count;
+
+  /* Instead of calculating the sum of times[] and bytes[], we
+     maintain the summed quantities.  To maintain each sum, we must
+     make sure that it gets increased by the newly downloaded amount,
+     but also that it gets decreased by the amount we're overwriting
+     in (erasing from) the cyclical buffer.  */
+  bp->recent.summed_times -= bp->recent.times[rec_index];
+  bp->recent.summed_bytes -= bp->recent.bytes[rec_index];
+
+  bp->recent.times[rec_index] = dltime - bp->recent.previous_time;
+  bp->recent.bytes[rec_index] = howmuch;
+
+  bp->recent.summed_times += bp->recent.times[rec_index];
+  bp->recent.summed_bytes += bp->recent.bytes[rec_index];
+
+  bp->recent.previous_time = dltime;
+
+#if 0
+  /* Sledgehammer check that summed_times and summed_bytes are
+     accurate.  */
+  {
+    int num = bp->recent.count;
+    int i;
+    int upper = num < RECENT_ARRAY_SIZE ? num : RECENT_ARRAY_SIZE;
+    long sumt = 0, sumb = 0;
+    for (i = 0; i < upper; i++)
+      {
+       sumt += bp->recent.times[i];
+       sumb += bp->recent.bytes[i];
+      }
+    assert (sumt == bp->recent.summed_times);
+    assert (sumb == bp->recent.summed_bytes);
+  }
+#endif
+
   if (screen_width - 1 != bp->width)
     {
       bp->width = screen_width - 1;
       bp->buffer = xrealloc (bp->buffer, bp->width + 1);
   if (screen_width - 1 != bp->width)
     {
       bp->width = screen_width - 1;
       bp->buffer = xrealloc (bp->buffer, bp->width + 1);
-      force_update = 1;
+      force_screen_update = 1;
     }
 
     }
 
-  if (dltime - bp->last_update < 200 && !force_update)
+  if (dltime - bp->last_screen_update < 200 && !force_screen_update)
     /* Don't update more often than five times per second. */
     return;
 
     /* Don't update more often than five times per second. */
     return;
 
-  bp->last_update = dltime;
-
   create_image (bp, dltime);
   display_image (bp->buffer);
   create_image (bp, dltime);
   display_image (bp->buffer);
+  bp->last_screen_update = dltime;
 }
 
 static void
 }
 
 static void
@@ -512,7 +590,7 @@ bar_finish (void *progress, long dltime)
 #endif
 
 static void
 #endif
 
 static void
-create_image (struct bar_progress *bp, long dltime)
+create_image (struct bar_progress *bp, long dl_total_time)
 {
   char *p = bp->buffer;
   long size = bp->initial_length + bp->count;
 {
   char *p = bp->buffer;
   long size = bp->initial_length + bp->count;
@@ -520,6 +598,9 @@ create_image (struct bar_progress *bp, long dltime)
   char *size_legible = legible (size);
   int size_legible_len = strlen (size_legible);
 
   char *size_legible = legible (size);
   int size_legible_len = strlen (size_legible);
 
+  long recent_time = bp->recent.summed_times;
+  long recent_bytes = bp->recent.summed_bytes;
+
   /* The progress bar should look like this:
      xx% [=======>             ] nn,nnn 12.34K/s ETA 00:00
 
   /* The progress bar should look like this:
      xx% [=======>             ] nn,nnn 12.34K/s ETA 00:00
 
@@ -617,11 +698,11 @@ create_image (struct bar_progress *bp, long dltime)
   p += strlen (p);
 
   /* " 1012.45K/s" */
   p += strlen (p);
 
   /* " 1012.45K/s" */
-  if (dltime && bp->count)
+  if (recent_time && recent_bytes)
     {
       static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
       int units = 0;
     {
       static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
       int units = 0;
-      double dlrate = calc_rate (bp->count, dltime, &units);
+      double dlrate = calc_rate (recent_bytes, recent_time, &units);
       sprintf (p, " %7.2f%s", dlrate, short_units[units]);
       p += strlen (p);
     }
       sprintf (p, " %7.2f%s", dlrate, short_units[units]);
       p += strlen (p);
     }
@@ -629,13 +710,25 @@ create_image (struct bar_progress *bp, long dltime)
     APPEND_LITERAL ("   --.--K/s");
 
   /* " ETA xx:xx:xx" */
     APPEND_LITERAL ("   --.--K/s");
 
   /* " ETA xx:xx:xx" */
-  if (bp->total_length > 0 && bp->count > 0)
+  if (bp->total_length > 0 && recent_bytes > 0)
     {
     {
-      int eta, eta_hrs, eta_min, eta_sec;
-      double tm_sofar = (double)dltime / 1000;
-      long bytes_remaining = bp->total_length - size;
-
-      eta = (int) (tm_sofar * bytes_remaining / bp->count);
+      long eta;
+      int eta_hrs, eta_min, eta_sec;
+
+      /* 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 (dl_total_time - bp->last_eta_time < 900
+         && bp->last_eta_value != 0)
+       eta = bp->last_eta_value;
+      else
+       {
+         double tm_sofar = (double)recent_time / 1000;
+         long bytes_remaining = bp->total_length - size;
+         eta = (long) (tm_sofar * bytes_remaining / recent_bytes);
+         bp->last_eta_value = eta;
+         bp->last_eta_time = dl_total_time;
+       }
 
       eta_hrs = eta / 3600, eta %= 3600;
       eta_min = eta / 60,   eta %= 60;
 
       eta_hrs = eta / 3600, eta %= 3600;
       eta_min = eta / 60,   eta %= 60;