[libcxx-commits] [libcxx] 8421364 - Modifications to the algorithm sort benchmark

Martijn Vels via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 6 15:32:17 PDT 2020


Author: MinJae Hwang
Date: 2020-07-06T18:30:02-04:00
New Revision: 8421364282646f5f398d76ffce13a37fe541f015

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

LOG: Modifications to the algorithm sort benchmark

Summary:
Modifies the algorithm sort bench:
- shows sorting time per element, instead of sorting time per array.
This would make comparison between different sizes of arrays easier.
- adds std::pair benchmark cases.
- uses a large number of arrays to benchmark, instead of repeatedly sorting the same array.
* sorting the same array again and again would not show actual sorting performance over randomized data sets.

Reviewers: EricWF, #libc, mvels

Reviewed By: EricWF, #libc, mvels

Subscribers: mgrang, libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D81770

Added: 
    

Modified: 
    libcxx/benchmarks/algorithms.bench.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/benchmarks/algorithms.bench.cpp b/libcxx/benchmarks/algorithms.bench.cpp
index b259d476457b..93383e2b9cd6 100644
--- a/libcxx/benchmarks/algorithms.bench.cpp
+++ b/libcxx/benchmarks/algorithms.bench.cpp
@@ -14,14 +14,23 @@
 
 namespace {
 
-enum class ValueType { Uint32, String };
-struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 2> {
-  static constexpr const char* Names[] = {"uint32", "string"};
+enum class ValueType { Uint32, Uint64, Pair, Tuple, String };
+struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 5> {
+  static constexpr const char* Names[] = {
+      "uint32", "uint64", "pair<uint32, uint32>",
+      "tuple<uint32, uint64, uint32>", "string"};
 };
 
 template <class V>
-using Value =
-    std::conditional_t<V() == ValueType::Uint32, uint32_t, std::string>;
+using Value = std::conditional_t<
+    V() == ValueType::Uint32, uint32_t,
+    std::conditional_t<
+        V() == ValueType::Uint64, uint64_t,
+        std::conditional_t<
+            V() == ValueType::Pair, std::pair<uint32_t, uint32_t>,
+            std::conditional_t<V() == ValueType::Tuple,
+                               std::tuple<uint32_t, uint64_t, uint32_t>,
+                               std::string> > > >;
 
 enum class Order {
   Random,
@@ -37,7 +46,8 @@ struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 6> {
                                           "PipeOrgan",  "Heap"};
 };
 
-void fillValues(std::vector<uint32_t>& V, size_t N, Order O) {
+template <typename T>
+void fillValues(std::vector<T>& V, size_t N, Order O) {
   if (O == Order::SingleElement) {
     V.resize(N, 0);
   } else {
@@ -46,13 +56,49 @@ void fillValues(std::vector<uint32_t>& V, size_t N, Order O) {
   }
 }
 
-void fillValues(std::vector<std::string>& V, size_t N, Order O) {
+template <typename T>
+void fillValues(std::vector<std::pair<T, T> >& V, size_t N, Order O) {
+  if (O == Order::SingleElement) {
+    V.resize(N, std::make_pair(0, 0));
+  } else {
+    while (V.size() < N)
+      // Half of array will have the same first element.
+      if (V.size() % 2) {
+        V.push_back(std::make_pair(V.size(), V.size()));
+      } else {
+        V.push_back(std::make_pair(0, V.size()));
+      }
+  }
+}
 
+template <typename T1, typename T2, typename T3>
+void fillValues(std::vector<std::tuple<T1, T2, T3> >& V, size_t N, Order O) {
+  if (O == Order::SingleElement) {
+    V.resize(N, std::make_tuple(0, 0, 0));
+  } else {
+    while (V.size() < N)
+      // One third of array will have the same first element.
+      // One third of array will have the same first element and the same second element.
+      switch (V.size() % 3) {
+      case 0:
+        V.push_back(std::make_tuple(V.size(), V.size(), V.size()));
+        break;
+      case 1:
+        V.push_back(std::make_tuple(0, V.size(), V.size()));
+        break;
+      case 2:
+        V.push_back(std::make_tuple(0, 0, V.size()));
+        break;
+      }
+  }
+}
+
+void fillValues(std::vector<std::string>& V, size_t N, Order O) {
   if (O == Order::SingleElement) {
-    V.resize(N, getRandomString(1024));
+    V.resize(N, getRandomString(64));
   } else {
     while (V.size() < N)
-      V.push_back(getRandomString(1024));
+      V.push_back(getRandomString(64));
   }
 }
 
@@ -85,21 +131,24 @@ void sortValues(T& V, Order O) {
   }
 }
 
+constexpr size_t TestSetElements =
+#if !TEST_HAS_FEATURE(memory_sanitizer)
+    1 << 18;
+#else
+    1 << 14;
+#endif
+
 template <class ValueType>
 std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
                                                                Order O) {
-  // Let's make sure that all random sequences of the same size are the same.
-  // That way we can compare the 
diff erent algorithms with the same input.
-  static std::map<std::pair<size_t, Order>, std::vector<Value<ValueType> > >
-      Cached;
-
-  auto& Values = Cached[{N, O}];
-  if (Values.empty()) {
-    fillValues(Values, N, O);
-    sortValues(Values, O);
-  };
-  const size_t NumCopies = std::max(size_t{1}, 1000 / N);
-  return { NumCopies, Values };
+  std::vector<std::vector<Value<ValueType> > > Ret;
+  const size_t NumCopies = std::max(size_t{1}, TestSetElements / N);
+  Ret.resize(NumCopies);
+  for (auto& V : Ret) {
+    fillValues(V, N, O);
+    sortValues(V, O);
+  }
+  return Ret;
 }
 
 template <class T, class U>
@@ -111,19 +160,28 @@ TEST_ALWAYS_INLINE void resetCopies(benchmark::State& state, T& Copies,
   state.ResumeTiming();
 }
 
+enum class BatchSize {
+  CountElements,
+  CountBatch,
+};
+
 template <class ValueType, class F>
 void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
-                   bool CountElements, F f) {
+                   BatchSize Count, F Body) {
   auto Copies = makeOrderedValues<ValueType>(Quantity, O);
-  const auto Orig = Copies[0];
+  auto Orig = Copies;
 
-  const size_t Batch = CountElements ? Copies.size() * Quantity : Copies.size();
+  const size_t Batch = Count == BatchSize::CountElements
+                           ? Copies.size() * Quantity
+                           : Copies.size();
   while (state.KeepRunningBatch(Batch)) {
     for (auto& Copy : Copies) {
-      f(Copy);
+      Body(Copy);
       benchmark::DoNotOptimize(Copy);
     }
-    resetCopies(state, Copies, Orig);
+    state.PauseTiming();
+    Copies = Orig;
+    state.ResumeTiming();
   }
 }
 
@@ -132,9 +190,9 @@ struct Sort {
   size_t Quantity;
 
   void run(benchmark::State& state) const {
-    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
-      std::sort(Copy.begin(), Copy.end());
-    });
+    runOpOnCopies<ValueType>(
+        state, Quantity, Order(), BatchSize::CountElements,
+        [](auto& Copy) { std::sort(Copy.begin(), Copy.end()); });
   }
 
   bool skip() const { return Order() == ::Order::Heap; }
@@ -150,9 +208,9 @@ struct StableSort {
   size_t Quantity;
 
   void run(benchmark::State& state) const {
-    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
-      std::stable_sort(Copy.begin(), Copy.end());
-    });
+    runOpOnCopies<ValueType>(
+        state, Quantity, Order(), BatchSize::CountElements,
+        [](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); });
   }
 
   bool skip() const { return Order() == ::Order::Heap; }
