[libstdc++-v3] [testsuite] improve future/*/poll.cc calibration

30_threads/future/members/poll.cc has calibration code that, on
systems with very low clock resolution, may spuriously fail to run.
Even when it does run, low resolution and reasonable
timeouts limit severely the viability of increasing the loop counts so
as to reduce measurement noise, so we end up with very noisy results.

On various vxworks targets, high iteration count (low-noise)
measurements confirmed that some of the operations that we expected to
be up to 100x slower than the fastest ones can run a little slower
than that and, with significant noise, may seem to be even slower,
comparatively.

Bump the factors up to 200x, so that we have plenty of margin over
measured results.


for  libstdc++-v3/ChangeLog

	* testsuite/30_threads/future/members/poll.cc: Factor out
	calibration, and run it unconditionally.  Lower its
	strictness.  Bump wait_until_*'s slowness factor.
This commit is contained in:
Alexandre Oliva 2024-09-02 11:32:03 -03:00 committed by Alexandre Oliva
parent 410061b15a
commit af1500dd8c

View File

@ -41,52 +41,75 @@ print(const char* desc, Duration dur)
return d;
}
static void
calibrate()
{
/* After set_value, wait_for is faster, so use that for the
calibration loops to avoid zero at low clock resultions. */
promise<int> p = {};
future<int> f = p.get_future();
p.set_value(1);
auto start = chrono::high_resolution_clock::now();
auto stop = start;
/* Loop until the clock advances, so that start is right after a
time increment. */
do
stop = chrono::high_resolution_clock::now();
while (start == stop);
/* This approximates the smallest time increment we may expect to be
able to measure. It doesn't have to be very precise, just a
ballpart of the right magnitude. */
auto tick = stop - start;
int i = 0;
start = stop;
/* Now until the clock advances again, so that stop is right
after another time increment. */
do
{
f.wait_for(chrono::seconds(0));
stop = chrono::high_resolution_clock::now();
i++;
}
while (start == stop);
/* Aim for some 10 ticks. This won't be quite right if now() takes
up a significant portion of the loop time, but we'll measure
without that and adjust in the loop below. */
if (iterations < i * 10)
iterations = i * 10;
/* We aim for some 10 ticks for the loop that's expected to be fastest,
but even if we don't get quite that many, we're still fine. */
iterations /= 2;
do
{
iterations *= 2;
start = chrono::high_resolution_clock::now();
for(int i = 0; i < iterations; i++)
f.wait_for(chrono::seconds(0));
stop = chrono::high_resolution_clock::now();
}
while (stop - start < 5 * tick);
}
int main()
{
/* First, calibrate the iteration count so that we don't get any of
the actual measurement loops to complete in less than the clock
granularity. */
calibrate ();
promise<int> p;
future<int> f = p.get_future();
start_over:
auto start = chrono::high_resolution_clock::now();
for(int i = 0; i < iterations; i++)
f.wait_for(chrono::seconds(0));
auto stop = chrono::high_resolution_clock::now();
/* We've run too few iterations for the clock resolution.
Attempt to calibrate it. */
if (start == stop)
{
/* After set_value, wait_for is faster, so use that for the
calibration to avoid zero at low clock resultions. */
promise<int> pc;
future<int> fc = pc.get_future();
pc.set_value(1);
/* Loop until the clock advances, so that start is right after a
time increment. */
do
start = chrono::high_resolution_clock::now();
while (start == stop);
int i = 0;
/* Now until the clock advances again, so that stop is right
after another time increment. */
do
{
fc.wait_for(chrono::seconds(0));
stop = chrono::high_resolution_clock::now();
i++;
}
while (start == stop);
/* Go for some 10 cycles, but if we're already past that and
still get into the calibration loop, double the iteration
count and try again. */
if (iterations < i * 10)
iterations = i * 10;
else
iterations *= 2;
goto start_over;
}
double wait_for_0 = print("wait_for(0s)", stop - start);
start = chrono::high_resolution_clock::now();
@ -129,15 +152,21 @@ int main()
// after the result is ready.
VERIFY( wait_for_0 < (ready * 30) );
// Polling before ready using wait_until(min) should not be terribly slow.
VERIFY( wait_until_sys_min < (ready * 100) );
VERIFY( wait_until_steady_min < (ready * 100) );
// Polling before ready using wait_until(min) should not be terribly
// slow. We hope for no more than 100x slower, but a little over
// 100x has been observed, and since the measurements may have a lot
// of noise, and increasing the measurement precision through
// additional iterations would make the test run for too long on
// systems with very low clock precision (60Hz clocks are not
// unheard of), we tolerate a lot of error.
VERIFY( wait_until_sys_min < (ready * 200) );
VERIFY( wait_until_steady_min < (ready * 200) );
// The following two tests fail with GCC 11, see
// https://gcc.gnu.org/pipermail/libstdc++/2020-November/051422.html
#if 0
// Polling before ready using wait_until(epoch) should not be terribly slow.
VERIFY( wait_until_sys_epoch < (ready * 100) );
VERIFY( wait_until_steady_epoch < (ready * 100) );
VERIFY( wait_until_sys_epoch < (ready * 200) );
VERIFY( wait_until_steady_epoch < (ready * 200) );
#endif
}