Move calculated values out of state.display into a new structure, state.calc, to separate out the display portion from the calculation portion; and move history_interval into state.control, as it is a control parameter set at the start.

This commit is contained in:
Andrew Wood
2024-10-04 11:08:01 +01:00
parent 5112251894
commit 954c2d32c1
4 changed files with 70 additions and 63 deletions
+18 -10
View File
@@ -116,6 +116,7 @@ struct pvstate_s {
int watch_fd; /* fd to watch */
int output_fd; /* fd to write output to */
unsigned int average_rate_window; /* time window in seconds for average rate calculations */
unsigned int history_interval; /* seconds between each average rate calc history entry */
unsigned int width; /* screen width */
unsigned int height; /* screen height */
bool force; /* display even if not on terminal */
@@ -193,16 +194,28 @@ struct pvstate_s {
char lastoutput_buffer[PV_SIZEOF_LASTOUTPUT_BUFFER];
long double prev_elapsed_sec; /* elapsed sec at which rate last calculated */
long double prev_rate; /* last calculated instantaneous transfer rate */
long double prev_trans; /* bytes transferred since last rate calculation */
long double current_avg_rate; /* current average rate over last history intervals */
/*@only@*/ /*@null@*/ char *display_buffer; /* buffer for display string */
size_t display_buffer_size; /* size allocated to display buffer */
size_t display_string_len; /* length of string in display buffer */
off_t initial_offset; /* offset when first opened (when watching fds) */
size_t lastoutput_length; /* number of last-output bytes to show */
size_t format_segment_count; /* number of format string segments */
unsigned int prev_screen_width; /* screen width last time we were called */
bool display_visible; /* set once anything written to terminal */
} display;
/************************************
* Calculated state of the transfer *
************************************/
struct {
long double prev_elapsed_sec; /* elapsed sec at which rate last calculated */
long double prev_rate; /* last calculated instantaneous transfer rate */
long double prev_trans; /* bytes transferred since last rate calculation */
long double current_avg_rate; /* current average rate over last history intervals */
/* Keep track of progress over last intervals to compute current average rate. */
/*@null@*/ struct { /* state at previous intervals (circular buffer) */
long double elapsed_sec; /* time since start of transfer */
@@ -211,14 +224,9 @@ struct pvstate_s {
size_t history_len; /* total size of history array */
size_t history_first; /* index of oldest entry */
size_t history_last; /* index of newest entry */
size_t format_segment_count; /* number of format string segments */
int history_interval; /* seconds between each history entry */
unsigned int prev_screen_width; /* screen width last time we were called */
int percentage; /* transfer percentage completion */
bool display_visible; /* set once anything written to terminal */
} display;
} calc;
/********************
* Cursor/IPC state *
+36 -37
View File
@@ -608,21 +608,21 @@ static long bound_long(long x, long min, long max)
static void pv__update_average_rate_history(pvstate_t state, off_t total_bytes, long double elapsed_sec,
long double rate)
{
size_t first = state->display.history_first;
size_t last = state->display.history_last;
size_t first = state->calc.history_first;
size_t last = state->calc.history_last;
long double last_elapsed;
if (NULL == state->display.history)
if (NULL == state->calc.history)
return;
last_elapsed = state->display.history[last].elapsed_sec;
last_elapsed = state->calc.history[last].elapsed_sec;
/*
* Do nothing if this is not the first call but not enough time has
* elapsed since the previous call yet.
*/
if ((last_elapsed > 0.0)
&& (elapsed_sec < (last_elapsed + state->display.history_interval)))
&& (elapsed_sec < (last_elapsed + state->control.history_interval)))
return;
/*
@@ -630,25 +630,24 @@ static void pv__update_average_rate_history(pvstate_t state, off_t total_bytes,
* buffer.
*/
if (last_elapsed > 0.0) {
size_t len = state->display.history_len;
size_t len = state->calc.history_len;
last = (last + 1) % len;
state->display.history_last = last;
state->calc.history_last = last;
if (last == first) {
first = (first + 1) % len;
state->display.history_first = first;
state->calc.history_first = first;
}
}
state->display.history[last].elapsed_sec = elapsed_sec;
state->display.history[last].total_bytes = total_bytes;
state->calc.history[last].elapsed_sec = elapsed_sec;
state->calc.history[last].total_bytes = total_bytes;
if (first == last) {
state->display.current_avg_rate = rate;
state->calc.current_avg_rate = rate;
} else {
off_t bytes = (state->display.history[last].total_bytes - state->display.history[first].total_bytes);
long double sec =
(state->display.history[last].elapsed_sec - state->display.history[first].elapsed_sec);
state->display.current_avg_rate = (long double) bytes / sec;
off_t bytes = (state->calc.history[last].total_bytes - state->calc.history[first].total_bytes);
long double sec = (state->calc.history[last].elapsed_sec - state->calc.history[first].elapsed_sec);
state->calc.current_avg_rate = (long double) bytes / sec;
}
}
@@ -709,20 +708,20 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
* adding to that until a reasonable amount of time has passed to
* avoid rate spikes or division by zero.
*/
time_since_last = elapsed_sec - state->display.prev_elapsed_sec;
time_since_last = elapsed_sec - state->calc.prev_elapsed_sec;
if (time_since_last <= 0.01) {
rate = state->display.prev_rate;
state->display.prev_trans += bytes_since_last;
rate = state->calc.prev_rate;
state->calc.prev_trans += bytes_since_last;
} else {
rate = ((long double) bytes_since_last + state->display.prev_trans) / time_since_last;
state->display.prev_elapsed_sec = elapsed_sec;
state->display.prev_trans = 0;
rate = ((long double) bytes_since_last + state->calc.prev_trans) / time_since_last;
state->calc.prev_elapsed_sec = elapsed_sec;
state->calc.prev_trans = 0;
}
state->display.prev_rate = rate;
state->calc.prev_rate = rate;
/* Update history and current average rate for ETA. */
pv__update_average_rate_history(state, total_bytes, elapsed_sec, rate);
average_rate = state->display.current_avg_rate;
average_rate = state->calc.current_avg_rate;
/*
* If this is the final update at the end of the transfer, we
@@ -749,16 +748,16 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
* 0%-100%, 100%-0%, 0%-100%, and so on.
*/
if (rate > 0)
state->display.percentage += 2;
if (state->display.percentage > 199)
state->display.percentage = 0;
state->calc.percentage += 2;
if (state->calc.percentage > 199)
state->calc.percentage = 0;
} else if (state->control.numeric || state->display.component[PV_COMPONENT_PROGRESS].required) {
/*
* If we do know the total size, and we're going to show
* the percentage (numeric mode or a progress bar),
* calculate the percentage completion.
*/
state->display.percentage = pv__calc_percentage(total_bytes, state->control.size);
state->calc.percentage = pv__calc_percentage(total_bytes, state->control.size);
}
/*
@@ -825,7 +824,7 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
} else {
(void) pv_snprintf(state->display.display_buffer,
state->display.display_buffer_size, "%.99s%ld\n", numericprefix,
(long) (state->display.percentage));
(long) (state->calc.percentage));
}
state->display.display_string_len = strlen(state->display.display_buffer); /* flawfinder: ignore */
@@ -965,7 +964,7 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
eta =
pv__seconds_remaining(((off_t) total_bytes - state->display.initial_offset),
state->control.size - state->display.initial_offset,
state->display.current_avg_rate);
state->calc.current_avg_rate);
/*
* Bounds check, so we don't overrun the suffix buffer. This
@@ -1020,7 +1019,7 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
eta =
pv__seconds_remaining((off_t) (total_bytes - state->display.initial_offset),
state->control.size - state->display.initial_offset,
state->display.current_avg_rate);
state->calc.current_avg_rate);
/*
* Bounds check, so we don't overrun the suffix buffer. This
@@ -1152,11 +1151,11 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
/* Known size; show a bar and a percentage. */
size_t pct_width;
if (state->display.percentage < 0)
state->display.percentage = 0;
if (state->display.percentage > 100000)
state->display.percentage = 100000;
(void) pv_snprintf(pct, sizeof(pct), "%3ld%%", state->display.percentage);
if (state->calc.percentage < 0)
state->calc.percentage = 0;
if (state->calc.percentage > 100000)
state->calc.percentage = 100000;
(void) pv_snprintf(pct, sizeof(pct), "%3ld%%", state->calc.percentage);
pct_width = strlen(pct); /* flawfinder: ignore */
/* flawfinder: always \0-terminated by pv_snprintf() and the earlier memset(). */
@@ -1169,7 +1168,7 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
available_width = (int) (component_buf_size - 16);
/* The bar portion. */
bar_length = (int) ((available_width * state->display.percentage) / 100 - 1);
bar_length = (int) ((available_width * state->calc.percentage) / 100 - 1);
for (pad_count = 0; pad_count < bar_length; pad_count++) {
if (pad_count < available_width)
(void) pv_strlcat(component_content, "=", component_buf_size);
@@ -1193,7 +1192,7 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin
} else {
/* Unknown size; show a moving indicator. */
int indicator_position = state->display.percentage;
int indicator_position = state->calc.percentage;
available_width = (int) (state->control.width) - static_portion_size - 5;
+14 -14
View File
@@ -24,12 +24,12 @@
/* alloc / realloc history buffer */
static void pv_alloc_history(pvstate_t state)
{
if (NULL != state->display.history)
free(state->display.history);
state->display.history = NULL;
if (NULL != state->calc.history)
free(state->calc.history);
state->calc.history = NULL;
state->display.history = calloc((size_t) (state->display.history_len), sizeof(state->display.history[0]));
if (NULL == state->display.history) {
state->calc.history = calloc((size_t) (state->calc.history_len), sizeof(state->calc.history[0]));
if (NULL == state->calc.history) {
/*@-mustfreefresh@ */
/*
* splint note: the gettext calls made by _() cause memory
@@ -42,8 +42,8 @@ static void pv_alloc_history(pvstate_t state)
return;
}
state->display.history_first = state->display.history_last = 0;
state->display.history[0].elapsed_sec = 0.0; /* to be safe, memset() not recommended for doubles */
state->calc.history_first = state->calc.history_last = 0;
state->calc.history[0].elapsed_sec = 0.0; /* to be safe, memset() not recommended for doubles */
}
/*
@@ -156,9 +156,9 @@ void pv_state_free(pvstate_t state)
/*@+keeptrans@ */
/* splint - explicitly freeing this structure, so free() here is OK. */
if (NULL != state->display.history)
free(state->display.history);
state->display.history = NULL;
if (NULL != state->calc.history)
free(state->calc.history);
state->calc.history = NULL;
if (NULL != state->files.filename) {
unsigned int file_idx;
@@ -406,11 +406,11 @@ void pv_state_average_rate_window_set(pvstate_t state, unsigned int val)
val = 1;
state->control.average_rate_window = val;
if (val >= 20) {
state->display.history_len = (size_t) (val / 5 + 1);
state->display.history_interval = 5;
state->calc.history_len = (size_t) (val / 5 + 1);
state->control.history_interval = 5;
} else {
state->display.history_len = (size_t) (val + 1);
state->display.history_interval = 1;
state->calc.history_len = (size_t) (val + 1);
state->control.history_interval = 1;
}
pv_alloc_history(state);
}
+2 -2
View File
@@ -498,8 +498,8 @@ int pv_watchpid_scanfds(pvstate_t state,
/*@-mustfreeonly@ *//* splint - this is not a leak, this is a new entry. */
info_array[use_idx].state->display.display_buffer = NULL;
info_array[use_idx].state->display.display_buffer_size = 0;
info_array[use_idx].state->display.history = NULL;
info_array[use_idx].state->display.history_len = 0;
info_array[use_idx].state->calc.history = NULL;
info_array[use_idx].state->calc.history_len = 0;
/*@+mustfreeonly@ */
pv_state_average_rate_window_set(info_array[use_idx].state, state->control.average_rate_window);