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
|