[libc][math] Improved ExhaustiveTest performance.

Previous implementation splits value ranges around threads. Because of
very different performance of testing functions over different ranges,
CPU utilization were poor. Current implementation split test range
over small pieces and threads take the pieces when they finish with
previous. Therefore the CPU load is constant during testing.

Differential Revision: https://reviews.llvm.org/D128995
This commit is contained in:
Kirill Okhotnikov 2022-07-01 16:37:27 +02:00
parent f80a4321ef
commit fdf1fda5a8
10 changed files with 117 additions and 118 deletions

View File

@ -6,67 +6,88 @@
//
//===----------------------------------------------------------------------===//
#include <atomic>
#include <fenv.h>
#include <functional>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
#include "exhaustive_test.h"
#include "src/__support/FPUtil/FPBits.h"
#include "utils/UnitTest/Test.h"
template <typename T>
void LlvmLibcExhaustiveTest<T>::test_full_range(T start, T stop, int nthreads,
mpfr::RoundingMode rounding) {
std::vector<std::thread> thread_list(nthreads);
T increment = (stop - start - 1) / nthreads + 1;
T begin = start;
T end = start + increment - 1;
for (int i = 0; i < nthreads; ++i) {
thread_list.emplace_back([this, begin, end, rounding]() {
std::stringstream msg;
msg << "-- Testing from " << begin << " to " << end << " [0x" << std::hex
<< begin << ", 0x" << end << "), [" << std::hexfloat
<< float(__llvm_libc::fputil::FPBits<float>(
static_cast<uint32_t>(begin)))
<< ", "
<< float(
__llvm_libc::fputil::FPBits<float>(static_cast<uint32_t>(end)))
<< ") ..." << std::endl;
std::cout << msg.str();
msg.str("");
#include "exhaustive_test.h"
bool result = check(begin, end, rounding);
template <typename T, typename FloatType>
void LlvmLibcExhaustiveTest<T, FloatType>::test_full_range(
T start, T stop, mpfr::RoundingMode rounding) {
int n_threads = std::thread::hardware_concurrency();
std::vector<std::thread> thread_list;
std::mutex mx_cur_val;
int current_percent = -1;
T current_value = start;
std::atomic<uint64_t> failed(0);
for (int i = 0; i < n_threads; ++i) {
thread_list.emplace_back([&, this]() {
while (true) {
T range_begin, range_end;
int new_percent = -1;
{
std::lock_guard<std::mutex> lock(mx_cur_val);
if (current_value == stop)
return;
msg << "** Finished testing from " << std::dec << begin << " to " << end
<< " [0x" << std::hex << begin << ", 0x" << end << "), ["
<< std::hexfloat
<< float(__llvm_libc::fputil::FPBits<float>(
static_cast<uint32_t>(begin)))
<< ", "
<< float(
__llvm_libc::fputil::FPBits<float>(static_cast<uint32_t>(end)))
<< ") : " << (result ? "PASSED" : "FAILED") << std::endl;
std::cout << msg.str();
range_begin = current_value;
if (stop >= increment && stop - increment >= current_value) {
range_end = current_value + increment;
} else
range_end = stop;
current_value = range_end;
int pc = 100.0 * double(range_end - start) / double(stop - start);
if (current_percent != pc) {
new_percent = pc;
current_percent = pc;
}
}
if (new_percent >= 0) {
std::stringstream msg;
msg << new_percent << "% is in process \r";
std::cout << msg.str() << std::flush;
;
}
bool check_passed = check(range_begin, range_end, rounding);
if (!check_passed) {
std::stringstream msg;
msg << "Test failed in range: " << std::dec << range_begin << " to "
<< range_end << " [0x" << std::hex << range_begin << ", 0x"
<< range_end << "), [" << std::hexfloat
<< static_cast<FloatType>(__llvm_libc::fputil::FPBits<FloatType>(
static_cast<T>(range_begin)))
<< ", "
<< static_cast<FloatType>(
__llvm_libc::fputil::FPBits<FloatType>(range_end))
<< ") " << std::endl;
std::cerr << msg.str() << std::flush;
failed.fetch_add(1);
}
}
});
begin += increment;
end += increment;
if (end > stop)
end = stop;
}
for (auto &thread : thread_list) {
if (thread.joinable()) {
thread.join();
}
}
std::cout << std::endl;
std::cout << "Test " << ((failed > 0) ? "FAILED" : "PASSED") << std::endl;
}
template void
LlvmLibcExhaustiveTest<uint32_t>::test_full_range(uint32_t, uint32_t, int,
mpfr::RoundingMode);
template void
LlvmLibcExhaustiveTest<uint64_t>::test_full_range(uint64_t, uint64_t, int,
mpfr::RoundingMode);
LlvmLibcExhaustiveTest<uint32_t>::test_full_range(uint32_t, uint32_t,
mpfr::RoundingMode);
template void LlvmLibcExhaustiveTest<uint64_t, double>::test_full_range(
uint64_t, uint64_t, mpfr::RoundingMode);

View File

@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
#include "src/__support/CPP/TypeTraits.h"
#include "src/__support/FPUtil/FPBits.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include "utils/UnitTest/Test.h"
@ -15,12 +17,16 @@
// 4. Call: test_full_range(start, stop, nthreads, rounding)
namespace mpfr = __llvm_libc::testing::mpfr;
template <typename T>
template <typename T, typename FloatType = float>
struct LlvmLibcExhaustiveTest : public __llvm_libc::testing::Test {
static constexpr T increment = (1 << 20);
static_assert(
__llvm_libc::cpp::IsSameV<
T, typename __llvm_libc::fputil::FPBits<FloatType>::UIntType>,
"Types are not consistent");
// Break [start, stop) into `nthreads` subintervals and apply *check to each
// subinterval in parallel.
void test_full_range(T start, T stop, int nthreads,
mpfr::RoundingMode rounding);
void test_full_range(T start, T stop, mpfr::RoundingMode rounding);
virtual bool check(T start, T stop, mpfr::RoundingMode rounding) = 0;
};

View File

@ -32,29 +32,24 @@ struct LlvmLibcExp2fExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
}
};
static constexpr int NUM_THREADS = 16;
// Range: [0, 128];
static constexpr uint32_t POS_START = 0x0000'0000U;
static constexpr uint32_t POS_STOP = 0x4300'0000U;
TEST_F(LlvmLibcExp2fExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::Nearest);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcExp2fExhaustiveTest, PostiveRangeRoundUp) {
test_full_range(POS_START, POS_STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcExp2fExhaustiveTest, PostiveRangeRoundDown) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::Downward);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcExp2fExhaustiveTest, PostiveRangeRoundTowardZero) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::TowardZero);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
}
// Range: [-150, 0];
@ -62,20 +57,17 @@ static constexpr uint32_t NEG_START = 0x8000'0000U;
static constexpr uint32_t NEG_STOP = 0xc316'0000U;
TEST_F(LlvmLibcExp2fExhaustiveTest, NegativeRangeRoundNearestTieToEven) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::Nearest);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcExp2fExhaustiveTest, NegativeRangeRoundUp) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcExp2fExhaustiveTest, NegativeRangeRoundDown) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::Downward);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcExp2fExhaustiveTest, NegativeRangeRoundTowardZero) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::TowardZero);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::TowardZero);
}

