diff --git a/libc/test/src/math/differential_testing/BinaryOpSingleOutputDiff.h b/libc/test/src/math/differential_testing/BinaryOpSingleOutputDiff.h new file mode 100644 --- /dev/null +++ b/libc/test/src/math/differential_testing/BinaryOpSingleOutputDiff.h @@ -0,0 +1,99 @@ +//===-- Common utility class for differential analysis --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/FPUtil/FPBits.h" +#include "utils/testutils/StreamWrapper.h" +#include "utils/testutils/Timer.h" + +namespace __llvm_libc { +namespace testing { + +template class BinaryOpSingleOutputDiff { + using FPBits = fputil::FPBits; + using UIntType = typename FPBits::UIntType; + static constexpr UIntType MSBIT = UIntType(1) << (8 * sizeof(UIntType) - 1); + static constexpr UIntType UINTMAX = (MSBIT - 1) + MSBIT; + +public: + typedef T Func(T, T); + + static void run_perf_in_range(Func myFunc, Func otherFunc, + UIntType startingBit, UIntType endingBit, + UIntType N, testutils::OutputFileStream &log) { + auto runner = [=](Func func) { + volatile T result; + if (endingBit < startingBit) { + return; + } + + UIntType step = (endingBit - startingBit) / N; + for (UIntType bitsX = startingBit, bitsY = endingBit;; + bitsX += step, bitsY -= step) { + T x = T(FPBits(bitsX)); + T y = T(FPBits(bitsY)); + result = func(x, y); + if (endingBit - bitsX < step) { + break; + } + } + }; + + Timer timer; + timer.start(); + runner(myFunc); + timer.stop(); + + double my_average = static_cast(timer.nanoseconds()) / N; + log << "-- My function --\n"; + log << " Total time : " << timer.nanoseconds() << " ns \n"; + log << " Average runtime : " << my_average << " ns/op \n"; + log << " Ops per second : " + << static_cast(1'000'000'000.0 / my_average) << " op/s \n"; + + timer.start(); + runner(otherFunc); + timer.stop(); + + double other_average = static_cast(timer.nanoseconds()) / N; + log << "-- Other function --\n"; + log << " Total time : " << timer.nanoseconds() << " ns \n"; + log << " Average runtime : " << other_average << " ns/op \n"; + log << " Ops per second : " + << static_cast(1'000'000'000.0 / other_average) << " op/s \n"; + + log << "-- Average runtime ratio --\n"; + log << " Mine / Other's : " << my_average / other_average << " \n"; + } + + static void run_perf(Func myFunc, Func otherFunc, const char *logFile) { + testutils::OutputFileStream log(logFile); + log << " Performance tests with inputs in denormal range:\n"; + run_perf_in_range(myFunc, otherFunc, /* startingBit= */ UIntType(0), + /* endingBit= */ FPBits::MAX_SUBNORMAL, 1'000'001, log); + log << "\n Performance tests with inputs in normal range:\n"; + run_perf_in_range(myFunc, otherFunc, /* startingBit= */ FPBits::MIN_NORMAL, + /* endingBit= */ FPBits::MAX_NORMAL, 100'000'001, log); + } +}; + +} // namespace testing +} // namespace __llvm_libc + +#define BINARY_OP_SINGLE_OUTPUT_DIFF(T, myFunc, otherFunc, filename) \ + int main() { \ + __llvm_libc::testing::BinaryOpSingleOutputDiff::run_diff( \ + &myFunc, &otherFunc, filename); \ + return 0; \ + } + +#define BINARY_OP_SINGLE_OUTPUT_PERF(T, myFunc, otherFunc, filename) \ + int main() { \ + __llvm_libc::testing::BinaryOpSingleOutputDiff::run_perf( \ + &myFunc, &otherFunc, filename); \ + return 0; \ + } diff --git a/libc/test/src/math/differential_testing/CMakeLists.txt b/libc/test/src/math/differential_testing/CMakeLists.txt --- a/libc/test/src/math/differential_testing/CMakeLists.txt +++ b/libc/test/src/math/differential_testing/CMakeLists.txt @@ -67,6 +67,12 @@ SingleInputSingleOutputDiff.h ) +add_header_library( + binary_op_single_output_diff + HDRS + BinaryOpSingleOutputDiff.h +) + add_diff_binary( sinf_diff SRCS @@ -368,3 +374,25 @@ COMPILE_OPTIONS -fno-builtin ) + +add_diff_binary( + hypotf_perf + SRCS + hypotf_perf.cpp + DEPENDS + .binary_op_single_output_diff + libc.src.math.hypotf + COMPILE_OPTIONS + -fno-builtin +) + +add_diff_binary( + hypot_perf + SRCS + hypot_perf.cpp + DEPENDS + .binary_op_single_output_diff + libc.src.math.hypot + COMPILE_OPTIONS + -fno-builtin +) diff --git a/libc/test/src/math/differential_testing/hypot_perf.cpp b/libc/test/src/math/differential_testing/hypot_perf.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/differential_testing/hypot_perf.cpp @@ -0,0 +1,16 @@ +//===-- Differential test for hypot ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "BinaryOpSingleOutputDiff.h" + +#include "src/math/hypot.h" + +#include + +BINARY_OP_SINGLE_OUTPUT_PERF(double, __llvm_libc::hypot, ::hypot, + "hypot_perf.log") diff --git a/libc/test/src/math/differential_testing/hypotf_perf.cpp b/libc/test/src/math/differential_testing/hypotf_perf.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/differential_testing/hypotf_perf.cpp @@ -0,0 +1,16 @@ +//===-- Differential test for hypotf --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "BinaryOpSingleOutputDiff.h" + +#include "src/math/hypotf.h" + +#include + +BINARY_OP_SINGLE_OUTPUT_PERF(float, __llvm_libc::hypotf, ::hypotf, + "hypotf_perf.log")