progress.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Routines to output progress information during a file transfer.
  3. *
  4. * Copyright (C) 1996-2000 Andrew Tridgell
  5. * Copyright (C) 1996 Paul Mackerras
  6. * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
  7. * Copyright (C) 2003-2009 Wayne Davison
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program; if not, visit the http://fsf.org website.
  21. */
  22. #include "rsync.h"
  23. extern int am_server;
  24. extern int need_unsorted_flist;
  25. extern struct stats stats;
  26. extern struct file_list *cur_flist;
  27. #define PROGRESS_HISTORY_SECS 5
  28. #ifdef GETPGRP_VOID
  29. #define GETPGRP_ARG
  30. #else
  31. #define GETPGRP_ARG 0
  32. #endif
  33. struct progress_history {
  34. struct timeval time;
  35. OFF_T ofs;
  36. };
  37. int progress_is_active = 0;
  38. static struct progress_history ph_start;
  39. static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
  40. static int newest_hpos, oldest_hpos;
  41. static int current_file_index;
  42. static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
  43. {
  44. return (t2->tv_sec - t1->tv_sec) * 1000L
  45. + (t2->tv_usec - t1->tv_usec) / 1000;
  46. }
  47. /**
  48. * @param ofs Current position in file
  49. * @param size Total size of file
  50. * @param is_last True if this is the last time progress will be
  51. * printed for this file, so we should output a newline. (Not
  52. * necessarily the same as all bytes being received.)
  53. **/
  54. static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
  55. int is_last)
  56. {
  57. char rembuf[64], eol[128];
  58. const char *units;
  59. int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
  60. unsigned long diff;
  61. double rate, remain;
  62. if (is_last) {
  63. /* Compute stats based on the starting info. */
  64. if (!ph_start.time.tv_sec
  65. || !(diff = msdiff(&ph_start.time, now)))
  66. diff = 1;
  67. rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
  68. /* Switch to total time taken for our last update. */
  69. remain = (double) diff / 1000.0;
  70. } else {
  71. /* Compute stats based on recent progress. */
  72. if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
  73. diff = 1;
  74. rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
  75. / diff / 1024.0;
  76. remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
  77. }
  78. if (rate > 1024*1024) {
  79. rate /= 1024.0 * 1024.0;
  80. units = "GB/s";
  81. } else if (rate > 1024) {
  82. rate /= 1024.0;
  83. units = "MB/s";
  84. } else {
  85. units = "kB/s";
  86. }
  87. if (remain < 0)
  88. strlcpy(rembuf, " ??:??:??", sizeof rembuf);
  89. else {
  90. snprintf(rembuf, sizeof rembuf, "%4d:%02d:%02d",
  91. (int) (remain / 3600.0),
  92. (int) (remain / 60.0) % 60,
  93. (int) remain % 60);
  94. }
  95. if (is_last) {
  96. snprintf(eol, sizeof eol, " (xfer#%d, to-check=%d/%d)\n",
  97. stats.num_transferred_files,
  98. stats.num_files - current_file_index - 1,
  99. stats.num_files);
  100. } else
  101. strlcpy(eol, "\r", sizeof eol);
  102. progress_is_active = 0;
  103. rprintf(FCLIENT, "%12s %3d%% %7.2f%s %s%s",
  104. human_num(ofs), pct, rate, units, rembuf, eol);
  105. if (!is_last)
  106. progress_is_active = 1;
  107. }
  108. void set_current_file_index(struct file_struct *file, int ndx)
  109. {
  110. if (need_unsorted_flist)
  111. current_file_index = flist_find(cur_flist, file) + cur_flist->ndx_start;
  112. else
  113. current_file_index = ndx;
  114. current_file_index -= cur_flist->flist_num;
  115. }
  116. void end_progress(OFF_T size)
  117. {
  118. if (!am_server) {
  119. struct timeval now;
  120. gettimeofday(&now, NULL);
  121. rprint_progress(size, size, &now, True);
  122. }
  123. memset(&ph_start, 0, sizeof ph_start);
  124. }
  125. void show_progress(OFF_T ofs, OFF_T size)
  126. {
  127. struct timeval now;
  128. #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
  129. static pid_t pgrp = -1;
  130. pid_t tc_pgrp;
  131. #endif
  132. if (am_server)
  133. return;
  134. #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
  135. if (pgrp == -1)
  136. pgrp = getpgrp(GETPGRP_ARG);
  137. #endif
  138. gettimeofday(&now, NULL);
  139. if (!ph_start.time.tv_sec) {
  140. int i;
  141. /* Try to guess the real starting time when the sender started
  142. * to send us data by using the time we last received some data
  143. * in the last file (if it was recent enough). */
  144. if (msdiff(&ph_list[newest_hpos].time, &now) <= 1500) {
  145. ph_start.time = ph_list[newest_hpos].time;
  146. ph_start.ofs = 0;
  147. } else {
  148. ph_start.time.tv_sec = now.tv_sec;
  149. ph_start.time.tv_usec = now.tv_usec;
  150. ph_start.ofs = ofs;
  151. }
  152. for (i = 0; i < PROGRESS_HISTORY_SECS; i++)
  153. ph_list[i] = ph_start;
  154. }
  155. else {
  156. if (msdiff(&ph_list[newest_hpos].time, &now) < 1000)
  157. return;
  158. newest_hpos = oldest_hpos;
  159. oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS;
  160. ph_list[newest_hpos].time.tv_sec = now.tv_sec;
  161. ph_list[newest_hpos].time.tv_usec = now.tv_usec;
  162. ph_list[newest_hpos].ofs = ofs;
  163. }
  164. #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
  165. tc_pgrp = tcgetpgrp(STDOUT_FILENO);
  166. if (tc_pgrp != pgrp && tc_pgrp != -1)
  167. return;
  168. #endif
  169. rprint_progress(ofs, size, &now, False);
  170. }