View File

@ -34,29 +34,24 @@ struct LlvmLibcExpfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
}
};
static const int NUM_THREADS = std::thread::hardware_concurrency();
// Range: [0, 89];
static constexpr uint32_t POS_START = 0x0000'0000U;
static constexpr uint32_t POS_STOP = 0x42b2'0000U;
TEST_F(LlvmLibcExpfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::Nearest);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcExpfExhaustiveTest, PostiveRangeRoundUp) {
test_full_range(POS_START, POS_STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcExpfExhaustiveTest, PostiveRangeRoundDown) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::Downward);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcExpfExhaustiveTest, PostiveRangeRoundTowardZero) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::TowardZero);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
}
// Range: [-104, 0];
@ -64,20 +59,17 @@ static constexpr uint32_t NEG_START = 0x8000'0000U;
static constexpr uint32_t NEG_STOP = 0xc2d0'0000U;
TEST_F(LlvmLibcExpfExhaustiveTest, NegativeRangeRoundNearestTieToEven) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::Nearest);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcExpfExhaustiveTest, NegativeRangeRoundUp) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcExpfExhaustiveTest, NegativeRangeRoundDown) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::Downward);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcExpfExhaustiveTest, NegativeRangeRoundTowardZero) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::TowardZero);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::TowardZero);
}

View File

