[libc-commits] [libc] [libc][math][c23] add performance tests for fmul (PR #106262)

Job Henandez Lara via libc-commits libc-commits at lists.llvm.org
Tue Aug 27 11:14:33 PDT 2024


https://github.com/Jobhdez created https://github.com/llvm/llvm-project/pull/106262

None

>From 05ef61e92a112357246ee94df5739780e29e9a75 Mon Sep 17 00:00:00 2001
From: Job Hernandez <hj93 at protonmail.com>
Date: Tue, 27 Aug 2024 11:13:11 -0700
Subject: [PATCH 1/2] add performance tests for fmul

---
 .../BinaryOpSingleOutputPerf.h                | 115 ++++++++++++++++++
 .../math/performance_testing/CMakeLists.txt   |  12 ++
 .../math/performance_testing/fmul_perf.cpp    |  34 ++++++
 3 files changed, 161 insertions(+)
 create mode 100644 libc/test/src/math/performance_testing/fmul_perf.cpp

diff --git a/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h b/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
index 63d9768e21899b..7e804c5b3c576b 100644
--- a/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
+++ b/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
@@ -122,6 +122,112 @@ template <typename T> class BinaryOpSingleOutputPerf {
   }
 };
 
+template <typename T, typename R>
+class BinaryOpSingleDifferentTypeOutputPerf {
+  using FPBits = fputil::FPBits<T>;
+  using StorageType = typename FPBits::StorageType;
+  static constexpr StorageType UIntMax = cpp::numeric_limits<StorageType>::max();
+
+public:
+  typedef T Func(R, R);
+
+  static void run_perf_in_range(Func myFunc, Func otherFunc,
+                                StorageType startingBit, StorageType endingBit,
+                                size_t N, size_t rounds, std::ofstream &log) {
+    if (sizeof(StorageType) <= sizeof(size_t))
+      N = cpp::min(N, static_cast<size_t>(endingBit - startingBit));
+
+    auto runner = [=](Func func) {
+      [[maybe_unused]] volatile T result;
+      if (endingBit < startingBit) {
+        return;
+      }
+
+      StorageType step = (endingBit - startingBit) / N;
+      for (size_t i = 0; i < rounds; i++) {
+        for (StorageType bitsX = startingBit, bitsY = endingBit;;
+             bitsX += step, bitsY -= step) {
+          R x = FPBits(bitsX).get_val();
+          R y = FPBits(bitsY).get_val();
+          result = func(x, y);
+          if (endingBit - bitsX < step) {
+            break;
+          }
+        }
+      }
+    };
+
+    Timer timer;
+    timer.start();
+    runner(myFunc);
+    timer.stop();
+
+    double my_average = static_cast<double>(timer.nanoseconds()) / N / rounds;
+    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<uint64_t>(1'000'000'000.0 / my_average) << " op/s \n";
+
+    timer.start();
+    runner(otherFunc);
+    timer.stop();
+
+    double other_average =
+        static_cast<double>(timer.nanoseconds()) / N / rounds;
+    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<uint64_t>(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, int rounds,
+                       const char *logFile) {
+    std::ofstream log(logFile);
+    log << " Performance tests with inputs in denormal range:\n";
+    run_perf_in_range(myFunc, otherFunc, /* startingBit= */ StorageType(0),
+                      /* endingBit= */ FPBits::max_subnormal().uintval(),
+                      1'000'001, rounds, log);
+    log << "\n Performance tests with inputs in normal range:\n";
+    run_perf_in_range(myFunc, otherFunc,
+                      /* startingBit= */ FPBits::min_normal().uintval(),
+                      /* endingBit= */ FPBits::max_normal().uintval(),
+                      1'000'001, rounds, log);
+    log << "\n Performance tests with inputs in normal range with exponents "
+           "close to each other:\n";
+    run_perf_in_range(myFunc, otherFunc,
+                      /* startingBit= */ FPBits(T(0x1.0p-10)).uintval(),
+                      /* endingBit= */ FPBits(T(0x1.0p+10)).uintval(),
+                      1'000'001, rounds, log);
+  }
+
+  static void run_diff(Func myFunc, Func otherFunc, const char *logFile) {
+    uint64_t diffCount = 0;
+    std::ofstream log(logFile);
+    log << " Diff tests with inputs in denormal range:\n";
+    diffCount += run_diff_in_range(
+        myFunc, otherFunc, /* startingBit= */ StorageType(0),
+        /* endingBit= */ FPBits::max_subnormal().uintval(), 1'000'001, log);
+    log << "\n Diff tests with inputs in normal range:\n";
+    diffCount += run_diff_in_range(
+        myFunc, otherFunc,
+        /* startingBit= */ FPBits::min_normal().uintval(),
+        /* endingBit= */ FPBits::max_normal().uintval(), 100'000'001, log);
+    log << "\n Diff tests with inputs in normal range with exponents "
+           "close to each other:\n";
+    diffCount += run_diff_in_range(
+        myFunc, otherFunc, /* startingBit= */ FPBits(T(0x1.0p-10)).uintval(),
+        /* endingBit= */ FPBits(T(0x1.0p+10)).uintval(), 10'000'001, log);
+
+    log << "Total number of differing results: " << diffCount << '\n';
+  }
+};
+
+
 } // namespace testing
 } // namespace LIBC_NAMESPACE_DECL
 