@@ -168,9 +226,9 @@ struct MakeHeap {
   size_t Quantity;
 
   void run(benchmark::State& state) const {
-    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
-      std::make_heap(Copy.begin(), Copy.end());
-    });
+    runOpOnCopies<ValueType>(
+        state, Quantity, Order(), BatchSize::CountElements,
+        [](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); });
   }
 
   std::string name() const {
@@ -185,7 +243,7 @@ struct SortHeap {
 
   void run(benchmark::State& state) const {
     runOpOnCopies<ValueType>(
-        state, Quantity, Order::Heap, false,
+        state, Quantity, Order::Heap, BatchSize::CountElements,
         [](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
   }
 
@@ -199,10 +257,11 @@ struct MakeThenSortHeap {
   size_t Quantity;
 
   void run(benchmark::State& state) const {
-    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
-      std::make_heap(Copy.begin(), Copy.end());
-      std::sort_heap(Copy.begin(), Copy.end());
-    });
+    runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
+                             [](auto& Copy) {
+                               std::make_heap(Copy.begin(), Copy.end());
+                               std::sort_heap(Copy.begin(), Copy.end());
+                             });
   }
 
   std::string name() const {
@@ -216,11 +275,12 @@ struct PushHeap {
   size_t Quantity;
 
   void run(benchmark::State& state) const {
-    runOpOnCopies<ValueType>(state, Quantity, Order(), true, [](auto& Copy) {
-      for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
-        std::push_heap(Copy.begin(), I + 1);
-      }
-    });
+    runOpOnCopies<ValueType>(
+        state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
+          for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
+            std::push_heap(Copy.begin(), I + 1);
+          }
+        });
   }
 
   bool skip() const { return Order() == ::Order::Heap; }
@@ -236,11 +296,12 @@ struct PopHeap {
   size_t Quantity;
 
   void run(benchmark::State& state) const {
-    runOpOnCopies<ValueType>(state, Quantity, Order(), true, [](auto& Copy) {
-      for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
-        std::pop_heap(B, I);
-      }
-    });
+    runOpOnCopies<ValueType>(
+        state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
+          for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
+            std::pop_heap(B, I);
+          }
+        });
   }
 
   std::string name() const {
@@ -273,4 +334,4 @@ int main(int argc, char** argv) {
   makeCartesianProductBenchmark<PushHeap, AllValueTypes, AllOrders>(Quantities);
   makeCartesianProductBenchmark<PopHeap, AllValueTypes>(Quantities);
   benchmark::RunSpecifiedBenchmarks();
-}
+}
\ No newline at end of file


        


More information about the libcxx-commits mailing list