@ -34,29 +34,24 @@ struct LlvmLibcExpm1fExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
}
};
static const int NUM_THREADS = std::thread::hardware_concurrency();
// Range: [0, 89];
static constexpr uint32_t POS_START = 0x0000'0000U;
static constexpr uint32_t POS_STOP = 0x42b2'0000U;
TEST_F(LlvmLibcExpm1fExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::Nearest);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcExpm1fExhaustiveTest, PostiveRangeRoundUp) {
test_full_range(POS_START, POS_STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcExpm1fExhaustiveTest, PostiveRangeRoundDown) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::Downward);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcExpm1fExhaustiveTest, PostiveRangeRoundTowardZero) {
test_full_range(POS_START, POS_STOP, NUM_THREADS,
mpfr::RoundingMode::TowardZero);
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
}
// Range: [-104, 0];
@ -64,20 +59,17 @@ static constexpr uint32_t NEG_START = 0x8000'0000U;
static constexpr uint32_t NEG_STOP = 0xc2d0'0000U;
TEST_F(LlvmLibcExpm1fExhaustiveTest, NegativeRangeRoundNearestTieToEven) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::Nearest);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcExpm1fExhaustiveTest, NegativeRangeRoundUp) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcExpm1fExhaustiveTest, NegativeRangeRoundDown) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::Downward);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcExpm1fExhaustiveTest, NegativeRangeRoundTowardZero) {
test_full_range(NEG_START, NEG_STOP, NUM_THREADS,
mpfr::RoundingMode::TowardZero);
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::TowardZero);
}

View File

@ -48,20 +48,19 @@ struct LlvmLibcHypotfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
// Range of the first input: [2^23, 2^24);
static constexpr uint32_t START = (23U + 127U) << 23;
static constexpr uint32_t STOP = ((23U + 127U) << 23) + 1;
static constexpr int NUM_THREADS = 1;
TEST_F(LlvmLibcHypotfExhaustiveTest, RoundNearestTieToEven) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Nearest);
test_full_range(START, STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcHypotfExhaustiveTest, RoundUp) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(START, STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcHypotfExhaustiveTest, RoundDown) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Downward);
test_full_range(START, STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcHypotfExhaustiveTest, RoundTowardZero) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::TowardZero);
test_full_range(START, STOP, mpfr::RoundingMode::TowardZero);
}

View File

@ -38,20 +38,18 @@ static constexpr uint32_t STOP = 0x7f80'0000U;
// Range: [1, 10];
// static constexpr uint32_t START = 0x3f80'0000U;
// static constexpr uint32_t STOP = 0x41c0'0000U;
static constexpr int NUM_THREADS = 16;
TEST_F(LlvmLibcLog10fExhaustiveTest, RoundNearestTieToEven) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Nearest);
test_full_range(START, STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcLog10fExhaustiveTest, RoundUp) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(START, STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcLog10fExhaustiveTest, RoundDown) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Downward);
test_full_range(START, STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcLog10fExhaustiveTest, RoundTowardZero) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::TowardZero);
test_full_range(START, STOP, mpfr::RoundingMode::TowardZero);
}

View File

@ -38,20 +38,19 @@ static constexpr uint32_t STOP = 0x7f80'0000U;
// Range: [-1, 0];
// static constexpr uint32_t START = 0x8000'0000U;
// static constexpr uint32_t STOP = 0xbf80'0000U;
static constexpr int NUM_THREADS = 16;
TEST_F(LlvmLibclog1pfExhaustiveTest, RoundNearestTieToEven) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Nearest);
test_full_range(START, STOP, mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibclog1pfExhaustiveTest, RoundUp) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Upward);
test_full_range(START, STOP, mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibclog1pfExhaustiveTest, RoundDown) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::Downward);
test_full_range(START, STOP, mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibclog1pfExhaustiveTest, RoundTowardZero) {
test_full_range(START, STOP, NUM_THREADS, mpfr::RoundingMode::TowardZero);
test_full_range(START, STOP, mpfr::RoundingMode::TowardZero);
}

View File

@ -33,21 +33,21 @@ struct LlvmLibcLog2fExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
};
TEST_F(LlvmLibcLog2fExhaustiveTest, RoundNearestTieToEven) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcLog2fExhaustiveTest, RoundUp) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcLog2fExhaustiveTest, RoundDown) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcLog2fExhaustiveTest, RoundTowardZero) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::TowardZero);
}

View File

@ -33,21 +33,21 @@ struct LlvmLibcLogfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
};
TEST_F(LlvmLibcLogfExhaustiveTest, RoundNearestTieToEven) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::Nearest);
}
TEST_F(LlvmLibcLogfExhaustiveTest, RoundUp) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::Upward);
}
TEST_F(LlvmLibcLogfExhaustiveTest, RoundDown) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::Downward);
}
TEST_F(LlvmLibcLogfExhaustiveTest, RoundTowardZero) {
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U, /*nthreads=*/16,
test_full_range(/*start=*/0U, /*stop=*/0x7f80'0000U,
mpfr::RoundingMode::TowardZero);
}