summaryrefslogtreecommitdiffstats
path: root/chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc')
-rw-r--r--chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc278
1 files changed, 183 insertions, 95 deletions
diff --git a/chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc b/chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc
index 85b782a5eef..bdd85f0ae1d 100644
--- a/chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc
+++ b/chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <atomic>
#include <vector>
+
#include "base/allocator/partition_allocator/partition_alloc.h"
+#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/timer/lap_timer.h"
-
#include "build/build_config.h"
-
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -28,19 +29,47 @@ constexpr int kMultiBucketIncrement = 13;
// Final size is 24 + (13 * 22) = 310 bytes.
constexpr int kMultiBucketRounds = 22;
-class MemoryAllocationPerfTest : public testing::Test {
+class AllocatingThread : public PlatformThread::Delegate {
public:
- MemoryAllocationPerfTest()
- : timer_(kWarmupRuns, kTimeLimit, kTimeCheckInterval) {}
- void SetUp() override { alloc_.init(); }
- void TearDown() override {
- alloc_.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages |
- PartitionPurgeDiscardUnusedSystemPages);
+ explicit AllocatingThread(PartitionAllocatorGeneric* allocator)
+ : allocator_(allocator), should_stop_(false) {
+ PlatformThread::Create(0, this, &thread_handle_);
}
- LapTimer timer_;
- PartitionAllocatorGeneric alloc_;
+
+ ~AllocatingThread() override {
+ should_stop_ = true;
+ PlatformThread::Join(thread_handle_);
+ }
+
+ // Allocates and frees memory in a loop until |should_stop_| becomes true.
+ void ThreadMain() override {
+ uint64_t count = 0;
+ while (true) {
+ // Only check |should_stop_| every 2^15 iterations, as it is a
+ // sequentially consistent access, hence expensive.
+ if (count % (1 << 15) == 0 && should_stop_)
+ break;
+ void* data = allocator_->root()->Alloc(10, "");
+ allocator_->root()->Free(data);
+ count++;
+ }
+ }
+
+ PartitionAllocatorGeneric* allocator_;
+ std::atomic<bool> should_stop_;
+ PlatformThreadHandle thread_handle_;
};
+void DisplayResults(const std::string& measurement,
+ const std::string& modifier,
+ size_t iterations_per_second) {
+ perf_test::PrintResult(measurement, modifier, "", iterations_per_second,
+ "runs/s", true);
+ perf_test::PrintResult(measurement, modifier, "",
+ static_cast<size_t>(1e9 / iterations_per_second),
+ "ns/run", true);
+}
+
class MemoryAllocationPerfNode {
public:
MemoryAllocationPerfNode* GetNext() const { return next_; }
@@ -59,110 +88,169 @@ class MemoryAllocationPerfNode {
MemoryAllocationPerfNode* next_ = nullptr;
};
-TEST_F(MemoryAllocationPerfTest, SingleBucket) {
- timer_.Reset();
- MemoryAllocationPerfNode* first = reinterpret_cast<MemoryAllocationPerfNode*>(
- alloc_.root()->Alloc(40, "<testing>"));
- MemoryAllocationPerfNode* cur = first;
- do {
- MemoryAllocationPerfNode* next =
+class MemoryAllocationPerfTest : public testing::Test {
+ public:
+ MemoryAllocationPerfTest()
+ : timer_(kWarmupRuns, kTimeLimit, kTimeCheckInterval) {}
+ void SetUp() override { alloc_.init(); }
+ void TearDown() override {
+ alloc_.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages |
+ PartitionPurgeDiscardUnusedSystemPages);
+ }
+
+ protected:
+ void TestSingleBucket() {
+ MemoryAllocationPerfNode* first =
reinterpret_cast<MemoryAllocationPerfNode*>(
alloc_.root()->Alloc(40, "<testing>"));
- CHECK_NE(next, nullptr);
- cur->SetNext(next);
- cur = next;
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
- // next_ = nullptr only works if the class constructor is called (it's not
- // called in this case because then we can allocate arbitrary-length
- // payloads.)
- cur->SetNext(nullptr);
-
- MemoryAllocationPerfNode::FreeAll(first, alloc_);
-
- perf_test::PrintResult("MemoryAllocationPerfTest",
- " single bucket allocation (40 bytes)", "",
- timer_.LapsPerSecond(), "runs/s", true);
-}
-
-TEST_F(MemoryAllocationPerfTest, SingleBucketWithFree) {
- timer_.Reset();
- // Allocate an initial element to make sure the bucket stays set up.
- void* elem = alloc_.root()->Alloc(40, "<testing>");
- do {
- void* cur = alloc_.root()->Alloc(40, "<testing>");
- CHECK_NE(cur, nullptr);
- alloc_.root()->Free(cur);
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- alloc_.root()->Free(elem);
- perf_test::PrintResult("MemoryAllocationPerfTest",
- " single bucket allocation + free (40 bytes)", "",
- timer_.LapsPerSecond(), "runs/s", true);
-}
-// Failing on Nexus5x: crbug.com/949838
-#if defined(OS_ANDROID)
-#define MAYBE_MultiBucket DISABLED_MultiBucket
-#else
-#define MAYBE_MultiBucket MultiBucket
-#endif
-TEST_F(MemoryAllocationPerfTest, MAYBE_MultiBucket) {
- timer_.Reset();
- MemoryAllocationPerfNode* first = reinterpret_cast<MemoryAllocationPerfNode*>(
- alloc_.root()->Alloc(40, "<testing>"));
- MemoryAllocationPerfNode* cur = first;
- do {
- for (int i = 0; i < kMultiBucketRounds; i++) {
+ timer_.Reset();
+ MemoryAllocationPerfNode* cur = first;
+ do {
MemoryAllocationPerfNode* next =
- reinterpret_cast<MemoryAllocationPerfNode*>(alloc_.root()->Alloc(
- kMultiBucketMinimumSize + (i * kMultiBucketIncrement),
- "<testing>"));
+ reinterpret_cast<MemoryAllocationPerfNode*>(
+ alloc_.root()->Alloc(40, "<testing>"));
CHECK_NE(next, nullptr);
cur->SetNext(next);
cur = next;
- }
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
- cur->SetNext(nullptr);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+ // next_ = nullptr only works if the class constructor is called (it's not
+ // called in this case because then we can allocate arbitrary-length
+ // payloads.)
+ cur->SetNext(nullptr);
- MemoryAllocationPerfNode::FreeAll(first, alloc_);
+ MemoryAllocationPerfNode::FreeAll(first, alloc_);
- perf_test::PrintResult("MemoryAllocationPerfTest", " multi-bucket allocation",
- "", timer_.LapsPerSecond() * kMultiBucketRounds,
- "runs/s", true);
-}
+ DisplayResults("MemoryAllocationPerfTest",
+ " single bucket allocation (40 bytes)",
+ timer_.LapsPerSecond());
+ }
-TEST_F(MemoryAllocationPerfTest, MultiBucketWithFree) {
- timer_.Reset();
- std::vector<void*> elems;
- // Do an initial round of allocation to make sure that the buckets stay in use
- // (and aren't accidentally released back to the OS).
- for (int i = 0; i < kMultiBucketRounds; i++) {
- void* cur = alloc_.root()->Alloc(
- kMultiBucketMinimumSize + (i * kMultiBucketIncrement), "<testing>");
- CHECK_NE(cur, nullptr);
- elems.push_back(cur);
+ void TestSingleBucketWithFree() {
+ // Allocate an initial element to make sure the bucket stays set up.
+ void* elem = alloc_.root()->Alloc(40, "<testing>");
+
+ timer_.Reset();
+ do {
+ void* cur = alloc_.root()->Alloc(40, "<testing>");
+ CHECK_NE(cur, nullptr);
+ alloc_.root()->Free(cur);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ alloc_.root()->Free(elem);
+ DisplayResults("MemoryAllocationPerfTest",
+ " single bucket allocation + free (40 bytes)",
+ timer_.LapsPerSecond());
+ }
+
+ void TestMultiBucket() {
+ MemoryAllocationPerfNode* first =
+ reinterpret_cast<MemoryAllocationPerfNode*>(
+ alloc_.root()->Alloc(40, "<testing>"));
+ MemoryAllocationPerfNode* cur = first;
+
+ timer_.Reset();
+ do {
+ for (int i = 0; i < kMultiBucketRounds; i++) {
+ MemoryAllocationPerfNode* next =
+ reinterpret_cast<MemoryAllocationPerfNode*>(alloc_.root()->Alloc(
+ kMultiBucketMinimumSize + (i * kMultiBucketIncrement),
+ "<testing>"));
+ CHECK_NE(next, nullptr);
+ cur->SetNext(next);
+ cur = next;
+ }
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+ cur->SetNext(nullptr);
+
+ MemoryAllocationPerfNode::FreeAll(first, alloc_);
+
+ DisplayResults("MemoryAllocationPerfTest", " multi-bucket allocation",
+ timer_.LapsPerSecond() * kMultiBucketRounds);
}
- do {
+ void TestMultiBucketWithFree() {
+ std::vector<void*> elems;
+ elems.reserve(kMultiBucketRounds);
+ // Do an initial round of allocation to make sure that the buckets stay in
+ // use (and aren't accidentally released back to the OS).
for (int i = 0; i < kMultiBucketRounds; i++) {
void* cur = alloc_.root()->Alloc(
kMultiBucketMinimumSize + (i * kMultiBucketIncrement), "<testing>");
CHECK_NE(cur, nullptr);
- alloc_.root()->Free(cur);
+ elems.push_back(cur);
+ }
+
+ timer_.Reset();
+ do {
+ for (int i = 0; i < kMultiBucketRounds; i++) {
+ void* cur = alloc_.root()->Alloc(
+ kMultiBucketMinimumSize + (i * kMultiBucketIncrement), "<testing>");
+ CHECK_NE(cur, nullptr);
+ alloc_.root()->Free(cur);
+ }
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ for (void* ptr : elems) {
+ alloc_.root()->Free(ptr);
}
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
- for (void* ptr : elems) {
- alloc_.root()->Free(ptr);
+ DisplayResults("MemoryAllocationPerfTest",
+ " multi-bucket allocation + free",
+ timer_.LapsPerSecond() * kMultiBucketRounds);
}
- perf_test::PrintResult(
- "MemoryAllocationPerfTest", " multi-bucket allocation + free", "",
- timer_.LapsPerSecond() * kMultiBucketRounds, "runs/s", true);
+ LapTimer timer_;
+ PartitionAllocatorGeneric alloc_;
+};
+
+TEST_F(MemoryAllocationPerfTest, SingleBucket) {
+ TestSingleBucket();
+}
+
+TEST_F(MemoryAllocationPerfTest, SingleBucketWithCompetingThread) {
+ AllocatingThread t(&alloc_);
+ TestSingleBucket();
+}
+
+TEST_F(MemoryAllocationPerfTest, SingleBucketWithFree) {
+ TestSingleBucketWithFree();
+}
+
+TEST_F(MemoryAllocationPerfTest, SingleBucketWithFreeWithCompetingThread) {
+ AllocatingThread t(&alloc_);
+ TestSingleBucketWithFree();
+}
+
+// Failing on Nexus5x: crbug.com/949838
+#if defined(OS_ANDROID)
+#define MAYBE_MultiBucket DISABLED_MultiBucket
+#define MAYBE_MultiBucketWithCompetingThread \
+ DISABLED_MultiBucketWithCompetingThread
+#else
+#define MAYBE_MultiBucket MultiBucket
+#define MAYBE_MultiBucketWithCompetingThread MultiBucketWithCompetingThread
+#endif
+TEST_F(MemoryAllocationPerfTest, MAYBE_MultiBucket) {
+ TestMultiBucket();
+}
+
+TEST_F(MemoryAllocationPerfTest, MAYBE_MultiBucketWithCompetingThread) {
+ AllocatingThread t(&alloc_);
+ TestMultiBucket();
+}
+
+TEST_F(MemoryAllocationPerfTest, MultiBucketWithFree) {
+ TestMultiBucketWithFree();
+}
+
+TEST_F(MemoryAllocationPerfTest, MultiBucketWithFreeWithCompetingThread) {
+ AllocatingThread t(&alloc_);
+ TestMultiBucketWithFree();
}
} // anonymous namespace