@@ -140,3 +246,12 @@ template <typename T> class BinaryOpSingleOutputPerf {
     LIBC_NAMESPACE::testing::BinaryOpSingleOutputPerf<T>::run_perf(            \
         &myFunc, &otherFunc, rounds, filename);                                \
   }
+
+#define BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(T, R, myFunc, otherFunc, rounds, filename) \
+                                                                                             \
+  {									                     \
+    LIBC_NAMESPACE::testing::BinaryOpSingleDifferentTypeOutputPerf<T,R>::run_perf(           \
+        &myFunc, &otherFunc, rounds, filename);                                              \
+     LIBC_NAMESPACE::testing::BinaryOpSingleDifferentTypeOutputPerf<T,R>::run_perf(          \
+        &myFunc, &otherFunc, rounds, filename);                                              \
+   }
diff --git a/libc/test/src/math/performance_testing/CMakeLists.txt b/libc/test/src/math/performance_testing/CMakeLists.txt
index 8e529ca09ed797..207a463fe185f8 100644
--- a/libc/test/src/math/performance_testing/CMakeLists.txt
+++ b/libc/test/src/math/performance_testing/CMakeLists.txt
@@ -476,3 +476,15 @@ add_perf_binary(
   COMPILE_OPTIONS
     -fno-builtin
 )
+
+add_perf_binary(
+  fmul_perf
+  SRCS
+    fmul_perf.cpp
+  DEPENDS
+    .binary_op_single_output_diff
+    libc.src.math.fmul
+    libc.src.math.fmull
+  COMPILE_OPTIONS
+    -fno-builtin
+)
diff --git a/libc/test/src/math/performance_testing/fmul_perf.cpp b/libc/test/src/math/performance_testing/fmul_perf.cpp
new file mode 100644
index 00000000000000..1d242fd3d19647
--- /dev/null
+++ b/libc/test/src/math/performance_testing/fmul_perf.cpp
@@ -0,0 +1,34 @@
+//===-- Performance test for maximum and minimum functions ----------------===//
+//
+// 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 "BinaryOpSingleOutputPerf.h"
+#include "src/math/fmul.h"
+#include "src/math/fmull.h"
+#include <math.h>
+
+static constexpr size_t DOUBLE_ROUNDS = 40;
+static constexpr size_t LONG_DOUBLE_ROUNDS = 40;
+
+float fmul_placeholder_binary(double x, double y) {
+  return static_cast<float>(x*y);
+}
+
+float fmull_placeholder_binary(long double x, long double y) {
+  return static_cast<float>(x*y);
+}
+
+int main() {
+  BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(float, double, LIBC_NAMESPACE::fmul,
+				  fmul_placeholder_binary, DOUBLE_ROUNDS,
+				  "fmul_perf.log")
+  BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(float, long double, LIBC_NAMESPACE::fmull,
+				  fmull_placeholder_binary, LONG_DOUBLE_ROUNDS,
+				  "fmull_perf.log")
+  return 0;
+}
+    

>From b7614b3d6129770d0a79d25931b171679d4772eb Mon Sep 17 00:00:00 2001
From: Job Hernandez <hj93 at protonmail.com>
Date: Tue, 27 Aug 2024 11:13:28 -0700
Subject: [PATCH 2/2] format code

