From 954c2d32c1bb9e13b4d59575b9f909636039c277 Mon Sep 17 00:00:00 2001 From: Andrew Wood Date: Fri, 4 Oct 2024 11:08:01 +0100 Subject: [PATCH] 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. --- src/include/pv-internal.h | 28 +++++++++------ src/pv/display.c | 73 +++++++++++++++++++-------------------- src/pv/state.c | 28 +++++++-------- src/pv/watchpid.c | 4 +-- 4 files changed, 70 insertions(+), 63 deletions(-) diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index a2669af..4d52a0a 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -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 * diff --git a/src/pv/display.c b/src/pv/display.c index 2a1b3df..872feb9 100644 --- a/src/pv/display.c +++ b/src/pv/display.c @@ -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; diff --git a/src/pv/state.c b/src/pv/state.c index 472175e..8b67d9f 100644 --- a/src/pv/state.c +++ b/src/pv/state.c @@ -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); } diff --git a/src/pv/watchpid.c b/src/pv/watchpid.c index 5ba2779..f9b6ab9 100644 --- a/src/pv/watchpid.c +++ b/src/pv/watchpid.c @@ -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);