Skip to content

Commit 684fe92

Browse files
committed
progress: use wall clock time to update progress instead of SIGALRM
An interval timer is set up using setitimer() that delivers a SIGALRM whose handler sets a flag that is then inspected to know when to write a new progress message. This also resets the flag. The decision whether to write a new progress message or not is effectively a synchronous operation. For example, if a call to display_progress() were delayed for many seconds, the SIGALRM that arrives every second cannot do anything about it---no update would occur until the call of display_progress() finally happens. Being synchronous enables a different scheme to decide when it is time to write an updated progress message: by looking at the clock. Replace the signal-based scheme by keeping track of when the last update happened. Retrieve the current time on every call to display_progress() and only update when a fixed interval has elapsed. Change the interval to 0.1 seconds to achieve smoother updates. Signed-off-by: Johannes Sixt <j6t@kdbg.org>
1 parent 2462961 commit 684fe92

File tree

3 files changed

+26
-51
lines changed

3 files changed

+26
-51
lines changed

progress.c

Lines changed: 24 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -45,62 +45,38 @@ struct progress {
4545
unsigned sparse;
4646
struct throughput *throughput;
4747
uint64_t start_ns;
48+
uint64_t last_update_ns;
4849
struct strbuf counters_sb;
4950
int title_len;
5051
int split;
5152
};
5253

53-
static volatile sig_atomic_t progress_update;
54-
5554
/*
5655
* These are only intended for testing the progress output, i.e. exclusively
5756
* for 'test-tool progress'.
5857
*/
5958
int progress_testing;
6059
uint64_t progress_test_ns = 0;
61-
void progress_test_force_update(void)
62-
{
63-
progress_update = 1;
64-
}
65-
66-
67-
static void progress_interval(int signum UNUSED)
60+
void progress_test_force_update(struct progress *progress)
6861
{
69-
progress_update = 1;
62+
progress->last_update_ns = 0;
7063
}
7164

72-
static void set_progress_signal(void)
73-
{
74-
struct sigaction sa;
75-
struct itimerval v;
76-
77-
if (progress_testing)
78-
return;
79-
80-
progress_update = 0;
81-
82-
memset(&sa, 0, sizeof(sa));
83-
sa.sa_handler = progress_interval;
84-
sigemptyset(&sa.sa_mask);
85-
sa.sa_flags = SA_RESTART;
86-
sigaction(SIGALRM, &sa, NULL);
87-
88-
v.it_interval.tv_sec = 1;
89-
v.it_interval.tv_usec = 0;
90-
v.it_value = v.it_interval;
91-
setitimer(ITIMER_REAL, &v, NULL);
92-
}
65+
/*
66+
* This value should not be too large, because progress indicator delay
67+
* is measured by number of display_progress() calls that also update
68+
* the progress text.
69+
*/
70+
#define NUM_UPDATES_PER_SEC 10
9371

94-
static void clear_progress_signal(void)
72+
static bool check_update_delay_expired(struct progress *progress)
9573
{
96-
struct itimerval v = {{0,},};
97-
98-
if (progress_testing)
99-
return;
100-
101-
setitimer(ITIMER_REAL, &v, NULL);
102-
signal(SIGALRM, SIG_IGN);
103-
progress_update = 0;
74+
uint64_t now = getnanotime();
75+
const uint64_t interval = 1000 * 1000 * 1000 / NUM_UPDATES_PER_SEC;
76+
bool update = interval <= now - progress->last_update_ns;
77+
if (update)
78+
progress->last_update_ns = now;
79+
return update;
10480
}
10581

10682
static int is_foreground_fd(int fd)
@@ -109,7 +85,8 @@ static int is_foreground_fd(int fd)
10985
return tpgrp < 0 || tpgrp == getpgid(0);
11086
}
11187

112-
static void display(struct progress *progress, uint64_t n, const char *done)
88+
static void display(struct progress *progress, uint64_t n, const char *done,
89+
bool progress_update)
11390
{
11491
const char *tp;
11592
struct strbuf *counters_sb = &progress->counters_sb;
@@ -246,14 +223,14 @@ void display_throughput(struct progress *progress, uint64_t total)
246223
tp->idx = (tp->idx + 1) % TP_IDX_MAX;
247224

248225
throughput_string(&tp->display, total, rate);
249-
if (progress->last_value != -1 && progress_update)
250-
display(progress, progress->last_value, NULL);
226+
if (progress->last_value != -1 && check_update_delay_expired(progress))
227+
display(progress, progress->last_value, NULL, true);
251228
}
252229

253230
void display_progress(struct progress *progress, uint64_t n)
254231
{
255232
if (progress)
256-
display(progress, n, NULL);
233+
display(progress, n, NULL, check_update_delay_expired(progress));
257234
}
258235

259236
static struct progress *start_progress_delay(struct repository *r,
@@ -266,14 +243,14 @@ static struct progress *start_progress_delay(struct repository *r,
266243
progress->total = total;
267244
progress->last_value = -1;
268245
progress->last_percent = -1;
269-
progress->delay = delay;
246+
progress->delay = delay * NUM_UPDATES_PER_SEC;
270247
progress->sparse = sparse;
271248
progress->throughput = NULL;
272249
progress->start_ns = getnanotime();
250+
progress->last_update_ns = progress->start_ns;
273251
strbuf_init(&progress->counters_sb, 0);
274252
progress->title_len = utf8_strwidth(title);
275253
progress->split = 0;
276-
set_progress_signal();
277254
trace2_region_enter("progress", title, r);
278255
return progress;
279256
}
@@ -341,9 +318,8 @@ static void force_last_update(struct progress *progress, const char *msg)
341318
rate = tp->curr_total / (misecs ? misecs : 1);
342319
throughput_string(&tp->display, tp->curr_total, rate);
343320
}
344-
progress_update = 1;
345321
buf = xstrfmt(", %s.\n", msg);
346-
display(progress, progress->last_value, buf);
322+
display(progress, progress->last_value, buf, true);
347323
free(buf);
348324
}
349325

@@ -376,7 +352,6 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
376352
force_last_update(progress, msg);
377353
log_trace2(progress);
378354

379-
clear_progress_signal();
380355
strbuf_release(&progress->counters_sb);
381356
if (progress->throughput)
382357
strbuf_release(&progress->throughput->display);

progress.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ struct repository;
99

1010
extern int progress_testing;
1111
extern uint64_t progress_test_ns;
12-
void progress_test_force_update(void);
12+
void progress_test_force_update(struct progress *progress);
1313

1414
#endif
1515

t/helper/test-progress.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ int cmd__progress(int argc, const char **argv)
8787
progress_test_ns = test_ms * 1000 * 1000;
8888
display_throughput(progress, byte_count);
8989
} else if (!strcmp(line.buf, "update")) {
90-
progress_test_force_update();
90+
progress_test_force_update(progress);
9191
} else if (!strcmp(line.buf, "stop")) {
9292
stop_progress(&progress);
9393
} else {

0 commit comments

Comments
 (0)