Skip to content

Commit cf84d51

Browse files
Nicolas Pitregitster
authored andcommitted
add throughput to progress display
This adds the ability for the progress code to also display transfer throughput when that makes sense. The math was inspired by commit c548cf4 from Linus. Signed-off-by: Nicolas Pitre <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4d4fcc5 commit cf84d51

File tree

2 files changed

+77
-4
lines changed

2 files changed

+77
-4
lines changed

progress.c

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
#include "git-compat-util.h"
22
#include "progress.h"
33

4+
#define TP_IDX_MAX 8
5+
6+
struct throughput {
7+
struct timeval prev_tv;
8+
unsigned long count;
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];
13+
unsigned int idx;
14+
char display[20];
15+
};
16+
417
struct progress {
518
const char *title;
619
int last_value;
720
unsigned total;
821
unsigned last_percent;
922
unsigned delay;
1023
unsigned delayed_percent_treshold;
24+
struct throughput *throughput;
1125
};
1226

1327
static volatile sig_atomic_t progress_update;
@@ -46,7 +60,7 @@ static void clear_progress_signal(void)
4660

4761
static int display(struct progress *progress, unsigned n, int done)
4862
{
49-
char *eol;
63+
char *eol, *tp;
5064

5165
if (progress->delay) {
5266
if (!progress_update || --progress->delay)
@@ -64,25 +78,81 @@ static int display(struct progress *progress, unsigned n, int done)
6478
}
6579

6680
progress->last_value = n;
81+
tp = (progress->throughput) ? progress->throughput->display : "";
6782
eol = done ? ", done. \n" : " \r";
6883
if (progress->total) {
6984
unsigned percent = n * 100 / progress->total;
7085
if (percent != progress->last_percent || progress_update) {
7186
progress->last_percent = percent;
72-
fprintf(stderr, "%s: %3u%% (%u/%u)%s", progress->title,
73-
percent, n, progress->total, eol);
87+
fprintf(stderr, "%s: %3u%% (%u/%u)%s%s",
88+
progress->title, percent, n,
89+
progress->total, tp, eol);
7490
progress_update = 0;
7591
return 1;
7692
}
7793
} else if (progress_update) {
78-
fprintf(stderr, "%s: %u%s", progress->title, n, eol);
94+
fprintf(stderr, "%s: %u%s%s", progress->title, n, tp, eol);
7995
progress_update = 0;
8096
return 1;
8197
}
8298

8399
return 0;
84100
}
85101

102+
void display_throughput(struct progress *progress, unsigned long n)
103+
{
104+
struct throughput *tp;
105+
struct timeval tv;
106+
unsigned int misecs;
107+
108+
if (!progress)
109+
return;
110+
tp = progress->throughput;
111+
112+
gettimeofday(&tv, NULL);
113+
114+
if (!tp) {
115+
progress->throughput = tp = calloc(1, sizeof(*tp));
116+
if (tp)
117+
tp->prev_tv = tv;
118+
return;
119+
}
120+
121+
tp->count += n;
122+
123+
/*
124+
* We have x = bytes and y = microsecs. We want z = KiB/s:
125+
*
126+
* z = (x / 1024) / (y / 1000000)
127+
* z = x / y * 1000000 / 1024
128+
* z = x / (y * 1024 / 1000000)
129+
* z = x / y'
130+
*
131+
* To simplify things we'll keep track of misecs, or 1024th of a sec
132+
* obtained with:
133+
*
134+
* y' = y * 1024 / 1000000
135+
* y' = y / (1000000 / 1024)
136+
* y' = y / 977
137+
*/
138+
misecs = (tv.tv_sec - tp->prev_tv.tv_sec) * 1024;
139+
misecs += (int)(tv.tv_usec - tp->prev_tv.tv_usec) / 977;
140+
141+
if (misecs > 512) {
142+
tp->prev_tv = tv;
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;
152+
tp->count = 0;
153+
}
154+
}
155+
86156
int display_progress(struct progress *progress, unsigned n)
87157
{
88158
return progress ? display(progress, n, 0) : 0;
@@ -103,6 +173,7 @@ struct progress *start_progress_delay(const char *title, unsigned total,
103173
progress->last_percent = -1;
104174
progress->delayed_percent_treshold = percent_treshold;
105175
progress->delay = delay;
176+
progress->throughput = NULL;
106177
set_progress_signal();
107178
return progress;
108179
}
@@ -124,5 +195,6 @@ void stop_progress(struct progress **p_progress)
124195
display(progress, progress->last_value, 1);
125196
}
126197
clear_progress_signal();
198+
free(progress->throughput);
127199
free(progress);
128200
}

progress.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
struct progress;
55

6+
void display_throughput(struct progress *progress, unsigned long n);
67
int display_progress(struct progress *progress, unsigned n);
78
struct progress *start_progress(const char *title, unsigned total);
89
struct progress *start_progress_delay(const char *title, unsigned total,

0 commit comments

Comments
 (0)