forked from OSchip/llvm-project
[libc] Add differential quality and perf analysis targets for sinf and cosf.
Infrastructure needed for setting up the diff binaries has been added. Along the way, an exhaustive test for sinf and cosf have also been added. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D101276
This commit is contained in:
parent
51b4610743
commit
c6aa206b42
|
@ -1134,3 +1134,4 @@ add_fp_unittest(
|
|||
|
||||
add_subdirectory(generic)
|
||||
add_subdirectory(exhaustive)
|
||||
add_subdirectory(differential_testing)
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
function(add_diff_binary target_name)
|
||||
cmake_parse_arguments(
|
||||
"DIFF"
|
||||
"" # No optional arguments
|
||||
"SUITE" # Single value arguments
|
||||
"SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi-value arguments
|
||||
${ARGN}
|
||||
)
|
||||
if(NOT DIFF_SRCS)
|
||||
message(FATAL_ERROR "'add_diff_binary' target requires a SRCS list of .cpp "
|
||||
"files.")
|
||||
endif()
|
||||
if(NOT DIFF_DEPENDS)
|
||||
message(FATAL_ERROR "'add_diff_binary' target requires a DEPENDS list of "
|
||||
"'add_entrypoint_object' targets.")
|
||||
endif()
|
||||
|
||||
get_fq_target_name(${target_name} fq_target_name)
|
||||
get_fq_deps_list(fq_deps_list ${DIFF_DEPENDS})
|
||||
get_object_files_for_test(
|
||||
link_object_files skipped_entrypoints_list ${fq_deps_list})
|
||||
if(skipped_entrypoints_list)
|
||||
set(msg "Will not build ${fq_target_name} as it has missing deps: "
|
||||
"${skipped_entrypoints_list}.")
|
||||
message(STATUS ${msg})
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(
|
||||
${fq_target_name}
|
||||
EXCLUDE_FROM_ALL
|
||||
${DIFF_SRCS}
|
||||
${DIFF_HDRS}
|
||||
)
|
||||
target_include_directories(
|
||||
${fq_target_name}
|
||||
PRIVATE
|
||||
${LIBC_SOURCE_DIR}
|
||||
${LIBC_BUILD_DIR}
|
||||
${LIBC_BUILD_DIR}/include
|
||||
)
|
||||
if(DIFF_COMPILE_OPTIONS)
|
||||
target_compile_options(
|
||||
${fq_target_name}
|
||||
PRIVATE ${DIFF_COMPILE_OPTIONS}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
${fq_target_name}
|
||||
PRIVATE ${link_object_files} libc_test_utils)
|
||||
|
||||
set_target_properties(${fq_target_name}
|
||||
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_dependencies(
|
||||
${fq_target_name}
|
||||
libc.utils.FPUtil.fputil
|
||||
${fq_deps_list}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
add_header_library(
|
||||
single_input_single_output_diff
|
||||
HDRS
|
||||
SingleInputSingleOutputDiff.h
|
||||
)
|
||||
|
||||
add_diff_binary(
|
||||
sinf_diff
|
||||
SRCS
|
||||
sinf_diff.cpp
|
||||
DEPENDS
|
||||
.single_input_single_output_diff
|
||||
libc.src.math.sinf
|
||||
)
|
||||
|
||||
add_diff_binary(
|
||||
sinf_perf
|
||||
SRCS
|
||||
sinf_perf.cpp
|
||||
DEPENDS
|
||||
.single_input_single_output_diff
|
||||
libc.src.math.sinf
|
||||
COMPILE_OPTIONS
|
||||
-fno-builtin
|
||||
)
|
||||
|
||||
add_diff_binary(
|
||||
cosf_diff
|
||||
SRCS
|
||||
cosf_diff.cpp
|
||||
DEPENDS
|
||||
.single_input_single_output_diff
|
||||
libc.src.math.cosf
|
||||
)
|
||||
|
||||
add_diff_binary(
|
||||
cosf_perf
|
||||
SRCS
|
||||
cosf_perf.cpp
|
||||
DEPENDS
|
||||
.single_input_single_output_diff
|
||||
libc.src.math.cosf
|
||||
COMPILE_OPTIONS
|
||||
-fno-builtin
|
||||
)
|
|
@ -0,0 +1,89 @@
|
|||
//===-- 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 "utils/FPUtil/FPBits.h"
|
||||
#include "utils/testutils/StreamWrapper.h"
|
||||
#include "utils/testutils/Timer.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
namespace testing {
|
||||
|
||||
template <typename T> class SingleInputSingleOutputDiff {
|
||||
using FPBits = fputil::FPBits<T>;
|
||||
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);
|
||||
|
||||
static void runDiff(Func myFunc, Func otherFunc, const char *logFile) {
|
||||
UIntType diffCount = 0;
|
||||
testutils::OutputFileStream log(logFile);
|
||||
log << "Starting diff for values from 0 to " << UIntMax << '\n'
|
||||
<< "Only differing results will be logged.\n\n";
|
||||
for (UIntType bits = 0;; ++bits) {
|
||||
T x = T(FPBits(bits));
|
||||
T myResult = myFunc(x);
|
||||
T otherResult = otherFunc(x);
|
||||
UIntType myBits = FPBits(myResult).uintval();
|
||||
UIntType otherBits = FPBits(otherResult).uintval();
|
||||
if (myBits != otherBits) {
|
||||
++diffCount;
|
||||
log << " Input: " << bits << " (" << x << ")\n"
|
||||
<< " My result: " << myBits << " (" << myResult << ")\n"
|
||||
<< "Other result: " << otherBits << " (" << otherResult << ")\n"
|
||||
<< '\n';
|
||||
}
|
||||
if (bits == UIntMax)
|
||||
break;
|
||||
}
|
||||
log << "Total number of differing results: " << diffCount << '\n';
|
||||
}
|
||||
|
||||
static void runPerf(Func myFunc, Func otherFunc, const char *logFile) {
|
||||
auto runner = [](Func func) {
|
||||
volatile T result;
|
||||
for (UIntType bits = 0;; ++bits) {
|
||||
T x = T(FPBits(bits));
|
||||
result = func(x);
|
||||
if (bits == UIntMax)
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
testutils::OutputFileStream log(logFile);
|
||||
Timer timer;
|
||||
timer.start();
|
||||
runner(myFunc);
|
||||
timer.stop();
|
||||
log << " Run time of my function: " << timer.nanoseconds() << " ns \n";
|
||||
|
||||
timer.start();
|
||||
runner(otherFunc);
|
||||
timer.stop();
|
||||
log << "Run time of other function: " << timer.nanoseconds() << " ns \n";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#define SINGLE_INPUT_SINGLE_OUTPUT_DIFF(T, myFunc, otherFunc, filename) \
|
||||
int main() { \
|
||||
__llvm_libc::testing::SingleInputSingleOutputDiff<T>::runDiff( \
|
||||
&myFunc, &otherFunc, filename); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define SINGLE_INPUT_SINGLE_OUTPUT_PERF(T, myFunc, otherFunc, filename) \
|
||||
int main() { \
|
||||
__llvm_libc::testing::SingleInputSingleOutputDiff<T>::runPerf( \
|
||||
&myFunc, &otherFunc, filename); \
|
||||
return 0; \
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
//===-- Differential test for cosf ----------------------------------------===//
|
||||
//
|
||||
// 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 "SingleInputSingleOutputDiff.h"
|
||||
|
||||
#include "src/math/cosf.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
SINGLE_INPUT_SINGLE_OUTPUT_DIFF(float, __llvm_libc::cosf, ::cosf,
|
||||
"cosf_diff.log")
|
|
@ -0,0 +1,16 @@
|
|||
//===-- Differential test for cosf ----------------------------------------===//
|
||||
//
|
||||
// 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 "SingleInputSingleOutputDiff.h"
|
||||
|
||||
#include "src/math/cosf.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
SINGLE_INPUT_SINGLE_OUTPUT_PERF(float, __llvm_libc::cosf, ::cosf,
|
||||
"cosf_perf.log")
|
|
@ -0,0 +1,16 @@
|
|||
//===-- Differential test for sinf ----------------------------------------===//
|
||||
//
|
||||
// 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 "SingleInputSingleOutputDiff.h"
|
||||
|
||||
#include "src/math/sinf.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
SINGLE_INPUT_SINGLE_OUTPUT_DIFF(float, __llvm_libc::sinf, ::sinf,
|
||||
"sinf_diff.log")
|
|
@ -0,0 +1,16 @@
|
|||
//===-- Differential test for sinf ----------------------------------------===//
|
||||
//
|
||||
// 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 "SingleInputSingleOutputDiff.h"
|
||||
|
||||
#include "src/math/sinf.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
SINGLE_INPUT_SINGLE_OUTPUT_PERF(float, __llvm_libc::sinf, ::sinf,
|
||||
"sinf_perf.log")
|
|
@ -12,3 +12,29 @@ add_fp_unittest(
|
|||
libc.src.math.sqrtf
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
sinf_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_exhaustive_tests
|
||||
SRCS
|
||||
sinf_test.cpp
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.sinf
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
cosf_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_exhaustive_tests
|
||||
SRCS
|
||||
cosf_test.cpp
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.cosf
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
//===-- Exhaustive test for cosf ------------------------------------------===//
|
||||
//
|
||||
// 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/math/cosf.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/FPUtil/TestHelpers.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
#include <math.h>
|
||||
|
||||
using FPBits = __llvm_libc::fputil::FPBits<float>;
|
||||
|
||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||
|
||||
TEST(LlvmLibccosffExhaustiveTest, AllValues) {
|
||||
uint32_t bits = 0;
|
||||
do {
|
||||
FPBits xbits(bits);
|
||||
float x = float(xbits);
|
||||
ASSERT_MPFR_MATCH(mpfr::Operation::Cos, x, __llvm_libc::cosf(x), 1.0);
|
||||
} while (bits++ < 0xffff'ffffU);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//===-- Exhaustive test for sinf ------------------------------------------===//
|
||||
//
|
||||
// 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/math/sinf.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/FPUtil/TestHelpers.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
#include <math.h>
|
||||
|
||||
using FPBits = __llvm_libc::fputil::FPBits<float>;
|
||||
|
||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||
|
||||
TEST(LlvmLibcsinffExhaustiveTest, AllValues) {
|
||||
uint32_t bits = 0;
|
||||
do {
|
||||
FPBits xbits(bits);
|
||||
float x = float(xbits);
|
||||
ASSERT_MPFR_MATCH(mpfr::Operation::Sin, x, __llvm_libc::sinf(x), 1.0);
|
||||
} while (bits++ < 0xffff'ffffU);
|
||||
}
|
|
@ -19,8 +19,8 @@ namespace mpfr = __llvm_libc::testing::mpfr;
|
|||
TEST(LlvmLibcSqrtfExhaustiveTest, AllValues) {
|
||||
uint32_t bits = 0;
|
||||
do {
|
||||
FPBits x(bits);
|
||||
ASSERT_MPFR_MATCH(mpfr::Operation::Sqrt, float(x), __llvm_libc::sqrtf(x),
|
||||
0.5);
|
||||
FPBits xbits(bits);
|
||||
float x = float(xbits);
|
||||
ASSERT_MPFR_MATCH(mpfr::Operation::Sqrt, x, __llvm_libc::sqrtf(x), 0.5);
|
||||
} while (bits++ < 0xffff'ffffU);
|
||||
}
|
||||
|
|
|
@ -13,4 +13,6 @@ add_llvm_library(
|
|||
ExecuteFunction.h
|
||||
${FDReaderFile}
|
||||
FDReader.h
|
||||
Timer.h
|
||||
Timer.cpp
|
||||
)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "StreamWrapper.h"
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -21,6 +22,7 @@ template <typename T> StreamWrapper &StreamWrapper::operator<<(T t) {
|
|||
assert(OS);
|
||||
std::ostream &Stream = *reinterpret_cast<std::ostream *>(OS);
|
||||
Stream << t;
|
||||
Stream.flush();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -43,6 +45,15 @@ template StreamWrapper &
|
|||
StreamWrapper::operator<<<unsigned long long>(unsigned long long t);
|
||||
template StreamWrapper &StreamWrapper::operator<<<bool>(bool t);
|
||||
template StreamWrapper &StreamWrapper::operator<<<std::string>(std::string t);
|
||||
template StreamWrapper &StreamWrapper::operator<<<float>(float t);
|
||||
template StreamWrapper &StreamWrapper::operator<<<double>(double t);
|
||||
|
||||
OutputFileStream::OutputFileStream(const char *FN)
|
||||
: StreamWrapper(new std::ofstream(FN)) {}
|
||||
|
||||
OutputFileStream::~OutputFileStream() {
|
||||
delete reinterpret_cast<std::ofstream *>(OS);
|
||||
}
|
||||
|
||||
} // namespace testutils
|
||||
} // namespace __llvm_libc
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace testutils {
|
|||
// standard headers so we must provide streams through indirection to not
|
||||
// expose the system libc headers.
|
||||
class StreamWrapper {
|
||||
protected:
|
||||
void *OS;
|
||||
|
||||
public:
|
||||
|
@ -26,6 +27,12 @@ public:
|
|||
|
||||
StreamWrapper outs();
|
||||
|
||||
class OutputFileStream : public StreamWrapper {
|
||||
public:
|
||||
explicit OutputFileStream(const char *FN);
|
||||
~OutputFileStream();
|
||||
};
|
||||
|
||||
} // namespace testutils
|
||||
} // namespace __llvm_libc
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
//===-- Timer.cpp --------------------------------------------------------===//
|
||||
//
|
||||
// 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 "Timer.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
namespace __llvm_libc {
|
||||
namespace testing {
|
||||
|
||||
struct TimerImplementation {
|
||||
std::chrono::high_resolution_clock::time_point Start;
|
||||
std::chrono::high_resolution_clock::time_point End;
|
||||
};
|
||||
|
||||
Timer::Timer() : Impl(new TimerImplementation) {}
|
||||
|
||||
Timer::~Timer() { delete reinterpret_cast<TimerImplementation *>(Impl); }
|
||||
|
||||
void Timer::start() {
|
||||
auto T = reinterpret_cast<TimerImplementation *>(Impl);
|
||||
T->Start = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void Timer::stop() {
|
||||
auto T = reinterpret_cast<TimerImplementation *>(Impl);
|
||||
T->End = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
uint64_t Timer::nanoseconds() const {
|
||||
auto T = reinterpret_cast<TimerImplementation *>(Impl);
|
||||
return std::chrono::nanoseconds(T->End - T->Start).count();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,33 @@
|
|||
//===-- Timer.h -------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_UTILS_TESTUTILS_TIMER_H
|
||||
#define LLVM_LIBC_UTILS_TESTUTILS_TIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace __llvm_libc {
|
||||
namespace testing {
|
||||
|
||||
class Timer {
|
||||
void *Impl;
|
||||
|
||||
public:
|
||||
Timer();
|
||||
~Timer();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
uint64_t nanoseconds() const;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_UTILS_TESTUTILS_TIMER_H
|
Loading…
Reference in New Issue