Skip to content

Commit ef93bfb

Browse files
committed
Merge branch 'sg/progress-fix'
Regression fix for progress output. * sg/progress-fix: Test the progress display Revert "progress: use term_clear_line()"
2 parents 980351d + 2bb74b5 commit ef93bfb

7 files changed

+421
-16
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@ TEST_BUILTINS_OBJS += test-parse-options.o
729729
TEST_BUILTINS_OBJS += test-path-utils.o
730730
TEST_BUILTINS_OBJS += test-pkt-line.o
731731
TEST_BUILTINS_OBJS += test-prio-queue.o
732+
TEST_BUILTINS_OBJS += test-progress.o
732733
TEST_BUILTINS_OBJS += test-reach.o
733734
TEST_BUILTINS_OBJS += test-read-cache.o
734735
TEST_BUILTINS_OBJS += test-read-midx.o

progress.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ struct progress {
4545

4646
static volatile sig_atomic_t progress_update;
4747

48+
/*
49+
* These are only intended for testing the progress output, i.e. exclusively
50+
* for 'test-tool progress'.
51+
*/
52+
int progress_testing;
53+
uint64_t progress_test_ns = 0;
54+
void progress_test_force_update(void); /* To silence -Wmissing-prototypes */
55+
void progress_test_force_update(void)
56+
{
57+
progress_update = 1;
58+
}
59+
60+
4861
static void progress_interval(int signum)
4962
{
5063
progress_update = 1;
@@ -55,6 +68,9 @@ static void set_progress_signal(void)
5568
struct sigaction sa;
5669
struct itimerval v;
5770

71+
if (progress_testing)
72+
return;
73+
5874
progress_update = 0;
5975

6076
memset(&sa, 0, sizeof(sa));
@@ -72,6 +88,10 @@ static void set_progress_signal(void)
7288
static void clear_progress_signal(void)
7389
{
7490
struct itimerval v = {{0,},};
91+
92+
if (progress_testing)
93+
return;
94+
7595
setitimer(ITIMER_REAL, &v, NULL);
7696
signal(SIGALRM, SIG_IGN);
7797
progress_update = 0;
@@ -88,6 +108,7 @@ static void display(struct progress *progress, uint64_t n, const char *done)
88108
const char *tp;
89109
struct strbuf *counters_sb = &progress->counters_sb;
90110
int show_update = 0;
111+
int last_count_len = counters_sb->len;
91112

92113
if (progress->delay && (!progress_update || --progress->delay))
93114
return;
@@ -115,21 +136,27 @@ static void display(struct progress *progress, uint64_t n, const char *done)
115136
if (show_update) {
116137
if (is_foreground_fd(fileno(stderr)) || done) {
117138
const char *eol = done ? done : "\r";
139+
size_t clear_len = counters_sb->len < last_count_len ?
140+
last_count_len - counters_sb->len + 1 :
141+
0;
142+
/* The "+ 2" accounts for the ": ". */
143+
size_t progress_line_len = progress->title_len +
144+
counters_sb->len + 2;
145+
int cols = term_columns();
118146

119-
term_clear_line();
120147
if (progress->split) {
121-
fprintf(stderr, " %s%s", counters_sb->buf,
122-
eol);
123-
} else if (!done &&
124-
/* The "+ 2" accounts for the ": ". */
125-
term_columns() < progress->title_len +
126-
counters_sb->len + 2) {
127-
fprintf(stderr, "%s:\n %s%s",
128-
progress->title, counters_sb->buf, eol);
148+
fprintf(stderr, " %s%*s", counters_sb->buf,
149+
(int) clear_len, eol);
150+
} else if (!done && cols < progress_line_len) {
151+
clear_len = progress->title_len + 1 < cols ?
152+
cols - progress->title_len - 1 : 0;
153+
fprintf(stderr, "%s:%*s\n %s%s",
154+
progress->title, (int) clear_len, "",
155+
counters_sb->buf, eol);
129156
progress->split = 1;
130157
} else {
131-
fprintf(stderr, "%s: %s%s", progress->title,
132-
counters_sb->buf, eol);
158+
fprintf(stderr, "%s: %s%*s", progress->title,
159+
counters_sb->buf, (int) clear_len, eol);
133160
}
134161
fflush(stderr);
135162
}
@@ -147,6 +174,14 @@ static void throughput_string(struct strbuf *buf, uint64_t total,
147174
strbuf_humanise_rate(buf, rate * 1024);
148175
}
149176

177+
static uint64_t progress_getnanotime(struct progress *progress)
178+
{
179+
if (progress_testing)
180+
return progress->start_ns + progress_test_ns;
181+
else
182+
return getnanotime();
183+
}
184+
150185
void display_throughput(struct progress *progress, uint64_t total)
151186
{
152187
struct throughput *tp;
@@ -157,7 +192,7 @@ void display_throughput(struct progress *progress, uint64_t total)
157192
return;
158193
tp = progress->throughput;
159194

160-
now_ns = getnanotime();
195+
now_ns = progress_getnanotime(progress);
161196

162197
if (!tp) {
163198
progress->throughput = tp = xcalloc(1, sizeof(*tp));
@@ -289,7 +324,7 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
289324
struct throughput *tp = progress->throughput;
290325

291326
if (tp) {
292-
uint64_t now_ns = getnanotime();
327+
uint64_t now_ns = progress_getnanotime(progress);
293328
unsigned int misecs, rate;
294329
misecs = ((now_ns - progress->start_ns) * 4398) >> 32;
295330
rate = tp->curr_total / (misecs ? misecs : 1);

t/helper/test-progress.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* A test helper to exercise the progress display.
3+
*
4+
* Reads instructions from standard input, one instruction per line:
5+
*
6+
* "progress <items>" - Call display_progress() with the given item count
7+
* as parameter.
8+
* "throughput <bytes> <millis> - Call display_throughput() with the given
9+
* byte count as parameter. The 'millis'
10+
* specify the time elapsed since the
11+
* start_progress() call.
12+
* "update" - Set the 'progress_update' flag.
13+
*
14+
* See 't0500-progress-display.sh' for examples.
15+
*/
16+
#include "test-tool.h"
17+
#include "gettext.h"
18+
#include "parse-options.h"
19+
#include "progress.h"
20+
#include "strbuf.h"
21+
22+
/*
23+
* These are defined in 'progress.c', but are not exposed in 'progress.h',
24+
* because they are exclusively for testing.
25+
*/
26+
extern int progress_testing;
27+
extern uint64_t progress_test_ns;
28+
void progress_test_force_update(void);
29+
30+
int cmd__progress(int argc, const char **argv)
31+
{
32+
uint64_t total = 0;
33+
const char *title;
34+
struct strbuf line = STRBUF_INIT;
35+
struct progress *progress;
36+
37+
const char *usage[] = {
38+
"test-tool progress [--total=<n>] <progress-title>",
39+
NULL
40+
};
41+
struct option options[] = {
42+
OPT_INTEGER(0, "total", &total, "total number of items"),
43+
OPT_END(),
44+
};
45+
46+
argc = parse_options(argc, argv, NULL, options, usage, 0);
47+
if (argc != 1)
48+
die("need a title for the progress output");
49+
title = argv[0];
50+
51+
progress_testing = 1;
52+
progress = start_progress(title, total);
53+
while (strbuf_getline(&line, stdin) != EOF) {
54+
char *end;
55+
56+
if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
57+
uint64_t item_count = strtoull(end, &end, 10);
58+
if (*end != '\0')
59+
die("invalid input: '%s'\n", line.buf);
60+
display_progress(progress, item_count);
61+
} else if (skip_prefix(line.buf, "throughput ",
62+
(const char **) &end)) {
63+
uint64_t byte_count, test_ms;
64+
65+
byte_count = strtoull(end, &end, 10);
66+
if (*end != ' ')
67+
die("invalid input: '%s'\n", line.buf);
68+
test_ms = strtoull(end + 1, &end, 10);
69+
if (*end != '\0')
70+
die("invalid input: '%s'\n", line.buf);
71+
progress_test_ns = test_ms * 1000 * 1000;
72+
display_throughput(progress, byte_count);
73+
} else if (!strcmp(line.buf, "update"))
74+
progress_test_force_update();
75+
else
76+
die("invalid input: '%s'\n", line.buf);
77+
}
78+
stop_progress(&progress);
79+
80+
return 0;
81+
}

t/helper/test-tool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static struct test_cmd cmds[] = {
4242
{ "path-utils", cmd__path_utils },
4343
{ "pkt-line", cmd__pkt_line },
4444
{ "prio-queue", cmd__prio_queue },
45+
{ "progress", cmd__progress },
4546
{ "reach", cmd__reach },
4647
{ "read-cache", cmd__read_cache },
4748
{ "read-midx", cmd__read_midx },

t/helper/test-tool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ int cmd__parse_options(int argc, const char **argv);
3232
int cmd__path_utils(int argc, const char **argv);
3333
int cmd__pkt_line(int argc, const char **argv);
3434
int cmd__prio_queue(int argc, const char **argv);
35+
int cmd__progress(int argc, const char **argv);
3536
int cmd__reach(int argc, const char **argv);
3637
int cmd__read_cache(int argc, const char **argv);
3738
int cmd__read_midx(int argc, const char **argv);

0 commit comments

Comments
 (0)