[libc-commits] [libc] c6aa206 - [libc] Add differential quality and perf analysis targets for sinf and cosf.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Mon Apr 26 12:39:45 PDT 2021


Author: Siva Chandra Reddy
Date: 2021-04-26T19:39:33Z
New Revision: c6aa206b429dccadc5c0471b22544337da1fc943

URL: https://github.com/llvm/llvm-project/commit/c6aa206b429dccadc5c0471b22544337da1fc943
DIFF: https://github.com/llvm/llvm-project/commit/c6aa206b429dccadc5c0471b22544337da1fc943.diff

LOG: [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

Added: 
    libc/test/src/math/differential_testing/CMakeLists.txt
    libc/test/src/math/differential_testing/SingleInputSingleOutputDiff.h
    libc/test/src/math/differential_testing/cosf_diff.cpp
    libc/test/src/math/differential_testing/cosf_perf.cpp
    libc/test/src/math/differential_testing/sinf_diff.cpp
    libc/test/src/math/differential_testing/sinf_perf.cpp
    libc/test/src/math/exhaustive/cosf_test.cpp
    libc/test/src/math/exhaustive/sinf_test.cpp
    libc/utils/testutils/Timer.cpp
    libc/utils/testutils/Timer.h

Modified: 
    libc/test/src/math/CMakeLists.txt
    libc/test/src/math/exhaustive/CMakeLists.txt
    libc/test/src/math/exhaustive/sqrtf_test.cpp
    libc/utils/testutils/CMakeLists.txt
    libc/utils/testutils/StreamWrapper.cpp
    libc/utils/testutils/StreamWrapper.h

Removed: 
    


################################################################################
diff  --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 208963334ca96..be7518f53a5a8 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1134,3 +1134,4 @@ add_fp_unittest(
 
 add_subdirectory(generic)
 add_subdirectory(exhaustive)
+add_subdirectory(
diff erential_testing)

diff  --git a/libc/test/src/math/
diff erential_testing/CMakeLists.txt b/libc/test/src/math/
diff erential_testing/CMakeLists.txt
new file mode 100644
index 0000000000000..94a0aa6a73903
--- /dev/null
+++ b/libc/test/src/math/
diff erential_testing/CMakeLists.txt
@@ -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
+)

diff  --git a/libc/test/src/math/
diff erential_testing/SingleInputSingleOutputDiff.h b/libc/test/src/math/
diff erential_testing/SingleInputSingleOutputDiff.h
new file mode 100644
index 0000000000000..9e39740d30389
--- /dev/null
+++ b/libc/test/src/math/
diff erential_testing/SingleInputSingleOutputDiff.h
@@ -0,0 +1,89 @@
+//===-- Common utility class for 
diff erential 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 
diff Count = 0;
+    testutils::OutputFileStream log(logFile);
+    log << "Starting 
diff  for values from 0 to " << UIntMax << '\n'
+        << "Only 
diff ering 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) {
+        ++
diff Count;
+        log << "       Input: " << bits << " (" << x << ")\n"
+            << "   My result: " << myBits << " (" << myResult << ")\n"
+            << "Other result: " << otherBits << " (" << otherResult << ")\n"
+            << '\n';
+      }
+      if (bits == UIntMax)
+        break;
+    }
+    log << "Total number of 
diff ering results: " << 
diff Count << '\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;                                                                  \
+  }

diff  --git a/libc/test/src/math/
diff erential_testing/cosf_
diff .cpp b/libc/test/src/math/
diff erential_testing/cosf_
diff .cpp
new file mode 100644
index 0000000000000..232a3ceb11418
--- /dev/null
+++ b/libc/test/src/math/
diff erential_testing/cosf_
diff .cpp
@@ -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")

diff  --git a/libc/test/src/math/
diff erential_testing/cosf_perf.cpp b/libc/test/src/math/
diff erential_testing/cosf_perf.cpp
new file mode 100644
index 0000000000000..3107d19943103
--- /dev/null
+++ b/libc/test/src/math/
diff erential_testing/cosf_perf.cpp
@@ -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")

