• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/sampling_heap_profiler/sampling_heap_profiler.h"
6 
7 #include <stdlib.h>
8 #include <cinttypes>
9 
10 #include "base/allocator/allocator_shim.h"
11 #include "base/debug/alias.h"
12 #include "base/threading/simple_thread.h"
13 #include "build/build_config.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace base {
17 namespace {
18 
19 class SamplingHeapProfilerTest : public ::testing::Test {
20 #if defined(OS_MACOSX)
SetUp()21   void SetUp() override { allocator::InitializeAllocatorShim(); }
22 #endif
23 };
24 
25 class SamplesCollector : public SamplingHeapProfiler::SamplesObserver {
26  public:
SamplesCollector(size_t watch_size)27   explicit SamplesCollector(size_t watch_size) : watch_size_(watch_size) {}
28 
SampleAdded(uint32_t id,size_t size,size_t)29   void SampleAdded(uint32_t id, size_t size, size_t) override {
30     if (sample_added || size != watch_size_)
31       return;
32     sample_id_ = id;
33     sample_added = true;
34   }
35 
SampleRemoved(uint32_t id)36   void SampleRemoved(uint32_t id) override {
37     if (id == sample_id_)
38       sample_removed = true;
39   }
40 
41   bool sample_added = false;
42   bool sample_removed = false;
43 
44  private:
45   size_t watch_size_;
46   uint32_t sample_id_ = 0;
47 };
48 
TEST_F(SamplingHeapProfilerTest,CollectSamples)49 TEST_F(SamplingHeapProfilerTest, CollectSamples) {
50   SamplingHeapProfiler::InitTLSSlot();
51   SamplesCollector collector(10000);
52   SamplingHeapProfiler* profiler = SamplingHeapProfiler::GetInstance();
53   profiler->SuppressRandomnessForTest(true);
54   profiler->SetSamplingInterval(1024);
55   profiler->Start();
56   profiler->AddSamplesObserver(&collector);
57   void* volatile p = malloc(10000);
58   free(p);
59   profiler->Stop();
60   profiler->RemoveSamplesObserver(&collector);
61   CHECK(collector.sample_added);
62   CHECK(collector.sample_removed);
63 }
64 
65 const int kNumberOfAllocations = 10000;
66 
Allocate1()67 NOINLINE void Allocate1() {
68   void* p = malloc(400);
69   base::debug::Alias(&p);
70 }
71 
Allocate2()72 NOINLINE void Allocate2() {
73   void* p = malloc(700);
74   base::debug::Alias(&p);
75 }
76 
Allocate3()77 NOINLINE void Allocate3() {
78   void* p = malloc(20480);
79   base::debug::Alias(&p);
80 }
81 
82 class MyThread1 : public SimpleThread {
83  public:
MyThread1()84   MyThread1() : SimpleThread("MyThread1") {}
Run()85   void Run() override {
86     for (int i = 0; i < kNumberOfAllocations; ++i)
87       Allocate1();
88   }
89 };
90 
91 class MyThread2 : public SimpleThread {
92  public:
MyThread2()93   MyThread2() : SimpleThread("MyThread2") {}
Run()94   void Run() override {
95     for (int i = 0; i < kNumberOfAllocations; ++i)
96       Allocate2();
97   }
98 };
99 
CheckAllocationPattern(void (* allocate_callback)())100 void CheckAllocationPattern(void (*allocate_callback)()) {
101   SamplingHeapProfiler::InitTLSSlot();
102   SamplingHeapProfiler* profiler = SamplingHeapProfiler::GetInstance();
103   profiler->SuppressRandomnessForTest(false);
104   profiler->SetSamplingInterval(10240);
105   base::TimeTicks t0 = base::TimeTicks::Now();
106   std::map<size_t, size_t> sums;
107   const int iterations = 40;
108   for (int i = 0; i < iterations; ++i) {
109     uint32_t id = profiler->Start();
110     allocate_callback();
111     std::vector<SamplingHeapProfiler::Sample> samples =
112         profiler->GetSamples(id);
113     profiler->Stop();
114     std::map<size_t, size_t> buckets;
115     for (auto& sample : samples) {
116       buckets[sample.size] += sample.total;
117     }
118     for (auto& it : buckets) {
119       if (it.first != 400 && it.first != 700 && it.first != 20480)
120         continue;
121       sums[it.first] += it.second;
122       printf("%zu,", it.second);
123     }
124     printf("\n");
125   }
126 
127   printf("Time taken %" PRIu64 "ms\n",
128          (base::TimeTicks::Now() - t0).InMilliseconds());
129 
130   for (auto sum : sums) {
131     intptr_t expected = sum.first * kNumberOfAllocations;
132     intptr_t actual = sum.second / iterations;
133     printf("%zu:\tmean: %zu\trelative error: %.2f%%\n", sum.first, actual,
134            100. * (actual - expected) / expected);
135   }
136 }
137 
138 // Manual tests to check precision of the sampling profiler.
139 // Yes, they do leak lots of memory.
140 
TEST_F(SamplingHeapProfilerTest,DISABLED_ParallelLargeSmallStats)141 TEST_F(SamplingHeapProfilerTest, DISABLED_ParallelLargeSmallStats) {
142   CheckAllocationPattern([]() {
143     SimpleThread* t1 = new MyThread1();
144     SimpleThread* t2 = new MyThread2();
145     t1->Start();
146     t2->Start();
147     for (int i = 0; i < kNumberOfAllocations; ++i)
148       Allocate3();
149     t1->Join();
150     t2->Join();
151   });
152 }
153 
TEST_F(SamplingHeapProfilerTest,DISABLED_SequentialLargeSmallStats)154 TEST_F(SamplingHeapProfilerTest, DISABLED_SequentialLargeSmallStats) {
155   CheckAllocationPattern([]() {
156     for (int i = 0; i < kNumberOfAllocations; ++i) {
157       Allocate1();
158       Allocate2();
159       Allocate3();
160     }
161   });
162 }
163 
164 }  // namespace
165 }  // namespace base
166