1 #include "git-compat-util.h"
7 struct timeval prev_tv
;
9 unsigned long avg_bytes
;
10 unsigned long last_bytes
[TP_IDX_MAX
];
11 unsigned int avg_misecs
;
12 unsigned int last_misecs
[TP_IDX_MAX
];
21 unsigned last_percent
;
23 unsigned delayed_percent_treshold
;
24 struct throughput
*throughput
;
27 static volatile sig_atomic_t progress_update
;
29 static void progress_interval(int signum
)
34 static void set_progress_signal(void)
41 memset(&sa
, 0, sizeof(sa
));
42 sa
.sa_handler
= progress_interval
;
43 sigemptyset(&sa
.sa_mask
);
44 sa
.sa_flags
= SA_RESTART
;
45 sigaction(SIGALRM
, &sa
, NULL
);
47 v
.it_interval
.tv_sec
= 1;
48 v
.it_interval
.tv_usec
= 0;
49 v
.it_value
= v
.it_interval
;
50 setitimer(ITIMER_REAL
, &v
, NULL
);
53 static void clear_progress_signal(void)
55 struct itimerval v
= {{0,},};
56 setitimer(ITIMER_REAL
, &v
, NULL
);
57 signal(SIGALRM
, SIG_IGN
);
61 static int display(struct progress
*progress
, unsigned n
, int done
)
65 if (progress
->delay
) {
66 if (!progress_update
|| --progress
->delay
)
68 if (progress
->total
) {
69 unsigned percent
= n
* 100 / progress
->total
;
70 if (percent
> progress
->delayed_percent_treshold
) {
71 /* inhibit this progress report entirely */
72 clear_progress_signal();
80 progress
->last_value
= n
;
81 tp
= (progress
->throughput
) ? progress
->throughput
->display
: "";
82 eol
= done
? ", done. \n" : " \r";
83 if (progress
->total
) {
84 unsigned percent
= n
* 100 / progress
->total
;
85 if (percent
!= progress
->last_percent
|| progress_update
) {
86 progress
->last_percent
= percent
;
87 fprintf(stderr
, "%s: %3u%% (%u/%u)%s%s",
88 progress
->title
, percent
, n
,
89 progress
->total
, tp
, eol
);
93 } else if (progress_update
) {
94 fprintf(stderr
, "%s: %u%s%s", progress
->title
, n
, tp
, eol
);
102 void display_throughput(struct progress
*progress
, unsigned long n
)
104 struct throughput
*tp
;
110 tp
= progress
->throughput
;
112 gettimeofday(&tv
, NULL
);
115 progress
->throughput
= tp
= calloc(1, sizeof(*tp
));
124 * We have x = bytes and y = microsecs. We want z = KiB/s:
126 * z = (x / 1024) / (y / 1000000)
127 * z = x / y * 1000000 / 1024
128 * z = x / (y * 1024 / 1000000)
131 * To simplify things we'll keep track of misecs, or 1024th of a sec
134 * y' = y * 1024 / 1000000
135 * y' = y / (1000000 / 1024)
138 misecs
= (tv
.tv_sec
- tp
->prev_tv
.tv_sec
) * 1024;
139 misecs
+= (int)(tv
.tv_usec
- tp
->prev_tv
.tv_usec
) / 977;
143 tp
->avg_bytes
+= tp
->count
;
144 tp
->avg_misecs
+= misecs
;
145 snprintf(tp
->display
, sizeof(tp
->display
),
146 ", %lu KiB/s", tp
->avg_bytes
/ tp
->avg_misecs
);
147 tp
->avg_bytes
-= tp
->last_bytes
[tp
->idx
];
148 tp
->avg_misecs
-= tp
->last_misecs
[tp
->idx
];
149 tp
->last_bytes
[tp
->idx
] = tp
->count
;
150 tp
->last_misecs
[tp
->idx
] = misecs
;
151 tp
->idx
= (tp
->idx
+ 1) % TP_IDX_MAX
;
156 int display_progress(struct progress
*progress
, unsigned n
)
158 return progress
? display(progress
, n
, 0) : 0;
161 struct progress
*start_progress_delay(const char *title
, unsigned total
,
162 unsigned percent_treshold
, unsigned delay
)
164 struct progress
*progress
= malloc(sizeof(*progress
));
166 /* unlikely, but here's a good fallback */
167 fprintf(stderr
, "%s...\n", title
);
170 progress
->title
= title
;
171 progress
->total
= total
;
172 progress
->last_value
= -1;
173 progress
->last_percent
= -1;
174 progress
->delayed_percent_treshold
= percent_treshold
;
175 progress
->delay
= delay
;
176 progress
->throughput
= NULL
;
177 set_progress_signal();
181 struct progress
*start_progress(const char *title
, unsigned total
)
183 return start_progress_delay(title
, total
, 0, 0);
186 void stop_progress(struct progress
**p_progress
)
188 struct progress
*progress
= *p_progress
;
192 if (progress
->last_value
!= -1) {
193 /* Force the last update */
195 display(progress
, progress
->last_value
, 1);
197 clear_progress_signal();
198 free(progress
->throughput
);