diff  --git a/libc/test/src/math/
diff erential_testing/sinf_
diff .cpp b/libc/test/src/math/
diff erential_testing/sinf_
diff .cpp
new file mode 100644
index 0000000000000..d69db9b1a136b
--- /dev/null
+++ b/libc/test/src/math/
diff erential_testing/sinf_
diff .cpp
@@ -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")

diff  --git a/libc/test/src/math/
diff erential_testing/sinf_perf.cpp b/libc/test/src/math/
diff erential_testing/sinf_perf.cpp
new file mode 100644
index 0000000000000..b32821a948323
--- /dev/null
+++ b/libc/test/src/math/
diff erential_testing/sinf_perf.cpp
@@ -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")

diff  --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index 4e65056581903..e7b5b308f53f1 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -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
+)

diff  --git a/libc/test/src/math/exhaustive/cosf_test.cpp b/libc/test/src/math/exhaustive/cosf_test.cpp
new file mode 100644
index 0000000000000..2d1b9b25de08d
--- /dev/null
+++ b/libc/test/src/math/exhaustive/cosf_test.cpp
@@ -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);
+}

diff  --git a/libc/test/src/math/exhaustive/sinf_test.cpp b/libc/test/src/math/exhaustive/sinf_test.cpp
new file mode 100644
index 0000000000000..a31e957a991cd
--- /dev/null
+++ b/libc/test/src/math/exhaustive/sinf_test.cpp
@@ -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);
+}

diff  --git a/libc/test/src/math/exhaustive/sqrtf_test.cpp b/libc/test/src/math/exhaustive/sqrtf_test.cpp
index 4e2b566625ef5..caa4bdd94d188 100644
--- a/libc/test/src/math/exhaustive/sqrtf_test.cpp
+++ b/libc/test/src/math/exhaustive/sqrtf_test.cpp
@@ -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);
 }

diff  --git a/libc/utils/testutils/CMakeLists.txt b/libc/utils/testutils/CMakeLists.txt
index c39a8399895db..248858c311d1c 100644
--- a/libc/utils/testutils/CMakeLists.txt
+++ b/libc/utils/testutils/CMakeLists.txt
@@ -13,4 +13,6 @@ add_llvm_library(
   ExecuteFunction.h
   ${FDReaderFile}
   FDReader.h
+  Timer.h
+  Timer.cpp
 )

diff  --git a/libc/utils/testutils/StreamWrapper.cpp b/libc/utils/testutils/StreamWrapper.cpp
index 9071ebca245cc..84ab583f66445 100644
--- a/libc/utils/testutils/StreamWrapper.cpp
+++ b/libc/utils/testutils/StreamWrapper.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

diff  --git a/libc/utils/testutils/StreamWrapper.h b/libc/utils/testutils/StreamWrapper.h
index a692bb639a398..2434ab06bb71f 100644
--- a/libc/utils/testutils/StreamWrapper.h
+++ b/libc/utils/testutils/StreamWrapper.h
@@ -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 @@ class StreamWrapper {
 
 StreamWrapper outs();
 
+class OutputFileStream : public StreamWrapper {
+public:
+  explicit OutputFileStream(const char *FN);
+  ~OutputFileStream();
+};
+
 } // namespace testutils
 } // namespace __llvm_libc
 

diff  --git a/libc/utils/testutils/Timer.cpp b/libc/utils/testutils/Timer.cpp
new file mode 100644
index 0000000000000..6780389d5322d
--- /dev/null
+++ b/libc/utils/testutils/Timer.cpp
@@ -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

diff  --git a/libc/utils/testutils/Timer.h b/libc/utils/testutils/Timer.h
new file mode 100644
index 0000000000000..9df13a0d40746
--- /dev/null
+++ b/libc/utils/testutils/Timer.h
@@ -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


        


More information about the libc-commits mailing list