diff options
Diffstat (limited to 'chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc')
-rw-r--r-- | chromium/base/allocator/partition_allocator/partition_alloc_perftest.cc | 278 |
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 |