chromium/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_perftest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "partition_alloc/partition_alloc.h"

#include <algorithm>
#include <atomic>
#include <limits>
#include <memory>
#include <vector>

#include "base/debug/debugging_buildflags.h"
#include "base/timer/lap_timer.h"
#include "partition_alloc/build_config.h"
#include "partition_alloc/extended_api.h"
#include "partition_alloc/partition_alloc_base/logging.h"
#include "partition_alloc/partition_alloc_base/strings/stringprintf.h"
#include "partition_alloc/partition_alloc_base/threading/platform_thread_for_testing.h"
#include "partition_alloc/partition_alloc_base/time/time.h"
#include "partition_alloc/partition_alloc_check.h"
#include "partition_alloc/partition_alloc_constants.h"
#include "partition_alloc/partition_alloc_for_testing.h"
#include "partition_alloc/partition_root.h"
#include "partition_alloc/thread_cache.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"

#if PA_BUILDFLAG(IS_ANDROID) || PA_BUILDFLAG(PA_ARCH_CPU_32_BITS) || \
    PA_BUILDFLAG(IS_FUCHSIA)
// Some tests allocate many GB of memory, which can cause issues on Android and
// address-space exhaustion for any 32-bit process.
#define MEMORY_CONSTRAINED
#endif

#if BUILDFLAG(ENABLE_ALLOCATION_STACK_TRACE_RECORDER)
#include "base/allocator/dispatcher/dispatcher.h"
#include "base/debug/allocation_trace.h"
#endif

namespace partition_alloc::internal {

namespace {

// Change kTimeLimit to something higher if you need more time to capture a
// trace.
constexpr ::base::TimeDelta kTimeLimit =;
constexpr int kWarmupRuns =;
constexpr int kTimeCheckInterval =;
constexpr size_t kAllocSize =;

// Size constants are mostly arbitrary, but try to simulate something like CSS
// parsing which consists of lots of relatively small objects.
constexpr int kMultiBucketMinimumSize =;
constexpr int kMultiBucketIncrement =;
// Final size is 24 + (13 * 22) = 310 bytes.
constexpr int kMultiBucketRounds =;

constexpr char kMetricPrefixMemoryAllocation[] =;
constexpr char kMetricThroughput[] =;
constexpr char kMetricTimePerAllocation[] =;

perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {}

enum class AllocatorType {};

class Allocator {};

class SystemAllocator : public Allocator {};

class PartitionAllocator : public Allocator {};

class PartitionAllocatorWithThreadCache : public Allocator {};

#if BUILDFLAG(ENABLE_ALLOCATION_STACK_TRACE_RECORDER)
class PartitionAllocatorWithAllocationStackTraceRecorder : public Allocator {
 public:
  explicit PartitionAllocatorWithAllocationStackTraceRecorder(
      bool register_hooks)
      : register_hooks_(register_hooks) {
    if (register_hooks_) {
      dispatcher_.InitializeForTesting(&recorder_);
    }
  }

  ~PartitionAllocatorWithAllocationStackTraceRecorder() override {
    if (register_hooks_) {
      dispatcher_.ResetForTesting();
    }
  }

  void* Alloc(size_t size) override { return alloc_.AllocInline(size); }

  void Free(void* data) override {
    // Even though it's easy to invoke the fast path with
    // alloc_.Free<kNoHooks>(), we chose to use the slower path, because it's
    // more common with PA-E.
    PartitionRoot::FreeInlineInUnknownRoot<
        partition_alloc::FreeFlags::kNoHooks>(data);
  }

 private:
  bool const register_hooks_;
  PartitionRoot alloc_{PartitionOptions{}};
  ::base::allocator::dispatcher::Dispatcher& dispatcher_ =
      ::base::allocator::dispatcher::Dispatcher::GetInstance();
  ::base::debug::tracer::AllocationTraceRecorder recorder_;
};
#endif  // BUILDFLAG(ENABLE_ALLOCATION_STACK_TRACE_RECORDER)

class TestLoopThread : public base::PlatformThreadForTesting::Delegate {};

void DisplayResults(const std::string& story_name,
                    float iterations_per_second) {}

class MemoryAllocationPerfNode {};

#if !defined(MEMORY_CONSTRAINED)
float SingleBucket(Allocator* allocator) {}
#endif  // defined(MEMORY_CONSTRAINED)

float SingleBucketWithFree(Allocator* allocator) {}

#if !defined(MEMORY_CONSTRAINED)
float MultiBucket(Allocator* allocator) {}
#endif  // defined(MEMORY_CONSTRAINED)

float MultiBucketWithFree(Allocator* allocator) {}

float DirectMapped(Allocator* allocator) {}

std::unique_ptr<Allocator> CreateAllocator(AllocatorType type,
                                           bool use_alternate_bucket_dist) {}

void LogResults(int thread_count,
                AllocatorType alloc_type,
                uint64_t total_laps_per_second,
                uint64_t min_laps_per_second) {}

void RunTest(int thread_count,
             bool use_alternate_bucket_dist,
             AllocatorType alloc_type,
             float (*test_fn)(Allocator*),
             float (*noisy_neighbor_fn)(Allocator*),
             const char* story_base_name) {}

class PartitionAllocMemoryAllocationPerfTest
    : public testing::TestWithParam<std::tuple<int, bool, AllocatorType>> {};

// Only one partition with a thread cache: cannot use the thread cache when
// PartitionAlloc is malloc().
INSTANTIATE_TEST_SUITE_P();

// This test (and the other one below) allocates a large amount of memory, which
// can cause issues on Android.
#if !defined(MEMORY_CONSTRAINED)
TEST_P(PartitionAllocMemoryAllocationPerfTest, SingleBucket) {}
#endif  // defined(MEMORY_CONSTRAINED)

TEST_P(PartitionAllocMemoryAllocationPerfTest, SingleBucketWithFree) {}

#if !defined(MEMORY_CONSTRAINED)
TEST_P(PartitionAllocMemoryAllocationPerfTest, MultiBucket) {}
#endif  // defined(MEMORY_CONSTRAINED)

TEST_P(PartitionAllocMemoryAllocationPerfTest, MultiBucketWithFree) {}

TEST_P(PartitionAllocMemoryAllocationPerfTest, DirectMapped) {}

#if !defined(MEMORY_CONSTRAINED)
TEST_P(PartitionAllocMemoryAllocationPerfTest,
       DISABLED_MultiBucketWithNoisyNeighbor) {}
#endif  // !defined(MEMORY_CONSTRAINED)

}  // namespace

}  // namespace partition_alloc::internal