]> sjero.net Git - wget/blobdiff - src/progress.c
[svn] Merge of fix for bugs 20341 and 20410.
[wget] / src / progress.c
index f7cbc009f0b5b6b0f43bb74f6e2af7b9f43d9d44..be841590abee1379139f7cd13e69918cbc68876f 100644 (file)
@@ -1,11 +1,11 @@
 /* Download progress.
-   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2001-2006 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
 In addition, as a special exception, the Free Software Foundation
 gives permission to link the code of its release of Wget with the
@@ -175,7 +174,7 @@ progress_interactive_p (void *progress)
 }
 
 /* Inform the progress gauge of newly received bytes.  DLTIME is the
-   time in milliseconds since the beginning of the download.  */
+   time since the beginning of the download.  */
 
 void
 progress_update (void *progress, wgint howmuch, double dltime)
@@ -301,37 +300,39 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
     else
       /* For last row also include bytes accumulated after last dot.  */
       bytes_this_row = dp->dots * opt.dot_bytes + dp->accumulated;
+    /* Don't count the portion of the row belonging to initial_length */
     if (dp->rows == dp->initial_length / ROW_BYTES)
-      /* Don't count the portion of the row belonging to initial_length */
       bytes_this_row -= dp->initial_length % ROW_BYTES;
     rate = calc_rate (bytes_this_row, dltime - dp->last_timer_value, &units);
     logprintf (LOG_VERBOSE, " %4.*f%c",
-              rate >= 100 ? 0 : rate >= 9.995 ? 1 : 2,
+              rate >= 99.95 ? 0 : rate >= 9.995 ? 1 : 2,
               rate, names[units]);
     dp->last_timer_value = dltime;
   }
 
   if (!last)
     {
+      /* Display ETA based on average speed.  Inspired by Vladi
+        Belperchinov-Shabanski's "wget-new-percentage" patch.  */
       if (dp->total_length)
        {
          wgint bytes_remaining = dp->total_length - bytes_displayed;
          /* The quantity downloaded in this download run. */
          wgint bytes_sofar = bytes_displayed - dp->initial_length;
-         double secs_sofar = dltime / 1000;
-         int eta = (int) (secs_sofar * bytes_remaining / bytes_sofar + 0.5);
-         logprintf (LOG_VERBOSE, " %s", eta_to_human_short (eta, true));
+         double eta = dltime * bytes_remaining / bytes_sofar;
+         if (eta < INT_MAX - 1)
+           logprintf (LOG_VERBOSE, " %s",
+                      eta_to_human_short ((int) (eta + 0.5), true));
        }
     }
   else
     {
       /* When done, print the total download time */
-      double secs = dltime / 1000;
-      if (secs >= 10)
+      if (dltime >= 10)
        logprintf (LOG_VERBOSE, "=%s",
-                  eta_to_human_short ((int) (secs + 0.5), true));
+                  eta_to_human_short ((int) (dltime + 0.5), true));
       else
-       logprintf (LOG_VERBOSE, "=%ss", print_decimal (secs));
+       logprintf (LOG_VERBOSE, "=%ss", print_decimal (dltime));
     }
 }
 
@@ -360,10 +361,6 @@ dot_update (void *progress, wgint howmuch, double dltime)
       ++dp->dots;
       if (dp->dots >= opt.dots_in_line)
        {
-         wgint row_qty = ROW_BYTES;
-         if (dp->rows == dp->initial_length / ROW_BYTES)
-           row_qty -= dp->initial_length % ROW_BYTES;
-
          ++dp->rows;
          dp->dots = 0;
 
@@ -480,12 +477,20 @@ static volatile sig_atomic_t received_sigwinch;
    sample is at least 150ms long, which means that, over the course of
    20 samples, "current" download speed spans at least 3s into the
    past.  */
-#define DLSPEED_SAMPLE_MIN 150
+#define DLSPEED_SAMPLE_MIN 0.15
 
 /* The time after which the download starts to be considered
    "stalled", i.e. the current bandwidth is not printed and the recent
    download speeds are scratched.  */
-#define STALL_START_TIME 5000
+#define STALL_START_TIME 5
+
+/* Time between screen refreshes will not be shorter than this, so
+   that Wget doesn't swamp the TTY with output.  */
+#define REFRESH_INTERVAL 0.2
+
+/* Don't refresh the ETA too often to avoid jerkiness in predictions.
+   This allows ETA to change approximately once per second.  */
+#define ETA_REFRESH_INTERVAL 0.99
 
 struct bar_progress {
   wgint initial_length;                /* how many bytes have been downloaded
@@ -515,12 +520,12 @@ struct bar_progress {
      details.  */
   struct bar_progress_hist {
     int pos;
-    wgint times[DLSPEED_HISTORY_SIZE];
+    double times[DLSPEED_HISTORY_SIZE];
     wgint bytes[DLSPEED_HISTORY_SIZE];
 
     /* The sum of times and bytes respectively, maintained for
        efficiency. */
-    wgint total_time;
+    double total_time;
     wgint total_bytes;
   } hist;
 
@@ -620,7 +625,7 @@ bar_update (void *progress, wgint howmuch, double dltime)
       received_sigwinch = 0;
     }
 
-  if (dltime - bp->last_screen_update < 200 && !force_screen_update)
+  if (dltime - bp->last_screen_update < REFRESH_INTERVAL && !force_screen_update)
     /* Don't update more often than five times per second. */
     return;
 
@@ -710,7 +715,7 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
         value because the current bandwidth would start too small.
         Start with an arbitrary (but more reasonable) time value and
         let it level out.  */
-      recent_age = 1000;
+      recent_age = 1;
     }
 
   /* Store "recent" bytes and download time to history ring at the
@@ -745,8 +750,14 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
        sumt += hist->times[i];
        sumb += hist->bytes[i];
       }
-    assert (sumt == hist->total_time);
     assert (sumb == hist->total_bytes);
+    /* We can't use assert(sumt==hist->total_time) because some
+       precision is lost by adding and subtracting floating-point
+       numbers.  But during a download this precision should not be
+       detectable, i.e. no larger than 1ns.  */
+    double diff = sumt - hist->total_time;
+    if (diff < 0) diff = -diff;
+    assert (diff < 1e-9);
   }
 #endif
 }
