OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/trace_event/heap_profiler_allocation_register.h" | 5 #include "base/trace_event/heap_profiler_allocation_register.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include "base/process/process_metrics.h" | 10 #include "base/process/process_metrics.h" |
11 #include "base/trace_event/heap_profiler_allocation_context.h" | 11 #include "base/trace_event/heap_profiler_allocation_context.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
13 | 13 |
14 namespace base { | 14 namespace base { |
15 namespace trace_event { | 15 namespace trace_event { |
16 | 16 |
17 class AllocationRegisterTest : public testing::Test { | 17 class AllocationRegisterTest : public testing::Test { |
18 public: | 18 public: |
19 static const uint32_t kNumBuckets = AllocationRegister::kNumBuckets; | 19 // Use a lower number of cells for unittests to avoid reserving a virtual |
| 20 // region which is too big. |
| 21 static const uint32_t kNumCellsForTesting = |
| 22 AllocationRegister::kNumBuckets + 100; |
20 | 23 |
21 // Returns the number of cells that the |AllocationRegister| can store per | 24 // Returns the number of cells that the |AllocationRegister| can store per |
22 // system page. | 25 // system page. |
23 size_t GetNumCellsPerPage() { | 26 size_t GetNumCellsPerPage() { |
24 return GetPageSize() / sizeof(AllocationRegister::Cell); | 27 return GetPageSize() / sizeof(AllocationRegister::Cell); |
25 } | 28 } |
26 | 29 |
27 uint32_t GetHighWaterMark(const AllocationRegister& reg) { | 30 uint32_t GetHighWaterMark(const AllocationRegister& reg) { |
28 return reg.next_unused_cell_; | 31 return reg.next_unused_cell_; |
29 } | 32 } |
(...skipping 19 matching lines...) Expand all Loading... |
49 size_t SumAllSizes(const AllocationRegister& reg) { | 52 size_t SumAllSizes(const AllocationRegister& reg) { |
50 size_t sum = 0; | 53 size_t sum = 0; |
51 | 54 |
52 for (auto i : reg) | 55 for (auto i : reg) |
53 sum += i.size; | 56 sum += i.size; |
54 | 57 |
55 return sum; | 58 return sum; |
56 } | 59 } |
57 | 60 |
58 TEST_F(AllocationRegisterTest, InsertRemove) { | 61 TEST_F(AllocationRegisterTest, InsertRemove) { |
59 AllocationRegister reg; | 62 AllocationRegister reg(kNumCellsForTesting); |
60 AllocationContext ctx; | 63 AllocationContext ctx; |
61 | 64 |
62 // Zero-sized allocations should be discarded. | 65 // Zero-sized allocations should be discarded. |
63 reg.Insert(reinterpret_cast<void*>(1), 0, ctx); | 66 reg.Insert(reinterpret_cast<void*>(1), 0, ctx); |
64 | 67 |
65 EXPECT_EQ(0u, OrAllAddresses(reg)); | 68 EXPECT_EQ(0u, OrAllAddresses(reg)); |
66 | 69 |
67 reg.Insert(reinterpret_cast<void*>(1), 1, ctx); | 70 reg.Insert(reinterpret_cast<void*>(1), 1, ctx); |
68 | 71 |
69 EXPECT_EQ(1u, OrAllAddresses(reg)); | 72 EXPECT_EQ(1u, OrAllAddresses(reg)); |
(...skipping 13 matching lines...) Expand all Loading... |
83 reg.Remove(reinterpret_cast<void*>(4)); | 86 reg.Remove(reinterpret_cast<void*>(4)); |
84 | 87 |
85 EXPECT_EQ(1u, OrAllAddresses(reg)); | 88 EXPECT_EQ(1u, OrAllAddresses(reg)); |
86 | 89 |
87 reg.Remove(reinterpret_cast<void*>(1)); | 90 reg.Remove(reinterpret_cast<void*>(1)); |
88 | 91 |
89 EXPECT_EQ(0u, OrAllAddresses(reg)); | 92 EXPECT_EQ(0u, OrAllAddresses(reg)); |
90 } | 93 } |
91 | 94 |
92 TEST_F(AllocationRegisterTest, DoubleFreeIsAllowed) { | 95 TEST_F(AllocationRegisterTest, DoubleFreeIsAllowed) { |
93 AllocationRegister reg; | 96 AllocationRegister reg(kNumCellsForTesting); |
94 AllocationContext ctx; | 97 AllocationContext ctx; |
95 | 98 |
96 reg.Insert(reinterpret_cast<void*>(1), 1, ctx); | 99 reg.Insert(reinterpret_cast<void*>(1), 1, ctx); |
97 reg.Insert(reinterpret_cast<void*>(2), 1, ctx); | 100 reg.Insert(reinterpret_cast<void*>(2), 1, ctx); |
98 reg.Remove(reinterpret_cast<void*>(1)); | 101 reg.Remove(reinterpret_cast<void*>(1)); |
99 reg.Remove(reinterpret_cast<void*>(1)); // Remove for the second time. | 102 reg.Remove(reinterpret_cast<void*>(1)); // Remove for the second time. |
100 reg.Remove(reinterpret_cast<void*>(4)); // Remove never inserted address. | 103 reg.Remove(reinterpret_cast<void*>(4)); // Remove never inserted address. |
101 | 104 |
102 EXPECT_EQ(2u, OrAllAddresses(reg)); | 105 EXPECT_EQ(2u, OrAllAddresses(reg)); |
103 } | 106 } |
104 | 107 |
105 TEST_F(AllocationRegisterTest, DoubleInsertOverwrites) { | 108 TEST_F(AllocationRegisterTest, DoubleInsertOverwrites) { |
106 // TODO(ruuda): Although double insert happens in practice, it should not. | 109 AllocationRegister reg(kNumCellsForTesting); |
107 // Find out the cause and ban double insert if possible. | |
108 AllocationRegister reg; | |
109 AllocationContext ctx; | 110 AllocationContext ctx; |
110 StackFrame frame1 = StackFrame::FromTraceEventName("Foo"); | 111 StackFrame frame1 = StackFrame::FromTraceEventName("Foo"); |
111 StackFrame frame2 = StackFrame::FromTraceEventName("Bar"); | 112 StackFrame frame2 = StackFrame::FromTraceEventName("Bar"); |
112 | 113 |
113 ctx.backtrace.frame_count = 1; | 114 ctx.backtrace.frame_count = 1; |
114 | 115 |
115 ctx.backtrace.frames[0] = frame1; | 116 ctx.backtrace.frames[0] = frame1; |
116 reg.Insert(reinterpret_cast<void*>(1), 11, ctx); | 117 reg.Insert(reinterpret_cast<void*>(1), 11, ctx); |
117 | 118 |
118 { | 119 { |
(...skipping 13 matching lines...) Expand all Loading... |
132 EXPECT_EQ(frame2, elem.context.backtrace.frames[0]); | 133 EXPECT_EQ(frame2, elem.context.backtrace.frames[0]); |
133 EXPECT_EQ(13u, elem.size); | 134 EXPECT_EQ(13u, elem.size); |
134 EXPECT_EQ(reinterpret_cast<void*>(1), elem.address); | 135 EXPECT_EQ(reinterpret_cast<void*>(1), elem.address); |
135 } | 136 } |
136 } | 137 } |
137 | 138 |
138 // Check that even if more entries than the number of buckets are inserted, the | 139 // Check that even if more entries than the number of buckets are inserted, the |
139 // register still behaves correctly. | 140 // register still behaves correctly. |
140 TEST_F(AllocationRegisterTest, InsertRemoveCollisions) { | 141 TEST_F(AllocationRegisterTest, InsertRemoveCollisions) { |
141 size_t expected_sum = 0; | 142 size_t expected_sum = 0; |
142 AllocationRegister reg; | 143 AllocationRegister reg(kNumCellsForTesting); |
143 AllocationContext ctx; | 144 AllocationContext ctx; |
144 | 145 |
145 // By inserting 100 more entries than the number of buckets, there will be at | 146 // By inserting 100 more entries than the number of buckets, there will be at |
146 // least 100 collisions. | 147 // least 100 collisions (100 = kNumCellsForTesting - kNumBuckets). |
147 for (uintptr_t i = 1; i <= kNumBuckets + 100; i++) { | 148 for (uintptr_t i = 1; i <= kNumCellsForTesting; i++) { |
148 size_t size = i % 31; | 149 size_t size = i % 31; |
149 expected_sum += size; | 150 expected_sum += size; |
150 reg.Insert(reinterpret_cast<void*>(i), size, ctx); | 151 reg.Insert(reinterpret_cast<void*>(i), size, ctx); |
151 | 152 |
152 // Don't check the sum on every iteration to keep the test fast. | 153 // Don't check the sum on every iteration to keep the test fast. |
153 if (i % (1 << 14) == 0) | 154 if (i % (1 << 14) == 0) |
154 EXPECT_EQ(expected_sum, SumAllSizes(reg)); | 155 EXPECT_EQ(expected_sum, SumAllSizes(reg)); |
155 } | 156 } |
156 | 157 |
157 EXPECT_EQ(expected_sum, SumAllSizes(reg)); | 158 EXPECT_EQ(expected_sum, SumAllSizes(reg)); |
158 | 159 |
159 for (uintptr_t i = 1; i <= kNumBuckets + 100; i++) { | 160 for (uintptr_t i = 1; i <= kNumCellsForTesting; i++) { |
160 size_t size = i % 31; | 161 size_t size = i % 31; |
161 expected_sum -= size; | 162 expected_sum -= size; |
162 reg.Remove(reinterpret_cast<void*>(i)); | 163 reg.Remove(reinterpret_cast<void*>(i)); |
163 | 164 |
164 if (i % (1 << 14) == 0) | 165 if (i % (1 << 14) == 0) |
165 EXPECT_EQ(expected_sum, SumAllSizes(reg)); | 166 EXPECT_EQ(expected_sum, SumAllSizes(reg)); |
166 } | 167 } |
167 | 168 |
168 EXPECT_EQ(expected_sum, SumAllSizes(reg)); | 169 EXPECT_EQ(expected_sum, SumAllSizes(reg)); |
169 } | 170 } |
170 | 171 |
171 // The previous tests are not particularly good for testing iterators, because | 172 // The previous tests are not particularly good for testing iterators, because |
172 // elements are removed and inserted in the same order, meaning that the cells | 173 // elements are removed and inserted in the same order, meaning that the cells |
173 // fill up from low to high index, and are then freed from low to high index. | 174 // fill up from low to high index, and are then freed from low to high index. |
174 // This test removes entries in a different order, to ensure that the iterator | 175 // This test removes entries in a different order, to ensure that the iterator |
175 // skips over the freed cells properly. Then insert again to ensure that the | 176 // skips over the freed cells properly. Then insert again to ensure that the |
176 // free list is utilised properly. | 177 // free list is utilised properly. |
177 TEST_F(AllocationRegisterTest, InsertRemoveRandomOrder) { | 178 TEST_F(AllocationRegisterTest, InsertRemoveRandomOrder) { |
178 size_t expected_sum = 0; | 179 size_t expected_sum = 0; |
179 AllocationRegister reg; | 180 AllocationRegister reg(kNumCellsForTesting); |
180 AllocationContext ctx; | 181 AllocationContext ctx; |
181 | 182 |
182 uintptr_t generator = 3; | 183 uintptr_t generator = 3; |
183 uintptr_t prime = 1013; | 184 uintptr_t prime = 1013; |
184 uint32_t initial_water_mark = GetHighWaterMark(reg); | 185 uint32_t initial_water_mark = GetHighWaterMark(reg); |
185 | 186 |
186 for (uintptr_t i = 2; i < prime; i++) { | 187 for (uintptr_t i = 2; i < prime; i++) { |
187 size_t size = i % 31 + 1; | 188 size_t size = i % 31 + 1; |
188 expected_sum += size; | 189 expected_sum += size; |
189 reg.Insert(reinterpret_cast<void*>(i), size, ctx); | 190 reg.Insert(reinterpret_cast<void*>(i), size, ctx); |
(...skipping 20 matching lines...) Expand all Loading... |
210 ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_water_mark); | 211 ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_water_mark); |
211 | 212 |
212 // Inserting one more entry should use a fresh cell again. | 213 // Inserting one more entry should use a fresh cell again. |
213 reg.Insert(reinterpret_cast<void*>(prime), 1, ctx); | 214 reg.Insert(reinterpret_cast<void*>(prime), 1, ctx); |
214 ASSERT_EQ(prime - 1, GetHighWaterMark(reg) - initial_water_mark); | 215 ASSERT_EQ(prime - 1, GetHighWaterMark(reg) - initial_water_mark); |
215 } | 216 } |
216 | 217 |
217 TEST_F(AllocationRegisterTest, ChangeContextAfterInsertion) { | 218 TEST_F(AllocationRegisterTest, ChangeContextAfterInsertion) { |
218 using Allocation = AllocationRegister::Allocation; | 219 using Allocation = AllocationRegister::Allocation; |
219 const char kStdString[] = "std::string"; | 220 const char kStdString[] = "std::string"; |
220 AllocationRegister reg; | 221 AllocationRegister reg(kNumCellsForTesting); |
221 AllocationContext ctx; | 222 AllocationContext ctx; |
222 | 223 |
223 reg.Insert(reinterpret_cast<void*>(17), 1, ctx); | 224 reg.Insert(reinterpret_cast<void*>(17), 1, ctx); |
224 reg.Insert(reinterpret_cast<void*>(19), 2, ctx); | 225 reg.Insert(reinterpret_cast<void*>(19), 2, ctx); |
225 reg.Insert(reinterpret_cast<void*>(23), 3, ctx); | 226 reg.Insert(reinterpret_cast<void*>(23), 3, ctx); |
226 | 227 |
227 // Looking up addresses that were not inserted should return null. | 228 // Looking up addresses that were not inserted should return null. |
228 // A null pointer lookup is a valid thing to do. | 229 // A null pointer lookup is a valid thing to do. |
229 EXPECT_EQ(nullptr, reg.Get(nullptr)); | 230 EXPECT_EQ(nullptr, reg.Get(nullptr)); |
230 EXPECT_EQ(nullptr, reg.Get(reinterpret_cast<void*>(13))); | 231 EXPECT_EQ(nullptr, reg.Get(reinterpret_cast<void*>(13))); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 const size_t cells_per_page = GetNumCellsPerPage(); | 283 const size_t cells_per_page = GetNumCellsPerPage(); |
283 | 284 |
284 ASSERT_DEATH(for (size_t j = 0; j < cells_per_page; j++) { | 285 ASSERT_DEATH(for (size_t j = 0; j < cells_per_page; j++) { |
285 reg.Insert(reinterpret_cast<void*>(i + j), 1, ctx); | 286 reg.Insert(reinterpret_cast<void*>(i + j), 1, ctx); |
286 }, ""); | 287 }, ""); |
287 } | 288 } |
288 #endif | 289 #endif |
289 | 290 |
290 } // namespace trace_event | 291 } // namespace trace_event |
291 } // namespace base | 292 } // namespace base |
OLD | NEW |