mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Fix flaky tests: add iteration guards, yield in busy-waits, cap thread count
libeigen/eigen!2208 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
@@ -224,10 +224,14 @@ void transformations() {
|
||||
t4 *= aa3;
|
||||
VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
|
||||
|
||||
do {
|
||||
v3 = Vector3::Random();
|
||||
dont_over_optimize(v3);
|
||||
} while (v3.cwiseAbs().minCoeff() < NumTraits<Scalar>::epsilon());
|
||||
{
|
||||
int guard = 0;
|
||||
do {
|
||||
v3 = Vector3::Random();
|
||||
dont_over_optimize(v3);
|
||||
} while (v3.cwiseAbs().minCoeff() < NumTraits<Scalar>::epsilon() && (++guard) < 100);
|
||||
VERIFY(guard < 100);
|
||||
}
|
||||
Translation3 tv3(v3);
|
||||
Transform3 t5(tv3);
|
||||
t4 = tv3;
|
||||
@@ -381,9 +385,13 @@ void transformations() {
|
||||
// test transform inversion
|
||||
t0.setIdentity();
|
||||
t0.translate(v0);
|
||||
do {
|
||||
t0.linear().setRandom();
|
||||
} while (t0.linear().jacobiSvd().singularValues()(2) < test_precision<Scalar>());
|
||||
{
|
||||
int guard = 0;
|
||||
do {
|
||||
t0.linear().setRandom();
|
||||
} while (t0.linear().jacobiSvd().singularValues()(2) < test_precision<Scalar>() && (++guard) < 100);
|
||||
VERIFY(guard < 100);
|
||||
}
|
||||
Matrix4 t044 = Matrix4::Zero();
|
||||
t044(3, 3) = 1;
|
||||
t044.block(0, 0, t0.matrix().rows(), 4) = t0.matrix();
|
||||
|
||||
@@ -26,16 +26,24 @@ void signed_integer_type_tests(const MatrixType& m) {
|
||||
|
||||
MatrixType m1(rows, cols), m2 = MatrixType::Random(rows, cols), mzero = MatrixType::Zero(rows, cols);
|
||||
|
||||
do {
|
||||
m1 = MatrixType::Random(rows, cols);
|
||||
} while (m1 == mzero || m1 == m2);
|
||||
{
|
||||
int guard = 0;
|
||||
do {
|
||||
m1 = MatrixType::Random(rows, cols);
|
||||
} while ((m1 == mzero || m1 == m2) && (++guard) < 100);
|
||||
VERIFY(guard < 100);
|
||||
}
|
||||
|
||||
// check linear structure
|
||||
|
||||
Scalar s1;
|
||||
do {
|
||||
s1 = internal::random<Scalar>();
|
||||
} while (s1 == 0);
|
||||
{
|
||||
int guard = 0;
|
||||
do {
|
||||
s1 = internal::random<Scalar>();
|
||||
} while (s1 == 0 && (++guard) < 100);
|
||||
VERIFY(guard < 100);
|
||||
}
|
||||
|
||||
VERIFY_IS_EQUAL(-(-m1), m1);
|
||||
VERIFY_IS_EQUAL(-m2 + m1 + m2, m1);
|
||||
@@ -63,13 +71,21 @@ void integer_type_tests(const MatrixType& m) {
|
||||
SquareMatrixType identity = SquareMatrixType::Identity(rows, rows), square = SquareMatrixType::Random(rows, rows);
|
||||
VectorType v1(rows), v2 = VectorType::Random(rows), vzero = VectorType::Zero(rows);
|
||||
|
||||
do {
|
||||
m1 = MatrixType::Random(rows, cols);
|
||||
} while (m1 == mzero || m1 == m2);
|
||||
{
|
||||
int guard = 0;
|
||||
do {
|
||||
m1 = MatrixType::Random(rows, cols);
|
||||
} while ((m1 == mzero || m1 == m2) && (++guard) < 100);
|
||||
VERIFY(guard < 100);
|
||||
}
|
||||
|
||||
do {
|
||||
v1 = VectorType::Random(rows);
|
||||
} while (v1 == vzero || v1 == v2);
|
||||
{
|
||||
int guard = 0;
|
||||
do {
|
||||
v1 = VectorType::Random(rows);
|
||||
} while ((v1 == vzero || v1 == v2) && (++guard) < 100);
|
||||
VERIFY(guard < 100);
|
||||
}
|
||||
|
||||
VERIFY_IS_APPROX(v1, v1);
|
||||
VERIFY_IS_NOT_APPROX(v1, 2 * v1);
|
||||
|
||||
@@ -106,10 +106,10 @@ void lu_invertible() {
|
||||
MatrixType m1(size, size), m2(size, size), m3(size, size);
|
||||
FullPivLU<MatrixType> lu;
|
||||
lu.setThreshold(RealScalar(0.01));
|
||||
do {
|
||||
m1 = MatrixType::Random(size, size);
|
||||
lu.compute(m1);
|
||||
} while (!lu.isInvertible());
|
||||
// Create a random diagonally dominant (thus invertible) matrix.
|
||||
m1 = MatrixType::Random(size, size);
|
||||
m1.diagonal().array() += RealScalar(2 * size);
|
||||
lu.compute(m1);
|
||||
|
||||
VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
|
||||
VERIFY(0 == lu.dimensionOfKernel());
|
||||
|
||||
@@ -28,12 +28,9 @@ void inverse_general_4x4(int repeat) {
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
double error_sum = 0., error_max = 0.;
|
||||
for (int i = 0; i < repeat; ++i) {
|
||||
MatrixType m;
|
||||
bool is_invertible;
|
||||
do {
|
||||
m = MatrixType::Random();
|
||||
is_invertible = Eigen::FullPivLU<MatrixType>(m).isInvertible();
|
||||
} while (!is_invertible);
|
||||
// Create a random diagonally dominant (thus invertible) matrix.
|
||||
MatrixType m = MatrixType::Random();
|
||||
m.diagonal().array() += Scalar(8); // 2 * 4 for a 4x4 matrix.
|
||||
MatrixType inv = m.inverse();
|
||||
double error = double((m * inv - MatrixType::Identity()).norm());
|
||||
error_sum += error;
|
||||
|
||||
@@ -154,10 +154,10 @@ void qr() {
|
||||
{
|
||||
MatrixType m2, m3;
|
||||
Index size = rows;
|
||||
do {
|
||||
m1 = MatrixType::Random(size, size);
|
||||
qr.compute(m1);
|
||||
} while (!qr.isInvertible());
|
||||
// Create a random diagonally dominant (thus invertible) matrix.
|
||||
m1 = MatrixType::Random(size, size);
|
||||
m1.diagonal().array() += Scalar(2 * size);
|
||||
qr.compute(m1);
|
||||
MatrixType m1_inv = qr.inverse();
|
||||
m3 = m1 * MatrixType::Random(size, cols2);
|
||||
m2 = qr.solve(m3);
|
||||
|
||||
@@ -56,10 +56,10 @@ void qr() {
|
||||
{
|
||||
MatrixType m2, m3;
|
||||
Index size = rows;
|
||||
do {
|
||||
m1 = MatrixType::Random(size, size);
|
||||
qr.compute(m1);
|
||||
} while (!qr.isInvertible());
|
||||
// Create a random diagonally dominant (thus invertible) matrix.
|
||||
m1 = MatrixType::Random(size, size);
|
||||
m1.diagonal().array() += Scalar(2 * size);
|
||||
qr.compute(m1);
|
||||
MatrixType m1_inv = qr.inverse();
|
||||
m3 = m1 * MatrixType::Random(size, cols2);
|
||||
m2 = qr.solve(m3);
|
||||
|
||||
@@ -52,13 +52,11 @@ void stable_norm(const MatrixType& m) {
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
// get a non-zero random factor
|
||||
Scalar factor = internal::random<Scalar>();
|
||||
while (numext::abs2(factor) < RealScalar(1e-4)) factor = internal::random<Scalar>();
|
||||
// Get a random factor bounded away from zero: |factor| >= 0.1.
|
||||
Scalar factor = internal::random<Scalar>(Scalar(RealScalar(0.1)), Scalar(RealScalar(1)));
|
||||
Scalar big = factor * ((std::numeric_limits<RealScalar>::max)() * RealScalar(1e-4));
|
||||
|
||||
factor = internal::random<Scalar>();
|
||||
while (numext::abs2(factor) < RealScalar(1e-4)) factor = internal::random<Scalar>();
|
||||
factor = internal::random<Scalar>(Scalar(RealScalar(0.1)), Scalar(RealScalar(1)));
|
||||
Scalar small = factor * ((std::numeric_limits<RealScalar>::min)() * RealScalar(1e4));
|
||||
|
||||
Scalar one(1);
|
||||
@@ -217,12 +215,11 @@ void test_empty() {
|
||||
template <typename Scalar>
|
||||
void test_hypot() {
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
Scalar factor = internal::random<Scalar>();
|
||||
while (numext::abs2(factor) < RealScalar(1e-4)) factor = internal::random<Scalar>();
|
||||
// Get a random factor bounded away from zero: |factor| >= 0.1.
|
||||
Scalar factor = internal::random<Scalar>(Scalar(RealScalar(0.1)), Scalar(RealScalar(1)));
|
||||
Scalar big = factor * ((std::numeric_limits<RealScalar>::max)() * RealScalar(1e-4));
|
||||
|
||||
factor = internal::random<Scalar>();
|
||||
while (numext::abs2(factor) < RealScalar(1e-4)) factor = internal::random<Scalar>();
|
||||
factor = internal::random<Scalar>(Scalar(RealScalar(0.1)), Scalar(RealScalar(1)));
|
||||
Scalar small = factor * ((std::numeric_limits<RealScalar>::min)() * RealScalar(1e4));
|
||||
|
||||
Scalar one(1), zero(0), sqrt2(std::sqrt(2)), nan(std::numeric_limits<RealScalar>::quiet_NaN());
|
||||
|
||||
@@ -177,8 +177,8 @@ void svd_min_norm(const MatrixType& m) {
|
||||
int guard = 0;
|
||||
do {
|
||||
m2.setRandom();
|
||||
} while (SVD_FOR_MIN_NORM(MatrixType2)(m2).setThreshold(test_precision<Scalar>()).rank() != rank && (++guard) < 10);
|
||||
VERIFY(guard < 10);
|
||||
} while (SVD_FOR_MIN_NORM(MatrixType2)(m2).setThreshold(test_precision<Scalar>()).rank() != rank && (++guard) < 100);
|
||||
VERIFY(guard < 100);
|
||||
|
||||
RhsType2 rhs2 = RhsType2::Random(rank);
|
||||
// use QR to find a reference minimal norm solution
|
||||
|
||||
@@ -74,7 +74,7 @@ const int TestQueue::kQueueSize;
|
||||
// fake queues. Ensure that it does not crash, consumers don't deadlock and
|
||||
// number of blocked and unblocked threads match.
|
||||
static void test_stress_eventcount() {
|
||||
const int kThreads = std::thread::hardware_concurrency();
|
||||
const int kThreads = (std::min)(static_cast<int>(std::thread::hardware_concurrency()), 16);
|
||||
static const int kEvents = 1 << 16;
|
||||
static const int kQueues = 10;
|
||||
|
||||
|
||||
@@ -12,6 +12,18 @@
|
||||
#include "main.h"
|
||||
#include "Eigen/ThreadPool"
|
||||
|
||||
// Spin-wait with yielding until the condition is met, or fail after a timeout.
|
||||
// Returns true if the condition was met before the deadline.
|
||||
template <typename Cond>
|
||||
static bool spin_wait(Cond cond, int timeout_seconds = 60) {
|
||||
auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds);
|
||||
while (!cond()) {
|
||||
if (std::chrono::steady_clock::now() > deadline) return false;
|
||||
std::this_thread::yield();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_create_destroy_empty_pool() {
|
||||
// Just create and destroy the pool. This will wind up and tear down worker
|
||||
// threads. Ensure there are no issues in that logic.
|
||||
@@ -38,12 +50,12 @@ static void test_parallelism(bool allow_spinning) {
|
||||
VERIFY_LE(thread_id, kThreads - 1);
|
||||
running++;
|
||||
while (phase < 1) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
done++;
|
||||
});
|
||||
}
|
||||
while (running != kThreads) {
|
||||
}
|
||||
VERIFY(spin_wait([&] { return running == kThreads; }));
|
||||
running = 0;
|
||||
phase = 1;
|
||||
// Now, while the previous tasks exit, schedule another kThreads tasks and
|
||||
@@ -52,6 +64,7 @@ static void test_parallelism(bool allow_spinning) {
|
||||
tp.Schedule([&, i]() {
|
||||
running++;
|
||||
while (phase < 2) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
// When all tasks are running, half of tasks exit, quarter of tasks
|
||||
// continue running and quarter of tasks schedule another 2 tasks each.
|
||||
@@ -62,6 +75,7 @@ static void test_parallelism(bool allow_spinning) {
|
||||
} else if (i < 3 * kThreads / 4) {
|
||||
running++;
|
||||
while (phase < 3) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
done++;
|
||||
} else {
|
||||
@@ -69,6 +83,7 @@ static void test_parallelism(bool allow_spinning) {
|
||||
tp.Schedule([&]() {
|
||||
running++;
|
||||
while (phase < 3) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
done++;
|
||||
});
|
||||
@@ -77,23 +92,21 @@ static void test_parallelism(bool allow_spinning) {
|
||||
done++;
|
||||
});
|
||||
}
|
||||
while (running != kThreads) {
|
||||
}
|
||||
VERIFY(spin_wait([&] { return running == kThreads; }));
|
||||
running = 0;
|
||||
phase = 2;
|
||||
for (int i = 0; i < kThreads / 4; ++i) {
|
||||
tp.Schedule([&]() {
|
||||
running++;
|
||||
while (phase < 3) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
done++;
|
||||
});
|
||||
}
|
||||
while (running != kThreads) {
|
||||
}
|
||||
VERIFY(spin_wait([&] { return running == kThreads; }));
|
||||
phase = 3;
|
||||
while (done != 3 * kThreads) {
|
||||
}
|
||||
VERIFY(spin_wait([&] { return done == 3 * kThreads; }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,12 +149,12 @@ static void test_pool_partitions() {
|
||||
VERIFY_LE(thread_id, kThreads - 1);
|
||||
++running;
|
||||
while (phase < 1) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
++done;
|
||||
});
|
||||
}
|
||||
while (running != kThreads) {
|
||||
}
|
||||
VERIFY(spin_wait([&] { return running == kThreads; }));
|
||||
// Schedule each closure to only run on thread 'i' and verify that it does.
|
||||
for (int i = 0; i < kThreads; ++i) {
|
||||
tp.ScheduleWithHint(
|
||||
@@ -150,6 +163,7 @@ static void test_pool_partitions() {
|
||||
const int thread_id = tp.CurrentThreadId();
|
||||
VERIFY_IS_EQUAL(thread_id, i);
|
||||
while (phase < 2) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
++done;
|
||||
},
|
||||
@@ -157,8 +171,7 @@ static void test_pool_partitions() {
|
||||
}
|
||||
running = 0;
|
||||
phase = 1;
|
||||
while (running != kThreads) {
|
||||
}
|
||||
VERIFY(spin_wait([&] { return running == kThreads; }));
|
||||
running = 0;
|
||||
phase = 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user