Pass more specific structures to pv_calculate_transfer_rate rather than the whole state (#165).

This commit is contained in:
Andrew Wood
2025-07-26 19:22:07 +01:00
parent b3c854b27a
commit 3b0891b128
4 changed files with 72 additions and 64 deletions
+1 -1
View File
@@ -490,7 +490,7 @@ typedef struct pvwatchfd_s *pvwatchfd_t;
void pv_error(pvstate_t, char *, ...);
int pv_main_loop(pvstate_t);
void pv_calculate_transfer_rate(pvstate_t, bool);
void pv_calculate_transfer_rate(pvtransfercalc_t, pvtransferstate_t, pvcontrol_t, pvdisplay_t, bool);
long pv_bound_long(long, long, long);
long pv_seconds_remaining(const off_t, const off_t, const long double);
+68 -61
View File
@@ -17,23 +17,24 @@
* rate, otherwise calulate the average rate from the difference between the
* current position + elapsed time pair, and the oldest pair in the buffer.
*/
static void pv__update_average_rate_history(pvstate_t state, long double rate)
static void pv__update_average_rate_history(pvtransfercalc_t calc, pvtransferstate_t transfer,
unsigned int history_interval, long double rate)
{
size_t first = state->calc.history_first;
size_t last = state->calc.history_last;
size_t first = calc->history_first;
size_t last = calc->history_last;
long double last_elapsed;
if (NULL == state->calc.history)
if (NULL == calc->history)
return;
last_elapsed = state->calc.history[last].elapsed_sec;
last_elapsed = 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)
&& (state->transfer.elapsed_seconds < (last_elapsed + state->control.history_interval)))
&& (transfer->elapsed_seconds < (last_elapsed + history_interval)))
return;
/*
@@ -41,53 +42,59 @@ static void pv__update_average_rate_history(pvstate_t state, long double rate)
* buffer.
*/
if (last_elapsed > 0.0) {
size_t len = state->calc.history_len;
size_t len = calc->history_len;
last = (last + 1) % len;
state->calc.history_last = last;
calc->history_last = last;
if (last == first) {
first = (first + 1) % len;
state->calc.history_first = first;
calc->history_first = first;
}
}
state->calc.history[last].elapsed_sec = state->transfer.elapsed_seconds;
state->calc.history[last].transferred = state->transfer.transferred;
calc->history[last].elapsed_sec = transfer->elapsed_seconds;
calc->history[last].transferred = transfer->transferred;
if (first == last) {
state->calc.current_avg_rate = rate;
calc->current_avg_rate = rate;
} else {
off_t bytes = (state->calc.history[last].transferred - state->calc.history[first].transferred);
long double sec = (state->calc.history[last].elapsed_sec - state->calc.history[first].elapsed_sec);
state->calc.current_avg_rate = (long double) bytes / sec;
off_t bytes = (calc->history[last].transferred - calc->history[first].transferred);
long double sec = (calc->history[last].elapsed_sec - calc->history[first].elapsed_sec);
calc->current_avg_rate = (long double) bytes / sec;
}
}
/*
* Update all calculated transfer state (state->calc).
* Update all calculated transfer state (usually state->calc).
*
* If "final" is true, this is the final update, so
* state->calc.transfer_rate and state->calc.average_rate are given as an
* average over the whole transfer; otherwise they are the current transfer
* rate and current average rate.
* If "final" is true, this is the final update, so calc->transfer_rate and
* calc->average_rate are given as an average over the whole transfer;
* otherwise they are the current transfer rate and current average rate.
*
* The value of state->calc.percentage will reflect the percentage
* completion if state->control.size is greater than zero, otherwise it will
* increase by 2 each call and wrap at 200.
* The value of calc->percentage will reflect the percentage completion if
* control->size is greater than zero, otherwise it will increase by 2 each
* call and wrap at 200.
*/
void pv_calculate_transfer_rate(pvstate_t state, bool final)
void pv_calculate_transfer_rate(pvtransfercalc_t calc, pvtransferstate_t transfer, pvcontrol_t control,
pvdisplay_t display, bool final)
{
off_t bytes_since_last;
long double time_since_last, transfer_rate, average_rate;
/* Quick safety check - state must exist. */
if (NULL == state)
/* Quick safety checks for null pointers. */
if (NULL == calc)
return;
if (NULL == transfer)
return;
if (NULL == control)
return;
if (NULL == display)
return;
bytes_since_last = 0;
if (state->transfer.transferred >= 0) {
bytes_since_last = state->transfer.transferred - state->calc.prev_transferred;
state->calc.prev_transferred = state->transfer.transferred;
if (transfer->transferred >= 0) {
bytes_since_last = transfer->transferred - calc->prev_transferred;
calc->prev_transferred = transfer->transferred;
}
/*
@@ -96,37 +103,37 @@ void pv_calculate_transfer_rate(pvstate_t state, bool final)
* adding to that until a reasonable amount of time has passed to
* avoid rate spikes or division by zero.
*/
time_since_last = state->transfer.elapsed_seconds - state->calc.prev_elapsed_sec;
time_since_last = transfer->elapsed_seconds - calc->prev_elapsed_sec;
if (time_since_last <= 0.01) {
transfer_rate = state->calc.prev_rate;
state->calc.prev_trans += bytes_since_last;
transfer_rate = calc->prev_rate;
calc->prev_trans += bytes_since_last;
} else {
long double measured_rate;
transfer_rate = ((long double) bytes_since_last + state->calc.prev_trans) / time_since_last;
transfer_rate = ((long double) bytes_since_last + calc->prev_trans) / time_since_last;
measured_rate = transfer_rate;
state->calc.prev_elapsed_sec = state->transfer.elapsed_seconds;
state->calc.prev_trans = 0;
calc->prev_elapsed_sec = transfer->elapsed_seconds;
calc->prev_trans = 0;
if (state->control.bits)
if (control->bits)
measured_rate = 8.0 * measured_rate;
if ((state->calc.measurements_taken < 1) || (measured_rate < state->calc.rate_min)) {
state->calc.rate_min = measured_rate;
if ((calc->measurements_taken < 1) || (measured_rate < calc->rate_min)) {
calc->rate_min = measured_rate;
}
if (measured_rate > state->calc.rate_max) {
state->calc.rate_max = measured_rate;
if (measured_rate > calc->rate_max) {
calc->rate_max = measured_rate;
}
state->calc.rate_sum += measured_rate;
state->calc.ratesquared_sum += (measured_rate * measured_rate);
state->calc.measurements_taken++;
calc->rate_sum += measured_rate;
calc->ratesquared_sum += (measured_rate * measured_rate);
calc->measurements_taken++;
}
state->calc.prev_rate = transfer_rate;
calc->prev_rate = transfer_rate;
/* Update history and current average rate for ETA. */
pv__update_average_rate_history(state, transfer_rate);
average_rate = state->calc.current_avg_rate;
pv__update_average_rate_history(calc, transfer, control->history_interval, transfer_rate);
average_rate = calc->current_avg_rate;
/*
* If this is the final update at the end of the transfer, we
@@ -135,18 +142,18 @@ void pv_calculate_transfer_rate(pvstate_t state, bool final)
*/
if (final) {
/* Safety check to avoid division by zero. */
if (state->transfer.elapsed_seconds < 0.000001)
state->transfer.elapsed_seconds = 0.000001;
if (transfer->elapsed_seconds < 0.000001)
transfer->elapsed_seconds = 0.000001;
average_rate =
(((long double) (state->transfer.transferred)) -
((long double) state->display.initial_offset)) / (long double) (state->transfer.elapsed_seconds);
(((long double) (transfer->transferred)) -
((long double) display->initial_offset)) / (long double) (transfer->elapsed_seconds);
transfer_rate = average_rate;
}
state->calc.transfer_rate = transfer_rate;
state->calc.average_rate = average_rate;
calc->transfer_rate = transfer_rate;
calc->average_rate = average_rate;
if (state->control.size <= 0) {
if (control->size <= 0) {
/*
* If we don't know the total size of the incoming data,
* then for a percentage, we gradually increase the
@@ -156,16 +163,16 @@ void pv_calculate_transfer_rate(pvstate_t state, bool final)
* 0%-100%, 100%-0%, 0%-100%, and so on.
*/
if (transfer_rate > 0)
state->calc.percentage += 2;
if (state->calc.percentage > 199)
state->calc.percentage = 0;
calc->percentage += 2;
if (calc->percentage > 199)
calc->percentage = 0;
} else {
state->calc.percentage = pv_percentage(state->transfer.transferred, state->control.size);
calc->percentage = pv_percentage(transfer->transferred, control->size);
}
/* Ensure the percentage is never negative or huge. */
if (state->calc.percentage < 0.0)
state->calc.percentage = 0.0;
if (state->calc.percentage > 100000.0)
state->calc.percentage = 100000.0;
if (calc->percentage < 0.0)
calc->percentage = 0.0;
if (calc->percentage > 100000.0)
calc->percentage = 100000.0;
}
+1 -1
View File
@@ -1194,7 +1194,7 @@ void pv_display(pvstate_t state, bool final)
pv_sig_checkbg();
pv_calculate_transfer_rate(state, final);
pv_calculate_transfer_rate(&(state->calc), &(state->transfer), &(state->control), &(state->display), final);
/*
* Enable colour on the main display, and disable it on the extra
+2 -1
View File
@@ -506,7 +506,8 @@ int pv_main_loop(pvstate_t state)
if (state->control.no_display) {
/* If there's no display, calculate rate for the statistics. */
pv_calculate_transfer_rate(state, final_update);
pv_calculate_transfer_rate(&(state->calc), &(state->transfer), &(state->control),
&(state->display), final_update);
} else {
/* Produce the display. */
pv_display(state, final_update);