progress: cleanup, less memory

Keep only a single `start` time and calculate the rest in delta
microseconds since then. Separate timestamps and durations into separate
sub-structures for clarity.

remove progress.t_acceptdata
It was recorded in FTP accept but never used anywhere.

Closes #22547
This commit is contained in:
Stefan Eissing 2026-08-11 17:09:26 +02:00 committed by Daniel Stenberg
parent fbfb2499f0
commit 35843dd635
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
13 changed files with 144 additions and 141 deletions

View file

@ -188,7 +188,7 @@ const struct curltime *Curl_pgrs_now(struct Curl_easy *data)
int Curl_pgrsDone(struct Curl_easy *data)
{
int rc;
data->progress.lastshow = 0;
data->progress.delta.lastshow_us = -1;
rc = Curl_pgrsUpdate(data); /* the final (forced) update */
if(rc)
return rc;
@ -247,7 +247,6 @@ static const char * const pgrs_timer_names[] = {
"PGRS-PRETRANSFER",
"PGRS-STARTTRANSFER",
"PGRS-POSTRANSFER",
"PGRS-STARTACCEPT",
"PGRS-REDIRECT",
};
@ -274,34 +273,33 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
break;
case TIMER_STARTOP:
/* This is set at the start of a transfer */
data->progress.t_startop = timestamp;
data->progress.t_startqueue = timestamp;
data->progress.t_postqueue = 0;
data->progress.delta.startop_us =
curlx_ptimediff_us(&timestamp, &data->progress.start);
data->progress.delta.startqueue_us = data->progress.delta.startop_us;
break;
case TIMER_STARTSINGLE:
/* This is set at the start of each single transfer */
data->progress.t_startsingle = timestamp;
data->progress.is_t_startransfer_set = FALSE;
data->progress.delta.startsingle_us =
curlx_ptimediff_us(&timestamp, &data->progress.start);
data->progress.startransfer_added = FALSE;
break;
case TIMER_POSTQUEUE:
/* Queue time is accumulative from all involved redirects */
data->progress.t_postqueue +=
curlx_ptimediff_us(&timestamp, &data->progress.t_startqueue);
break;
case TIMER_STARTACCEPT:
data->progress.t_acceptdata = timestamp;
data->progress.total.queued_us +=
curlx_ptimediff_us(&timestamp, &data->progress.start) -
data->progress.delta.startqueue_us;
break;
case TIMER_NAMELOOKUP:
delta = &data->progress.t_nslookup;
delta = &data->progress.total.nslookup_us;
break;
case TIMER_CONNECT:
delta = &data->progress.t_connect;
delta = &data->progress.total.connect_us;
break;
case TIMER_APPCONNECT:
delta = &data->progress.t_appconnect;
delta = &data->progress.total.appconnect_us;
break;
case TIMER_PRETRANSFER:
delta = &data->progress.t_pretransfer;
delta = &data->progress.total.pretransfer_us;
break;
case TIMER_STARTTRANSFER:
/* prevent updating t_starttransfer unless:
@ -310,25 +308,27 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
* This prevents repeated invocations of the function from incorrectly
* changing the t_starttransfer time.
*/
if(data->progress.is_t_startransfer_set) {
if(data->progress.startransfer_added) {
CURL_TRC_M(data, "[%s] ignored", pgrs_timer_name(timer));
return;
}
data->progress.is_t_startransfer_set = TRUE;
delta = &data->progress.t_starttransfer;
data->progress.startransfer_added = TRUE;
delta = &data->progress.total.starttransfer_us;
break;
case TIMER_POSTRANSFER:
delta = &data->progress.t_posttransfer;
delta = &data->progress.total.posttransfer_us;
break;
case TIMER_REDIRECT:
data->progress.t_redirect = curlx_ptimediff_us(&timestamp,
&data->progress.start);
data->progress.t_startqueue = timestamp;
data->progress.delta.startredirect_us =
curlx_ptimediff_us(&timestamp, &data->progress.start);
/* transfer starts queueing again */
data->progress.delta.startqueue_us =
data->progress.delta.startredirect_us;
break;
}
if(delta) {
timediff_t us = curlx_ptimediff_us(&timestamp,
&data->progress.t_startsingle);
timediff_t us = curlx_ptimediff_us(&timestamp, &data->progress.start) -
data->progress.delta.startsingle_us;
if(us < 1)
us = 1; /* make sure at least one microsecond passed */
*delta += us;
@ -350,13 +350,17 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
Curl_pgrsTimeWas(data, timer, *Curl_pgrs_now(data));
}
void Curl_pgrsStartNow(struct Curl_easy *data)
void Curl_pgrsStart(struct Curl_easy *data, const struct curltime *pnow)
{
struct Progress *p = &data->progress;
if(!pnow)
pnow = Curl_pgrs_now(data);
p->speeder_c = 0; /* reset the progress meter display */
p->start = *Curl_pgrs_now(data);
p->is_t_startransfer_set = FALSE;
p->start = *pnow;
memset(&p->delta, 0, sizeof(p->delta));
memset(&p->total, 0, sizeof(p->total));
p->startransfer_added = FALSE;
p->dl.cur_size = 0;
p->ul.cur_size = 0;
/* the sizes are unknown at start */
@ -456,21 +460,22 @@ static bool progress_calc(struct Curl_easy *data,
{
struct Progress * const p = &data->progress;
int i_next, i_oldest, i_latest;
timediff_t duration_us;
timediff_t duration_us, elapsed_us;
curl_off_t amount;
/* The time spent so far (from the start) in microseconds */
p->timespent = curlx_ptimediff_us(pnow, &p->start);
p->dl.speed = trspeed(p->dl.cur_size, p->timespent);
p->ul.speed = trspeed(p->ul.cur_size, p->timespent);
elapsed_us = curlx_ptimediff_us(pnow, &p->start);
p->total.spent_us = elapsed_us;
p->dl.speed = trspeed(p->dl.cur_size, p->total.spent_us);
p->ul.speed = trspeed(p->ul.cur_size, p->total.spent_us);
if(!p->speeder_c) { /* no previous record exists */
p->speed_amount[0] = p->dl.cur_size + p->ul.cur_size;
p->speed_time[0] = *pnow;
p->speed_time[0] = elapsed_us;
p->speeder_c++;
/* use the overall average at the start */
p->current_speed = p->ul.speed + p->dl.speed;
p->lastshow = pnow->tv_sec;
p->delta.lastshow_us = elapsed_us;
return TRUE;
}
/* We have at least one record now. Where to put the next and
@ -480,11 +485,11 @@ static bool progress_calc(struct Curl_easy *data,
/* Make a new record only when some time has passed.
* Too frequent calls otherwise ruin the history. */
if(curlx_ptimediff_ms(pnow, &p->speed_time[i_latest]) >= 1000) {
if((elapsed_us - p->speed_time[i_latest]) >= (1000 * 1000)) {
p->speeder_c++;
i_latest = i_next;
p->speed_amount[i_latest] = p->dl.cur_size + p->ul.cur_size;
p->speed_time[i_latest] = *pnow;
p->speed_time[i_latest] = elapsed_us;
}
else if(data->req.done) {
/* When a transfer is done, and we did not have a current speed
@ -493,7 +498,7 @@ static bool progress_calc(struct Curl_easy *data,
* reported speed since it no longer measures a full second. */
if(!p->current_speed) {
p->speed_amount[i_latest] = p->dl.cur_size + p->ul.cur_size;
p->speed_time[i_latest] = *pnow;
p->speed_time[i_latest] = elapsed_us;
}
}
else {
@ -507,8 +512,7 @@ static bool progress_calc(struct Curl_easy *data,
/* How much we transferred between oldest and current records */
amount = p->speed_amount[i_latest] - p->speed_amount[i_oldest];
/* How long this took */
duration_us = curlx_ptimediff_us(&p->speed_time[i_latest],
&p->speed_time[i_oldest]);
duration_us = p->speed_time[i_latest] - p->speed_time[i_oldest];
if(duration_us <= 0)
duration_us = 1;
@ -522,9 +526,10 @@ static bool progress_calc(struct Curl_easy *data,
p->current_speed = amount * 1000000 / duration_us;
}
if((p->lastshow == pnow->tv_sec) && !data->req.done)
if((p->delta.lastshow_us >= 0) && !data->req.done &&
((elapsed_us - p->delta.lastshow_us) >= (1000 * 1000)))
return FALSE;
p->lastshow = pnow->tv_sec;
p->delta.lastshow_us = elapsed_us;
return TRUE;
}
@ -569,7 +574,7 @@ static void progress_meter(struct Curl_easy *data)
char time_left[8];
char time_total[8];
char time_spent[8];
curl_off_t cur_secs = (curl_off_t)p->timespent / 1000000; /* seconds */
curl_off_t cur_secs = (curl_off_t)p->total.spent_us / 1000000;
if(!p->headers_out) {
if(data->state.resume_from) {
@ -731,5 +736,24 @@ void Curl_pgrsUpdate_nometer(struct Curl_easy *data)
void Curl_pgrsCompleted(struct Curl_easy *data)
{
struct Progress * const p = &data->progress;
p->timespent = curlx_ptimediff_us(Curl_pgrs_now(data), &p->start);
p->total.spent_us = curlx_ptimediff_us(Curl_pgrs_now(data), &p->start);
}
timediff_t Curl_pgrs_since_ms(struct Curl_easy *data,
const struct curltime *pnow,
timerid timer)
{
if(!pnow)
pnow = Curl_pgrs_now(data);
switch(timer) {
case TIMER_STARTOP:
return (curlx_ptimediff_us(pnow, &data->progress.start) -
data->progress.delta.startop_us) / 1000;
case TIMER_STARTSINGLE:
return (curlx_ptimediff_us(pnow, &data->progress.start) -
data->progress.delta.startsingle_us) / 1000;
default:
DEBUGASSERT(0);
return 0;
}
}