about summary refs log tree commit diff homepage
path: root/unittests/KDAlloc/randomtest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/KDAlloc/randomtest.cpp')
-rw-r--r--unittests/KDAlloc/randomtest.cpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/unittests/KDAlloc/randomtest.cpp b/unittests/KDAlloc/randomtest.cpp
new file mode 100644
index 00000000..1120ee4e
--- /dev/null
+++ b/unittests/KDAlloc/randomtest.cpp
@@ -0,0 +1,177 @@
+//===-- randomtest.cpp ----------------------------------------------------===//
+//
+//                     The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/KDAlloc/kdalloc.h"
+#include "xoshiro.h"
+
+#if defined(USE_GTEST_INSTEAD_OF_MAIN)
+#include "gtest/gtest.h"
+#endif
+
+#include <cassert>
+#include <chrono>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <iomanip>
+#include <iostream>
+#include <random>
+#include <utility>
+#include <vector>
+
+namespace {
+class RandomTest {
+  xoshiro512 rng;
+
+#if defined(USE_KDALLOC)
+  klee::kdalloc::Allocator allocator;
+#endif
+
+  std::vector<std::pair<void *, std::size_t>> allocations;
+
+  std::geometric_distribution<std::size_t> allocation_bin_distribution;
+  std::geometric_distribution<std::size_t> large_allocation_distribution;
+
+public:
+  std::size_t maximum_concurrent_allocations = 0;
+  std::uint64_t allocation_count = 0;
+  std::uint64_t deallocation_count = 0;
+
+  RandomTest(std::uint64_t seed = 0x31337)
+      : rng(seed)
+#if defined(USE_KDALLOC)
+        ,
+        allocator(klee::kdalloc::AllocatorFactory(
+            static_cast<std::size_t>(1) << 42, 0))
+#endif
+        ,
+        allocation_bin_distribution(0.3),
+        large_allocation_distribution(0.00003) {
+  }
+
+  void run(std::uint64_t const iterations) {
+    std::uniform_int_distribution<std::uint32_t> choice(0, 999);
+    for (std::uint64_t i = 0; i < iterations; ++i) {
+      auto chosen = choice(rng);
+      if (chosen < 650) {
+        ++allocation_count;
+        allocate_sized();
+      } else if (chosen < 700) {
+        ++allocation_count;
+        allocate_large();
+      } else if (chosen < 1000) {
+        ++deallocation_count;
+        deallocate();
+      }
+    }
+    cleanup();
+  }
+
+  void cleanup() {
+    while (!allocations.empty()) {
+      auto choice = std::uniform_int_distribution<std::size_t>(
+          0, allocations.size() - 1)(rng);
+#if defined(USE_KDALLOC)
+      allocator.free(allocations[choice].first, allocations[choice].second);
+#else
+      free(allocations[choice].first);
+#endif
+      allocations[choice] = allocations.back();
+      allocations.pop_back();
+    }
+  }
+
+  void allocate_sized() {
+    auto bin = allocation_bin_distribution(rng);
+    while (bin >= 11) {
+      bin = allocation_bin_distribution(rng);
+    }
+    auto min = (bin == 0 ? 1 : (static_cast<std::size_t>(1) << (bin + 1)) + 1);
+    auto max = static_cast<std::size_t>(1) << (bin + 2);
+    auto size = std::uniform_int_distribution<std::size_t>(min, max)(rng);
+
+#if defined(USE_KDALLOC)
+    allocations.emplace_back(allocator.allocate(size), size);
+#else
+    allocations.emplace_back(std::malloc(size), size);
+#endif
+    if (allocations.size() > maximum_concurrent_allocations) {
+      maximum_concurrent_allocations = allocations.size();
+    }
+  }
+
+  void allocate_large() {
+    auto size = 0;
+    while (size <= 4096 || size > 1073741825) {
+      size = large_allocation_distribution(rng) + 4097;
+    }
+
+#if defined(USE_KDALLOC)
+    allocations.emplace_back(allocator.allocate(size), size);
+#else
+    allocations.emplace_back(std::malloc(size), size);
+#endif
+    if (allocations.size() > maximum_concurrent_allocations) {
+      maximum_concurrent_allocations = allocations.size();
+    }
+  }
+
+  void deallocate() {
+    if (allocations.empty()) {
+      return;
+    }
+    auto choice = std::uniform_int_distribution<std::size_t>(
+        0, allocations.size() - 1)(rng);
+#if defined(USE_KDALLOC)
+    allocator.free(allocations[choice].first, allocations[choice].second);
+#else
+    free(allocations[choice].first);
+#endif
+    allocations[choice] = allocations.back();
+    allocations.pop_back();
+  }
+};
+} // namespace
+
+#if defined(USE_GTEST_INSTEAD_OF_MAIN)
+int random_test() {
+#else
+int main() {
+#endif
+#if defined(USE_KDALLOC)
+  std::cout << "Using kdalloc\n";
+#else
+  std::cout << "Using std::malloc\n";
+#endif
+  auto start = std::chrono::steady_clock::now();
+
+  RandomTest tester;
+  tester.run(10'000'000);
+
+  auto stop = std::chrono::steady_clock::now();
+  std::cout << std::dec
+            << std::chrono::duration_cast<std::chrono::milliseconds>(stop -
+                                                                     start)
+                   .count()
+            << " ms\n";
+  std::cout << "\n";
+
+  std::cout << "Allocations: " << tester.allocation_count << "\n";
+  std::cout << "Deallocations: " << tester.deallocation_count << "\n";
+  std::cout << "Maximum concurrent allocations: "
+            << tester.maximum_concurrent_allocations << "\n";
+
+  exit(0);
+}
+
+#if defined(USE_GTEST_INSTEAD_OF_MAIN)
+TEST(KDAllocDeathTest, Random) {
+  ASSERT_EXIT(random_test(), ::testing::ExitedWithCode(0), "");
+}
+#endif