00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "rsync.h"
00023
00024 extern struct stats stats;
00025 extern int am_server;
00026
00027 #define PROGRESS_HISTORY_SECS 5
00028
00029 #ifdef GETPGRP_VOID
00030 #define GETPGRP_ARG
00031 #else
00032 #define GETPGRP_ARG 0
00033 #endif
00034
00035 struct progress_history {
00036 struct timeval time;
00037 OFF_T ofs;
00038 };
00039
00040 static struct progress_history ph_start;
00041 static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
00042 static int newest_hpos, oldest_hpos;
00043
00044 static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
00045 {
00046 return (t2->tv_sec - t1->tv_sec) * 1000L
00047 + (t2->tv_usec - t1->tv_usec) / 1000;
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
00059 int is_last)
00060 {
00061 char eol[256];
00062 const char *units;
00063 int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
00064 unsigned long diff;
00065 double rate, remain;
00066 int remain_h, remain_m, remain_s;
00067
00068 if (is_last) {
00069
00070 if (!ph_start.time.tv_sec
00071 || !(diff = msdiff(&ph_start.time, now)))
00072 diff = 1;
00073 rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
00074
00075 remain = (double) diff / 1000.0;
00076 } else {
00077
00078 if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
00079 diff = 1;
00080 rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0
00081 / diff / 1024.0;
00082 remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
00083 }
00084
00085 if (rate > 1024*1024) {
00086 rate /= 1024.0 * 1024.0;
00087 units = "GB/s";
00088 } else if (rate > 1024) {
00089 rate /= 1024.0;
00090 units = "MB/s";
00091 } else {
00092 units = "kB/s";
00093 }
00094
00095 remain_s = (int) remain % 60;
00096 remain_m = (int) (remain / 60.0) % 60;
00097 remain_h = (int) (remain / 3600.0);
00098
00099 if (is_last) {
00100 snprintf(eol, sizeof eol, " (xfer#%d, to-check=%d/%d)\n",
00101 stats.num_transferred_files,
00102 stats.num_files - stats.current_file_index - 1,
00103 stats.num_files);
00104 } else
00105 strcpy(eol, "\r");
00106 rprintf(FINFO, "%12s %3d%% %7.2f%s %4d:%02d:%02d%s",
00107 human_num(ofs), pct, rate, units,
00108 remain_h, remain_m, remain_s, eol);
00109 }
00110
00111 void end_progress(OFF_T size)
00112 {
00113 if (!am_server) {
00114 struct timeval now;
00115 gettimeofday(&now, NULL);
00116 rprint_progress(size, size, &now, True);
00117 }
00118 memset(&ph_start, 0, sizeof ph_start);
00119 }
00120
00121 void show_progress(OFF_T ofs, OFF_T size)
00122 {
00123 struct timeval now;
00124 #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
00125 static pid_t pgrp = -1;
00126 pid_t tc_pgrp;
00127 #endif
00128
00129 if (am_server)
00130 return;
00131
00132 #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
00133 if (pgrp == -1)
00134 pgrp = getpgrp(GETPGRP_ARG);
00135 #endif
00136
00137 gettimeofday(&now, NULL);
00138
00139 if (!ph_start.time.tv_sec) {
00140 int i;
00141
00142
00143
00144
00145 if (msdiff(&ph_list[newest_hpos].time, &now) <= 1500) {
00146 ph_start.time = ph_list[newest_hpos].time;
00147 ph_start.ofs = 0;
00148 } else {
00149 ph_start.time.tv_sec = now.tv_sec;
00150 ph_start.time.tv_usec = now.tv_usec;
00151 ph_start.ofs = ofs;
00152 }
00153
00154 for (i = 0; i < PROGRESS_HISTORY_SECS; i++)
00155 ph_list[i] = ph_start;
00156 }
00157 else {
00158 if (msdiff(&ph_list[newest_hpos].time, &now) < 1000)
00159 return;
00160
00161 newest_hpos = oldest_hpos;
00162 oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS;
00163 ph_list[newest_hpos].time.tv_sec = now.tv_sec;
00164 ph_list[newest_hpos].time.tv_usec = now.tv_usec;
00165 ph_list[newest_hpos].ofs = ofs;
00166 }
00167
00168 #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP
00169 tc_pgrp = tcgetpgrp(STDOUT_FILENO);
00170 if (tc_pgrp != pgrp && tc_pgrp != -1)
00171 return;
00172 #endif
00173
00174 rprint_progress(ofs, size, &now, False);
00175 }