summaryrefslogtreecommitdiff
path: root/progress.c
diff options
context:
space:
mode:
Diffstat (limited to 'progress.c')
-rw-r--r--progress.c91
1 files changed, 41 insertions, 50 deletions
diff --git a/progress.c b/progress.c
index 2e31bec60f..5a99c9fbf0 100644
--- a/progress.c
+++ b/progress.c
@@ -25,17 +25,17 @@ struct throughput {
unsigned int last_bytes[TP_IDX_MAX];
unsigned int last_misecs[TP_IDX_MAX];
unsigned int idx;
- char display[32];
+ struct strbuf display;
};
struct progress {
const char *title;
- int last_value;
- unsigned total;
+ uint64_t last_value;
+ uint64_t total;
unsigned last_percent;
unsigned delay;
- unsigned delayed_percent_treshold;
struct throughput *throughput;
+ uint64_t start_ns;
};
static volatile sig_atomic_t progress_update;
@@ -78,36 +78,25 @@ static int is_foreground_fd(int fd)
return tpgrp < 0 || tpgrp == getpgid(0);
}
-static int display(struct progress *progress, unsigned n, const char *done)
+static int display(struct progress *progress, uint64_t n, const char *done)
{
const char *eol, *tp;
- if (progress->delay) {
- if (!progress_update || --progress->delay)
- return 0;
- if (progress->total) {
- unsigned percent = n * 100 / progress->total;
- if (percent > progress->delayed_percent_treshold) {
- /* inhibit this progress report entirely */
- clear_progress_signal();
- progress->delay = -1;
- progress->total = 0;
- return 0;
- }
- }
- }
+ if (progress->delay && (!progress_update || --progress->delay))
+ return 0;
progress->last_value = n;
- tp = (progress->throughput) ? progress->throughput->display : "";
+ tp = (progress->throughput) ? progress->throughput->display.buf : "";
eol = done ? done : " \r";
if (progress->total) {
unsigned percent = n * 100 / progress->total;
if (percent != progress->last_percent || progress_update) {
progress->last_percent = percent;
if (is_foreground_fd(fileno(stderr)) || done) {
- fprintf(stderr, "%s: %3u%% (%u/%u)%s%s",
- progress->title, percent, n,
- progress->total, tp, eol);
+ fprintf(stderr, "%s: %3u%% (%"PRIuMAX"/%"PRIuMAX")%s%s",
+ progress->title, percent,
+ (uintmax_t)n, (uintmax_t)progress->total,
+ tp, eol);
fflush(stderr);
}
progress_update = 0;
@@ -115,8 +104,8 @@ static int display(struct progress *progress, unsigned n, const char *done)
}
} else if (progress_update) {
if (is_foreground_fd(fileno(stderr)) || done) {
- fprintf(stderr, "%s: %u%s%s",
- progress->title, n, tp, eol);
+ fprintf(stderr, "%s: %"PRIuMAX"%s%s",
+ progress->title, (uintmax_t)n, tp, eol);
fflush(stderr);
}
progress_update = 0;
@@ -126,9 +115,10 @@ static int display(struct progress *progress, unsigned n, const char *done)
return 0;
}
-static void throughput_string(struct strbuf *buf, off_t total,
+static void throughput_string(struct strbuf *buf, uint64_t total,
unsigned int rate)
{
+ strbuf_reset(buf);
strbuf_addstr(buf, ", ");
strbuf_humanise_bytes(buf, total);
strbuf_addstr(buf, " | ");
@@ -136,12 +126,11 @@ static void throughput_string(struct strbuf *buf, off_t total,
strbuf_addstr(buf, "/s");
}
-void display_throughput(struct progress *progress, off_t total)
+void display_throughput(struct progress *progress, uint64_t total)
{
struct throughput *tp;
uint64_t now_ns;
unsigned int misecs, count, rate;
- struct strbuf buf = STRBUF_INIT;
if (!progress)
return;
@@ -154,6 +143,7 @@ void display_throughput(struct progress *progress, off_t total)
if (tp) {
tp->prev_total = tp->curr_total = total;
tp->prev_ns = now_ns;
+ strbuf_init(&tp->display, 0);
}
return;
}
@@ -193,20 +183,18 @@ void display_throughput(struct progress *progress, off_t total)
tp->last_misecs[tp->idx] = misecs;
tp->idx = (tp->idx + 1) % TP_IDX_MAX;
- throughput_string(&buf, total, rate);
- strncpy(tp->display, buf.buf, sizeof(tp->display));
- strbuf_release(&buf);
+ throughput_string(&tp->display, total, rate);
if (progress->last_value != -1 && progress_update)
display(progress, progress->last_value, NULL);
}
-int display_progress(struct progress *progress, unsigned n)
+int display_progress(struct progress *progress, uint64_t n)
{
return progress ? display(progress, n, NULL) : 0;
}
-struct progress *start_progress_delay(const char *title, unsigned total,
- unsigned percent_treshold, unsigned delay)
+static struct progress *start_progress_delay(const char *title, uint64_t total,
+ unsigned delay)
{
struct progress *progress = malloc(sizeof(*progress));
if (!progress) {
@@ -219,16 +207,21 @@ struct progress *start_progress_delay(const char *title, unsigned total,
progress->total = total;
progress->last_value = -1;
progress->last_percent = -1;
- progress->delayed_percent_treshold = percent_treshold;
progress->delay = delay;
progress->throughput = NULL;
+ progress->start_ns = getnanotime();
set_progress_signal();
return progress;
}
-struct progress *start_progress(const char *title, unsigned total)
+struct progress *start_delayed_progress(const char *title, uint64_t total)
+{
+ return start_progress_delay(title, total, 2);
+}
+
+struct progress *start_progress(const char *title, uint64_t total)
{
- return start_progress_delay(title, total, 0, 0);
+ return start_progress_delay(title, total, 0);
}
void stop_progress(struct progress **p_progress)
@@ -244,26 +237,24 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
*p_progress = NULL;
if (progress->last_value != -1) {
/* Force the last update */
- char buf[128], *bufp;
- size_t len = strlen(msg) + 5;
+ char *buf;
struct throughput *tp = progress->throughput;
- bufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);
if (tp) {
- struct strbuf strbuf = STRBUF_INIT;
- unsigned int rate = !tp->avg_misecs ? 0 :
- tp->avg_bytes / tp->avg_misecs;
- throughput_string(&strbuf, tp->curr_total, rate);
- strncpy(tp->display, strbuf.buf, sizeof(tp->display));
- strbuf_release(&strbuf);
+ uint64_t now_ns = getnanotime();
+ unsigned int misecs, rate;
+ misecs = ((now_ns - progress->start_ns) * 4398) >> 32;
+ rate = tp->curr_total / (misecs ? misecs : 1);
+ throughput_string(&tp->display, tp->curr_total, rate);
}
progress_update = 1;
- sprintf(bufp, ", %s.\n", msg);
- display(progress, progress->last_value, bufp);
- if (buf != bufp)
- free(bufp);
+ buf = xstrfmt(", %s.\n", msg);
+ display(progress, progress->last_value, buf);
+ free(buf);
}
clear_progress_signal();
+ if (progress->throughput)
+ strbuf_release(&progress->throughput->display);
free(progress->throughput);
free(progress);
}