1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/profiling/memory/bookkeeping.h"
18
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21
22 namespace perfetto {
23 namespace profiling {
24 namespace {
25
26 using ::testing::AnyOf;
27 using ::testing::Eq;
28
stack()29 std::vector<FrameData> stack() {
30 std::vector<FrameData> res;
31
32 unwindstack::FrameData data{};
33 data.function_name = "fun1";
34 data.map_name = "map1";
35 res.emplace_back(std::move(data), "dummy_buildid");
36 data = {};
37 data.function_name = "fun2";
38 data.map_name = "map2";
39 res.emplace_back(std::move(data), "dummy_buildid");
40 return res;
41 }
42
stack2()43 std::vector<FrameData> stack2() {
44 std::vector<FrameData> res;
45 unwindstack::FrameData data{};
46 data.function_name = "fun1";
47 data.map_name = "map1";
48 res.emplace_back(std::move(data), "dummy_buildid");
49 data = {};
50 data.function_name = "fun3";
51 data.map_name = "map3";
52 res.emplace_back(std::move(data), "dummy_buildid");
53 return res;
54 }
55
TEST(BookkeepingTest,Basic)56 TEST(BookkeepingTest, Basic) {
57 uint64_t sequence_number = 1;
58 GlobalCallstackTrie c;
59 HeapTracker hd(&c);
60
61 hd.RecordMalloc(stack(), 1, 5, sequence_number, 100 * sequence_number);
62 sequence_number++;
63 hd.RecordMalloc(stack2(), 2, 2, sequence_number, 100 * sequence_number);
64 sequence_number++;
65 ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
66 ASSERT_EQ(hd.GetSizeForTesting(stack2()), 2);
67 ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
68 hd.RecordFree(2, sequence_number, 100 * sequence_number);
69 sequence_number++;
70 ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
71 ASSERT_EQ(hd.GetSizeForTesting(stack2()), 0);
72 ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
73 hd.RecordFree(1, sequence_number, 100 * sequence_number);
74 sequence_number++;
75 ASSERT_EQ(hd.GetSizeForTesting(stack()), 0);
76 ASSERT_EQ(hd.GetSizeForTesting(stack2()), 0);
77 ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
78 }
79
TEST(BookkeepingTest,TwoHeapTrackers)80 TEST(BookkeepingTest, TwoHeapTrackers) {
81 uint64_t sequence_number = 1;
82 GlobalCallstackTrie c;
83 HeapTracker hd(&c);
84 {
85 HeapTracker hd2(&c);
86
87 hd.RecordMalloc(stack(), 1, 5, sequence_number, 100 * sequence_number);
88 hd2.RecordMalloc(stack(), 2, 2, sequence_number, 100 * sequence_number);
89 sequence_number++;
90 ASSERT_EQ(hd2.GetSizeForTesting(stack()), 2);
91 ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
92 ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
93 }
94 ASSERT_EQ(hd.GetSizeForTesting(stack()), 5);
95 }
96
TEST(BookkeepingTest,ReplaceAlloc)97 TEST(BookkeepingTest, ReplaceAlloc) {
98 uint64_t sequence_number = 1;
99 GlobalCallstackTrie c;
100 HeapTracker hd(&c);
101
102 hd.RecordMalloc(stack(), 1, 5, sequence_number, 100 * sequence_number);
103 sequence_number++;
104 hd.RecordMalloc(stack2(), 1, 2, sequence_number, 100 * sequence_number);
105 sequence_number++;
106 EXPECT_EQ(hd.GetSizeForTesting(stack()), 0);
107 EXPECT_EQ(hd.GetSizeForTesting(stack2()), 2);
108 ASSERT_EQ(hd.GetTimestampForTesting(), 100 * (sequence_number - 1));
109 }
110
TEST(BookkeepingTest,OutOfOrder)111 TEST(BookkeepingTest, OutOfOrder) {
112 GlobalCallstackTrie c;
113 HeapTracker hd(&c);
114
115 hd.RecordMalloc(stack(), 1, 5, 2, 2);
116 hd.RecordMalloc(stack2(), 1, 2, 1, 1);
117 EXPECT_EQ(hd.GetSizeForTesting(stack()), 5);
118 EXPECT_EQ(hd.GetSizeForTesting(stack2()), 0);
119 }
120
TEST(BookkeepingTest,ManyAllocations)121 TEST(BookkeepingTest, ManyAllocations) {
122 GlobalCallstackTrie c;
123 HeapTracker hd(&c);
124
125 std::vector<std::pair<uint64_t, uint64_t>> batch_frees;
126
127 for (uint64_t sequence_number = 1; sequence_number < 1000;) {
128 if (batch_frees.size() > 10) {
129 for (const auto& p : batch_frees)
130 hd.RecordFree(p.first, p.second, 100 * p.second);
131 batch_frees.clear();
132 }
133
134 uint64_t addr = sequence_number;
135 hd.RecordMalloc(stack(), addr, 5, sequence_number, sequence_number);
136 sequence_number++;
137 batch_frees.emplace_back(addr, sequence_number++);
138 ASSERT_THAT(hd.GetSizeForTesting(stack()), AnyOf(Eq(0), Eq(5)));
139 }
140 }
141
TEST(BookkeepingTest,ArbitraryOrder)142 TEST(BookkeepingTest, ArbitraryOrder) {
143 std::vector<FrameData> s = stack();
144 std::vector<FrameData> s2 = stack2();
145
146 struct Operation {
147 uint64_t sequence_number;
148 uint64_t address;
149 uint64_t bytes; // 0 for free
150 const std::vector<FrameData>* stack; // nullptr for free
151
152 // For std::next_permutation.
153 bool operator<(const Operation& other) const {
154 return sequence_number < other.sequence_number;
155 }
156 } operations[] = {
157 {1, 1, 5, &s}, //
158 {2, 1, 10, &s2}, //
159 {3, 1, 0, nullptr}, //
160 {4, 2, 0, nullptr}, //
161 {5, 3, 0, nullptr}, //
162 {6, 3, 2, &s}, //
163 {7, 4, 3, &s2}, //
164 };
165
166 uint64_t s_size = 2;
167 uint64_t s2_size = 3;
168
169 do {
170 GlobalCallstackTrie c;
171 HeapTracker hd(&c);
172
173 for (auto it = std::begin(operations); it != std::end(operations); ++it) {
174 const Operation& operation = *it;
175
176 if (operation.bytes == 0) {
177 hd.RecordFree(operation.address, operation.sequence_number,
178 100 * operation.sequence_number);
179 } else {
180 hd.RecordMalloc(*operation.stack, operation.address, operation.bytes,
181 operation.sequence_number,
182 100 * operation.sequence_number);
183 }
184 }
185 ASSERT_EQ(hd.GetSizeForTesting(s), s_size);
186 ASSERT_EQ(hd.GetSizeForTesting(s2), s2_size);
187 } while (std::next_permutation(std::begin(operations), std::end(operations)));
188 }
189
190 } // namespace
191 } // namespace profiling
192 } // namespace perfetto
193