@@ -789,13 +800,13 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
      "xx% " or "100%"  - percentage               - 4 chars
      "[]"              - progress bar decorations - 2 chars
      " nnn,nnn,nnn"    - downloaded bytes         - 12 chars or very rarely more
-     " 1012.56K/s"     - dl rate                  - 11 chars
+     " 12.5K/s"        - download rate             - 8 chars
      "  eta 36m 51s"   - ETA                      - 13 chars
 
      "=====>..."       - progress bar             - the rest
   */
   int dlbytes_size = 1 + MAX (size_grouped_len, 11);
-  int progress_size = bp->width - (4 + 2 + dlbytes_size + 11 + 13);
+  int progress_size = bp->width - (4 + 2 + dlbytes_size + 8 + 13);
 
   if (progress_size < 5)
     progress_size = 0;
@@ -880,8 +891,8 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
   sprintf (p, " %-11s", size_grouped);
   move_to_end (p);
 
-  /* " 1012.45K/s" */
-  if (hist->total_time && hist->total_bytes)
+  /* " 12.52K/s" */
+  if (hist->total_time > 0 && hist->total_bytes)
     {
       static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
       int units = 0;
@@ -890,18 +901,19 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
       wgint dlquant = hist->total_bytes + bp->recent_bytes;
       double dltime = hist->total_time + (dl_total_time - bp->recent_start);
       double dlspeed = calc_rate (dlquant, dltime, &units);
-      sprintf (p, " %7.2f%s", dlspeed, short_units[units]);
+      sprintf (p, " %4.*f%s", dlspeed >= 99.95 ? 0 : dlspeed >= 9.995 ? 1 : 2,
+              dlspeed, short_units[units]);
       move_to_end (p);
     }
   else
-    APPEND_LITERAL ("   --.--K/s");
+    APPEND_LITERAL (" --.-K/s");
 
   if (!done)
     {
       /* "  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 (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3)
        {
          int eta;
 
@@ -910,7 +922,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
             any value to the user. */
          if (bp->total_length != size
              && bp->last_eta_value != 0
-             && dl_total_time - bp->last_eta_time < 900)
+             && dl_total_time - bp->last_eta_time < ETA_REFRESH_INTERVAL)
            eta = bp->last_eta_value;
          else
            {
@@ -920,9 +932,11 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
                 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);
+             double eta_ = dl_total_time * bytes_remaining / bp->count;
+             if (eta_ >= INT_MAX - 1)
+               goto skip_eta;
+             eta = (int) (eta_ + 0.5);
              bp->last_eta_value = eta;
              bp->last_eta_time = dl_total_time;
            }
@@ -934,21 +948,22 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
        }
       else if (bp->total_length > 0)
        {
+       skip_eta:
          APPEND_LITERAL ("             ");
        }
     }
   else
     {
       /* When the download is done, print the elapsed time.  */
-      double secs = dl_total_time / 1000;
+
       /* Note to translators: this should not take up more room than
         available here.  Abbreviate if necessary.  */
       strcpy (p, _("   in "));
       move_to_end (p);         /* not p+=6, think translations! */
-      if (secs >= 10)
-       strcpy (p, eta_to_human_short ((int) (secs + 0.5), false));
+      if (dl_total_time >= 10)
+       strcpy (p, eta_to_human_short ((int) (dl_total_time + 0.5), false));
       else
-       sprintf (p, "%ss", print_decimal (secs));
+       sprintf (p, "%ss", print_decimal (dl_total_time));
       move_to_end (p);
     }
 
@@ -1049,7 +1064,7 @@ eta_to_human_short (int secs, bool condensed)
     sprintf (buf, "%ds", secs);
   else if (secs < 100 * 60)
     sprintf (buf, "%dm%s%ds", secs / 60, space, secs % 60);
-  else if (secs < 100 * 3600)
+  else if (secs < 48 * 3600)
     sprintf (buf, "%dh%s%dm", secs / 3600, space, (secs / 60) % 60);
   else if (secs < 100 * 86400)
     sprintf (buf, "%dd%s%dh", secs / 86400, space, (secs / 3600) % 60);