time-keeping: keep timestamp in multi, always update

Always use curlx_now() when calling Curl_pgrs_now(data). Tests with the
"manual" updates to now proved differ more then 100ms in parallel testing.

Add `curlx_nowp()` to set current time into a struct curltime.
Add `curlx_ptimediff_ms() and friends, passing pointers.

Update documentation.

Closes #19998
This commit is contained in:
Stefan Eissing 2025-12-18 13:55:07 +01:00 committed by Daniel Stenberg
parent 308c347c8b
commit b4be1f271e
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
61 changed files with 471 additions and 502 deletions

View file

@ -102,7 +102,7 @@ static void pgrs_speedinit(struct Curl_easy *data)
* @unittest: 1606
*/
UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data,
struct curltime *pnow)
const struct curltime *pnow)
{
if(!data->set.low_speed_time || !data->set.low_speed_limit ||
Curl_xfer_recv_is_paused(data) || Curl_xfer_send_is_paused(data))
@ -116,7 +116,8 @@ UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data,
data->state.keeps_speed = *pnow;
else {
/* how long has it been under the limit */
timediff_t howlong = curlx_timediff_ms(*pnow, data->state.keeps_speed);
timediff_t howlong =
curlx_ptimediff_ms(pnow, &data->state.keeps_speed);
if(howlong >= data->set.low_speed_time * 1000) {
/* too long */
@ -141,23 +142,12 @@ UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data,
return CURLE_OK;
}
void Curl_pgrs_now_set(struct Curl_easy *data)
const struct curltime *Curl_pgrs_now(struct Curl_easy *data)
{
data->progress.now = curlx_now();
}
void Curl_pgrs_now_at_least(struct Curl_easy *data, struct curltime *pts)
{
if((pts->tv_sec > data->progress.now.tv_sec) ||
((pts->tv_sec == data->progress.now.tv_sec) &&
(pts->tv_usec > data->progress.now.tv_usec))) {
data->progress.now = *pts;
}
}
void Curl_pgrs_now_update(struct Curl_easy *data, struct Curl_easy *other)
{
Curl_pgrs_now_at_least(data, &other->progress.now);
struct curltime *pnow = data->multi ?
&data->multi->now : &data->progress.now;
curlx_pnow(pnow);
return pnow;
}
/*
@ -251,7 +241,7 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
case TIMER_POSTQUEUE:
/* Queue time is accumulative from all involved redirects */
data->progress.t_postqueue +=
curlx_timediff_us(timestamp, data->progress.t_startqueue);
curlx_ptimediff_us(&timestamp, &data->progress.t_startqueue);
break;
case TIMER_STARTACCEPT:
data->progress.t_acceptdata = timestamp;
@ -287,13 +277,14 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
delta = &data->progress.t_posttransfer;
break;
case TIMER_REDIRECT:
data->progress.t_redirect = curlx_timediff_us(timestamp,
data->progress.start);
data->progress.t_redirect = curlx_ptimediff_us(&timestamp,
&data->progress.start);
data->progress.t_startqueue = timestamp;
break;
}
if(delta) {
timediff_t us = curlx_timediff_us(timestamp, data->progress.t_startsingle);
timediff_t us = curlx_ptimediff_us(&timestamp,
&data->progress.t_startsingle);
if(us < 1)
us = 1; /* make sure at least one microsecond passed */
*delta += us;
@ -309,15 +300,15 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
*/
void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
{
Curl_pgrs_now_set(data); /* update on real progress */
Curl_pgrsTimeWas(data, timer, data->progress.now);
Curl_pgrsTimeWas(data, timer, *Curl_pgrs_now(data));
}
void Curl_pgrsStartNow(struct Curl_easy *data)
{
struct Progress *p = &data->progress;
p->speeder_c = 0; /* reset the progress meter display */
p->start = data->progress.now;
p->start = *Curl_pgrs_now(data);
p->is_t_startransfer_set = FALSE;
p->dl.cur_size = 0;
p->ul.cur_size = 0;
@ -330,7 +321,7 @@ void Curl_pgrs_download_inc(struct Curl_easy *data, size_t delta)
{
if(delta) {
data->progress.dl.cur_size += delta;
Curl_rlimit_drain(&data->progress.dl.rlimit, delta, &data->progress.now);
Curl_rlimit_drain(&data->progress.dl.rlimit, delta, Curl_pgrs_now(data));
}
}
@ -338,7 +329,7 @@ void Curl_pgrs_upload_inc(struct Curl_easy *data, size_t delta)
{
if(delta) {
data->progress.ul.cur_size += delta;
Curl_rlimit_drain(&data->progress.ul.rlimit, delta, &data->progress.now);
Curl_rlimit_drain(&data->progress.ul.rlimit, delta, Curl_pgrs_now(data));
}
}
@ -394,7 +385,8 @@ static curl_off_t trspeed(curl_off_t size, /* number of bytes */
}
/* returns TRUE if it is time to show the progress meter */
static bool progress_calc(struct Curl_easy *data, struct curltime *pnow)
static bool progress_calc(struct Curl_easy *data,
const struct curltime *pnow)
{
struct Progress * const p = &data->progress;
int i_next, i_oldest, i_latest;
@ -402,7 +394,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime *pnow)
curl_off_t amount;
/* The time spent so far (from the start) in microseconds */
p->timespent = curlx_timediff_us(*pnow, p->start);
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);
@ -422,7 +414,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime *pnow)
/* Make a new record only when some time has passed.
* Too frequent calls otherwise ruin the history. */
if(curlx_timediff_ms(*pnow, p->speed_time[i_latest]) >= 1000) {
if(curlx_ptimediff_ms(pnow, &p->speed_time[i_latest]) >= 1000) {
p->speeder_c++;
i_latest = i_next;
p->speed_amount[i_latest] = p->dl.cur_size + p->ul.cur_size;
@ -449,8 +441,8 @@ static bool progress_calc(struct Curl_easy *data, struct curltime *pnow)
/* 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_ms = curlx_timediff_ms(p->speed_time[i_latest],
p->speed_time[i_oldest]);
duration_ms = curlx_ptimediff_ms(&p->speed_time[i_latest],
&p->speed_time[i_oldest]);
if(duration_ms <= 0)
duration_ms = 1;
@ -635,7 +627,8 @@ static CURLcode pgrsupdate(struct Curl_easy *data, bool showprogress)
return CURLE_OK;
}
static CURLcode pgrs_update(struct Curl_easy *data, struct curltime *pnow)
static CURLcode pgrs_update(struct Curl_easy *data,
const struct curltime *pnow)
{
bool showprogress = progress_calc(data, pnow);
return pgrsupdate(data, showprogress);
@ -643,16 +636,16 @@ static CURLcode pgrs_update(struct Curl_easy *data, struct curltime *pnow)
CURLcode Curl_pgrsUpdate(struct Curl_easy *data)
{
return pgrs_update(data, &data->progress.now);
return pgrs_update(data, Curl_pgrs_now(data));
}
CURLcode Curl_pgrsCheck(struct Curl_easy *data)
{
CURLcode result;
result = pgrs_update(data, &data->progress.now);
result = pgrs_update(data, Curl_pgrs_now(data));
if(!result && !data->req.done)
result = pgrs_speedcheck(data, &data->progress.now);
result = pgrs_speedcheck(data, Curl_pgrs_now(data));
return result;
}
@ -661,5 +654,5 @@ CURLcode Curl_pgrsCheck(struct Curl_easy *data)
*/
void Curl_pgrsUpdate_nometer(struct Curl_easy *data)
{
(void)progress_calc(data, &data->progress.now);
(void)progress_calc(data, Curl_pgrs_now(data));
}