Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: base/trace_event/memory_profiler_allocation_register_unittest.cc

Issue 1371053002: [Tracing] Add allocation register for heap profiling (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@backtrace
Patch Set: _linux -> _posix Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/trace_event/memory_profiler_allocation_register.h"
6
7 #include "base/process/process_metrics.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 namespace base {
11 namespace trace_event {
12
13 class AllocationRegisterTest : public testing::Test {
14 public:
15 // Returns the number of cells that the |AllocationlessHashTable| in the
16 // |AllocationRegister| can store per system page.
17 size_t GetNumCellsPerPage() {
18 return GetPageSize() / sizeof(AllocationRegister::Cell);
19 }
20
21 uint32_t GetTableSize(const AllocationRegister& reg) {
Primiano Tucci (use gerrit) 2015/10/06 13:34:45 Uh? Aren't this static constants. How is this diff
Ruud van Asseldonk 2015/10/06 15:44:35 Done.
22 return reg.kNumBuckets;
23 }
24
25 uint32_t GetNumCells(const AllocationRegister& reg) { return reg.kNumCells; }
Primiano Tucci (use gerrit) 2015/10/06 13:34:45 ditto here
Ruud van Asseldonk 2015/10/06 15:44:35 Done.
26
27 uint32_t GetHighWaterMark(const AllocationRegister& reg) {
28 return reg.next_unused_cell_;
29 }
30 };
31
32 // Iterates over all entries in the allocation register and returns the bitwise
33 // or of all addresses stored in it.
34 uintptr_t OrAllAddresses(const AllocationRegister& reg) {
35 uintptr_t acc = 0;
36
37 for (auto i : reg)
38 acc |= reinterpret_cast<uintptr_t>(i.address);
39
40 return acc;
41 }
42
43 // Iterates over all entries in the allocation register and returns the sum of
44 // the sizes of the entries.
45 size_t SumAllSizes(const AllocationRegister& reg) {
46 size_t sum = 0;
47
48 for (auto i : reg)
49 sum += i.size;
50
51 return sum;
52 }
53
54 TEST_F(AllocationRegisterTest, InsertRemoveKeys) {
55 AllocationRegister reg;
56 AllocationContext ctx;
57
58 EXPECT_EQ(0u, OrAllAddresses(reg));
59
60 reg.Insert(reinterpret_cast<void*>(1), 0, ctx);
61
62 EXPECT_EQ(1u, OrAllAddresses(reg));
63
64 reg.Insert(reinterpret_cast<void*>(2), 0, ctx);
65
66 EXPECT_EQ(3u, OrAllAddresses(reg));
67
68 reg.Insert(reinterpret_cast<void*>(4), 0, ctx);
69
70 EXPECT_EQ(7u, OrAllAddresses(reg));
71
72 reg.Remove(reinterpret_cast<void*>(2));
73
74 EXPECT_EQ(5u, OrAllAddresses(reg));
75
76 reg.Remove(reinterpret_cast<void*>(4));
77
78 EXPECT_EQ(1u, OrAllAddresses(reg));
79
80 reg.Remove(reinterpret_cast<void*>(1));
81
82 EXPECT_EQ(0u, OrAllAddresses(reg));
83 }
84
85 TEST_F(AllocationRegisterTest, DoubleFreeIsAllowed) {
86 AllocationRegister reg;
87 AllocationContext ctx;
88
89 reg.Insert(reinterpret_cast<void*>(1), 0, ctx);
90 reg.Insert(reinterpret_cast<void*>(2), 0, ctx);
91 reg.Remove(reinterpret_cast<void*>(1));
92 reg.Remove(reinterpret_cast<void*>(1)); // Remove for the second time.
93 reg.Remove(reinterpret_cast<void*>(4)); // Remove never inserted address.
94
95 EXPECT_EQ(2u, OrAllAddresses(reg));
96 }
97
98 TEST_F(AllocationRegisterTest, DoubleInsertOverwrites) {
99 // TODO(ruuda): Although double insert happens in practice, it should not.
100 // Find out the cause and ban double insert if possible.
101 AllocationRegister reg;
102 AllocationContext ctx;
103 StackFrame frame1 = "Foo";
104 StackFrame frame2 = "Bar";
105
106 ctx.backtrace.frames[0] = frame1;
107 reg.Insert(reinterpret_cast<void*>(1), 11, ctx);
108
109 auto elem = *reg.begin();
110
111 EXPECT_EQ(frame1, elem.context.backtrace.frames[0]);
112 EXPECT_EQ(11u, elem.size);
113 EXPECT_EQ(reinterpret_cast<void*>(1), elem.address);
114
115 ctx.backtrace.frames[0] = frame2;
116 reg.Insert(reinterpret_cast<void*>(1), 13, ctx);
117
118 elem = *reg.begin();
119
120 EXPECT_EQ(frame2, elem.context.backtrace.frames[0]);
121 EXPECT_EQ(13u, elem.size);
122 EXPECT_EQ(reinterpret_cast<void*>(1), elem.address);
123 }
124
125 // Check that even if more entries than the table size are inserted, the
126 // register still behaves correctly.
127 TEST_F(AllocationRegisterTest, InsertRemoveCollisions) {
128 size_t expected_sum = 0;
129 AllocationRegister reg;
130 AllocationContext ctx;
131
132 // By inserting 100 more entries than the table size, there will be at least
133 // 100 collisions.
134 for (uintptr_t i = 1; i <= GetTableSize(reg) + 100; i++) {
135 size_t size = i % 31;
136 expected_sum += size;
137 reg.Insert(reinterpret_cast<void*>(i), size, ctx);
138
139 // Don't check the sum on every iteration to keep the test fast.
140 if (i % (1 << 14) == 0)
141 EXPECT_EQ(expected_sum, SumAllSizes(reg));
142 }
143
144 EXPECT_EQ(expected_sum, SumAllSizes(reg));
145
146 for (uintptr_t i = 1; i <= GetTableSize(reg) + 100; i++) {
147 size_t size = i % 31;
148 expected_sum -= size;
149 reg.Remove(reinterpret_cast<void*>(i));
150
151 if (i % (1 << 14) == 0)
152 EXPECT_EQ(expected_sum, SumAllSizes(reg));
153 }
154
155 EXPECT_EQ(expected_sum, SumAllSizes(reg));
156 }
157
158 // The previous tests are not particularly good for testing iterators, because
159 // elements are removed and inserted in the same order, meaning that the cells
160 // fill up from low to high index, and are then freed from low to high index.
161 // This test removes entries in a different order, to ensure that the iterator
162 // skips over the freed cells properly. Then insert again to ensure that the
163 // free list is utilised properly.
164 TEST_F(AllocationRegisterTest, InsertRemoveRandomOrder) {
165 size_t expected_sum = 0;
166 AllocationRegister reg;
167 AllocationContext ctx;
168
169 uintptr_t generator = 3;
170 uintptr_t prime = 1013;
171 uint32_t initial_used = GetHighWaterMark(reg);
172
173 for (uintptr_t i = 2; i < prime; i++) {
174 size_t size = i % 31;
175 expected_sum += size;
176 reg.Insert(reinterpret_cast<void*>(i), size, ctx);
177 }
178
179 // This should have used a fresh slot for each of the |prime - 2| inserts.
180 ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_used);
181
182 // Iterate the numbers 2, 3, ..., prime - 1 in pseudorandom order.
183 for (uintptr_t i = generator; i != 1; i = (i * generator) % prime) {
184 size_t size = i % 31;
185 expected_sum -= size;
186 reg.Remove(reinterpret_cast<void*>(i));
187 EXPECT_EQ(expected_sum, SumAllSizes(reg));
188 }
189
190 ASSERT_EQ(0u, expected_sum);
191
192 // Insert |prime - 2| entries again. This should use cells from the free list,
193 // so the |next_unused_cell_| index should not change.
194 for (uintptr_t i = 2; i < prime; i++)
195 reg.Insert(reinterpret_cast<void*>(i), 0, ctx);
196
197 ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_used);
198
199 // Inserting one more entry should use a fresh cell again.
200 reg.Insert(reinterpret_cast<void*>(prime), 0, ctx);
201 ASSERT_EQ(prime - 1, GetHighWaterMark(reg) - initial_used);
202 }
203
204 // Check that the process aborts due to hitting the guard page when inserting
205 // too many elements.
206 TEST_F(AllocationRegisterTest, OverflowDeathTest) {
Primiano Tucci (use gerrit) 2015/10/06 13:34:44 Hmm how long does it take to run this test? Having
Ruud van Asseldonk 2015/10/06 15:44:35 It is pretty heavy (~400 ms on my machine), but I
207 AllocationRegister reg;
208 AllocationContext ctx;
209 uintptr_t i;
210
211 // Fill up all of the memory allocated for the register. |GetNumCells(reg)|
212 // minus 1 elements are inserted, because cell 0 is unused, so this should
213 // fill up the available cells exactly.
214 for (i = 1; i < GetNumCells(reg); i++) {
215 reg.Insert(reinterpret_cast<void*>(i), 0, ctx);
216 }
217
218 // Adding just one extra element might still work because the allocated memory
219 // is rounded up to the page size. Adding a page full of elements should cause
220 // overflow.
221 const size_t cells_per_page = GetNumCellsPerPage();
222
223 ASSERT_DEATH(for (size_t j = 0; j < cells_per_page; j++) {
224 reg.Insert(reinterpret_cast<void*>(i + j), 0, ctx);
225 }, "");
226 }
227
228 } // namespace trace_event
229 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698