---
 .../BinaryOpSingleOutputPerf.h                | 24 +++++++++----------
 .../math/performance_testing/fmul_perf.cpp    | 17 +++++++------
 2 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h b/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
index 7e804c5b3c576b..5941aa71689a59 100644
--- a/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
+++ b/libc/test/src/math/performance_testing/BinaryOpSingleOutputPerf.h
@@ -122,11 +122,11 @@ template <typename T> class BinaryOpSingleOutputPerf {
   }
 };
 
-template <typename T, typename R>
-class BinaryOpSingleDifferentTypeOutputPerf {
+template <typename T, typename R> class BinaryOpSingleDifferentTypeOutputPerf {
   using FPBits = fputil::FPBits<T>;
   using StorageType = typename FPBits::StorageType;
-  static constexpr StorageType UIntMax = cpp::numeric_limits<StorageType>::max();
+  static constexpr StorageType UIntMax =
+      cpp::numeric_limits<StorageType>::max();
 
 public:
   typedef T Func(R, R);
@@ -227,7 +227,6 @@ class BinaryOpSingleDifferentTypeOutputPerf {
   }
 };
 
-
 } // namespace testing
 } // namespace LIBC_NAMESPACE_DECL
 
@@ -247,11 +246,12 @@ class BinaryOpSingleDifferentTypeOutputPerf {
         &myFunc, &otherFunc, rounds, filename);                                \
   }
 
-#define BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(T, R, myFunc, otherFunc, rounds, filename) \
-                                                                                             \
-  {									                     \
-    LIBC_NAMESPACE::testing::BinaryOpSingleDifferentTypeOutputPerf<T,R>::run_perf(           \
-        &myFunc, &otherFunc, rounds, filename);                                              \
-     LIBC_NAMESPACE::testing::BinaryOpSingleDifferentTypeOutputPerf<T,R>::run_perf(          \
-        &myFunc, &otherFunc, rounds, filename);                                              \
-   }
+#define BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(                        \
+    T, R, myFunc, otherFunc, rounds, filename)                                 \
+                                                                               \
+  {                                                                            \
+    LIBC_NAMESPACE::testing::BinaryOpSingleDifferentTypeOutputPerf<            \
+        T, R>::run_perf(&myFunc, &otherFunc, rounds, filename);                \
+    LIBC_NAMESPACE::testing::BinaryOpSingleDifferentTypeOutputPerf<            \
+        T, R>::run_perf(&myFunc, &otherFunc, rounds, filename);                \
+  }
diff --git a/libc/test/src/math/performance_testing/fmul_perf.cpp b/libc/test/src/math/performance_testing/fmul_perf.cpp
index 1d242fd3d19647..9e692b1848602e 100644
--- a/libc/test/src/math/performance_testing/fmul_perf.cpp
+++ b/libc/test/src/math/performance_testing/fmul_perf.cpp
@@ -15,20 +15,19 @@ static constexpr size_t DOUBLE_ROUNDS = 40;
 static constexpr size_t LONG_DOUBLE_ROUNDS = 40;
 
 float fmul_placeholder_binary(double x, double y) {
-  return static_cast<float>(x*y);
+  return static_cast<float>(x * y);
 }
 
 float fmull_placeholder_binary(long double x, long double y) {
-  return static_cast<float>(x*y);
+  return static_cast<float>(x * y);
 }
 
 int main() {
-  BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(float, double, LIBC_NAMESPACE::fmul,
-				  fmul_placeholder_binary, DOUBLE_ROUNDS,
-				  "fmul_perf.log")
-  BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(float, long double, LIBC_NAMESPACE::fmull,
-				  fmull_placeholder_binary, LONG_DOUBLE_ROUNDS,
-				  "fmull_perf.log")
+  BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(
+      float, double, LIBC_NAMESPACE::fmul, fmul_placeholder_binary,
+      DOUBLE_ROUNDS, "fmul_perf.log")
+  BINARY_OP_SINGLE_DIFFERENT_TYPE_OUTPUT_PERF_EX(
+      float, long double, LIBC_NAMESPACE::fmull, fmull_placeholder_binary,
+      LONG_DOUBLE_ROUNDS, "fmull_perf.log")
   return 0;
 }
-    



More information about the libc-commits mailing list