aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/tcmalloc/tcmalloc/heap_profiling_test.cc
blob: 5c4019c98a56547f5a6e176243c7857983da0ba6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright 2019 The TCMalloc Authors 
// 
// Licensed under the Apache License, Version 2.0 (the "License"); 
// you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at 
// 
//     https://www.apache.org/licenses/LICENSE-2.0 
// 
// Unless required by applicable law or agreed to in writing, software 
// distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
// See the License for the specific language governing permissions and 
// limitations under the License. 
 
#include <stdint.h> 
#include <stdlib.h> 
 
#include <memory> 
#include <new> 
 
#include "gtest/gtest.h" 
#include "benchmark/benchmark.h"
#include "tcmalloc/internal/logging.h" 
#include "tcmalloc/internal/parameter_accessors.h" 
#include "tcmalloc/malloc_extension.h" 
#include "tcmalloc/static_vars.h" 
 
namespace tcmalloc { 
namespace { 
 
int64_t ProfileSize(ProfileType type) { 
  int64_t total = 0; 
 
  MallocExtension::SnapshotCurrent(type).Iterate( 
      [&](const Profile::Sample &e) { total += e.sum; }); 
  return total; 
} 
 
class ScopedPeakGrowthFraction { 
 public: 
  explicit ScopedPeakGrowthFraction(double temporary_value) 
      : previous_(TCMalloc_Internal_GetPeakSamplingHeapGrowthFraction()) { 
    TCMalloc_Internal_SetPeakSamplingHeapGrowthFraction(temporary_value); 
  } 
 
  ~ScopedPeakGrowthFraction() { 
    TCMalloc_Internal_SetPeakSamplingHeapGrowthFraction(previous_); 
  } 
 
 private: 
  double previous_; 
}; 
 
TEST(HeapProfilingTest, PeakHeapTracking) { 
  // Adjust high watermark threshold for our scenario, to be independent of 
  // changes to the default.  As we use a random value for choosing our next 
  // sampling point, we may overweight some allocations above their true size. 
  ScopedPeakGrowthFraction s(1.25); 
 
  int64_t start_peak_sz = ProfileSize(ProfileType::kPeakHeap); 
 
  // make a large allocation to force a new peak heap sample 
  // (total live: 50MiB) 
  void *first = ::operator new(50 << 20); 
  // TODO(b/183453911): Remove workaround for GCC 10.x deleting operator new,
  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94295.
  benchmark::DoNotOptimize(first);
  int64_t peak_after_first = ProfileSize(ProfileType::kPeakHeap); 
  EXPECT_NEAR(peak_after_first, start_peak_sz + (50 << 20), 10 << 20); 
 
  // a small allocation shouldn't increase the peak 
  // (total live: 54MiB) 
  void *second = ::operator new(4 << 20); 
  benchmark::DoNotOptimize(second);
  int64_t peak_after_second = ProfileSize(ProfileType::kPeakHeap); 
  EXPECT_EQ(peak_after_second, peak_after_first); 
 
  // but a large one should 
  // (total live: 254MiB) 
  void *third = ::operator new(200 << 20); 
  benchmark::DoNotOptimize(third);
  int64_t peak_after_third = ProfileSize(ProfileType::kPeakHeap); 
  EXPECT_NEAR(peak_after_third, peak_after_second + (200 << 20), 10 << 20); 
 
  // freeing everything shouldn't affect the peak 
  // (total live: 0MiB) 
  ::operator delete(first); 
  EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); 
 
  ::operator delete(second); 
  EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); 
 
  ::operator delete(third); 
  EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); 
 
  // going back up less than previous peak shouldn't affect the peak 
  // (total live: 200MiB) 
  void *fourth = ::operator new(100 << 20); 
  benchmark::DoNotOptimize(fourth);
  void *fifth = ::operator new(100 << 20); 
  benchmark::DoNotOptimize(fifth);
  EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); 
 
  // passing the old peak significantly, even with many small allocations, 
  // should generate a new one 
  // (total live: 200MiB + 256MiB = 456MiB, 80% over the 254MiB peak) 
  void *bitsy[1 << 10]; 
  for (int i = 0; i < 1 << 10; i++) { 
    bitsy[i] = ::operator new(1 << 18); 
    benchmark::DoNotOptimize(bitsy[i]);
  } 
  EXPECT_GT(ProfileSize(ProfileType::kPeakHeap), peak_after_third); 
 
  ::operator delete(fourth); 
  ::operator delete(fifth); 
  for (int i = 0; i < 1 << 10; i++) { 
    ::operator delete(bitsy[i]); 
  } 
} 
 
}  // namespace 
}  // namespace tcmalloc