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_stack_frame_deduplicator.h" | 5 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h" |
6 | 6 |
7 #include <iterator> | 7 #include <iterator> |
8 #include <memory> | 8 #include <memory> |
9 | 9 |
10 #include "base/macros.h" | 10 #include "base/macros.h" |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 StackFrame null_bt[] = {kNull}; | 99 StackFrame null_bt[] = {kNull}; |
100 | 100 |
101 // Empty backtraces (begin == end) are mapped to an implicitly added | 101 // Empty backtraces (begin == end) are mapped to an implicitly added |
102 // node #0. However, backtrace with a single null frame is not empty, | 102 // node #0. However, backtrace with a single null frame is not empty, |
103 // and should be mapped to some other id. | 103 // and should be mapped to some other id. |
104 | 104 |
105 StringDeduplicator string_dedup; | 105 StringDeduplicator string_dedup; |
106 StackFrameDeduplicator dedup(&string_dedup); | 106 StackFrameDeduplicator dedup(&string_dedup); |
107 | 107 |
108 // Node #0 is added implicitly and corresponds to an empty backtrace. | 108 // Node #0 is added implicitly and corresponds to an empty backtrace. |
109 ASSERT_EQ(dedup.begin() + 1, dedup.end()); | 109 ASSERT_TRUE(dedup.begin() + 1 == dedup.end()); |
110 ASSERT_EQ(0, dedup.Insert(std::begin(null_bt), std::begin(null_bt))); | 110 ASSERT_EQ(0, dedup.Insert(std::begin(null_bt), std::begin(null_bt))); |
111 | 111 |
112 // Placeholder entry for ID 0 is a frame with NULL name and no parent. | 112 // Placeholder entry for ID 0 is a frame with NULL name and no parent. |
113 // However inserting such a frame should yield a different ID. | 113 // However inserting such a frame should yield a different ID. |
114 ExpectIncrementalEntries(&dedup, &string_dedup, {{0, kNull}}); | 114 ExpectIncrementalEntries(&dedup, &string_dedup, {{0, kNull}}); |
115 ASSERT_EQ(1, dedup.Insert(std::begin(null_bt), std::end(null_bt))); | 115 ASSERT_EQ(1, dedup.Insert(std::begin(null_bt), std::end(null_bt))); |
116 } | 116 } |
117 | 117 |
118 TEST(StackFrameDeduplicatorTest, SingleBacktrace) { | 118 TEST(StackFrameDeduplicatorTest, SingleBacktrace) { |
119 StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc}; | 119 StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc}; |
(...skipping 11 matching lines...) Expand all Loading... |
131 auto iter = dedup.begin() + 1; // skip implicit node #0 | 131 auto iter = dedup.begin() + 1; // skip implicit node #0 |
132 ASSERT_EQ(kBrowserMain, (iter + 0)->frame); | 132 ASSERT_EQ(kBrowserMain, (iter + 0)->frame); |
133 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index); | 133 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index); |
134 | 134 |
135 ASSERT_EQ(kCreateWidget, (iter + 1)->frame); | 135 ASSERT_EQ(kCreateWidget, (iter + 1)->frame); |
136 ASSERT_EQ(1, (iter + 1)->parent_frame_index); | 136 ASSERT_EQ(1, (iter + 1)->parent_frame_index); |
137 | 137 |
138 ASSERT_EQ(kMalloc, (iter + 2)->frame); | 138 ASSERT_EQ(kMalloc, (iter + 2)->frame); |
139 ASSERT_EQ(2, (iter + 2)->parent_frame_index); | 139 ASSERT_EQ(2, (iter + 2)->parent_frame_index); |
140 | 140 |
141 ASSERT_EQ(iter + 3, dedup.end()); | 141 ASSERT_TRUE(iter + 3 == dedup.end()); |
142 } | 142 } |
143 | 143 |
144 TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) { | 144 TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) { |
145 StackFrame null_frame = StackFrame::FromTraceEventName(nullptr); | 145 StackFrame null_frame = StackFrame::FromTraceEventName(nullptr); |
146 StackFrame bt[] = {kBrowserMain, null_frame, kMalloc}; | 146 StackFrame bt[] = {kBrowserMain, null_frame, kMalloc}; |
147 | 147 |
148 // Deduplicator doesn't care about what's inside StackFrames, | 148 // Deduplicator doesn't care about what's inside StackFrames, |
149 // and handles nullptr StackFrame values as any other. | 149 // and handles nullptr StackFrame values as any other. |
150 // | 150 // |
151 // So the call tree should look like this (index in brackets). | 151 // So the call tree should look like this (index in brackets). |
152 // | 152 // |
153 // BrowserMain [1] | 153 // BrowserMain [1] |
154 // (null) [2] | 154 // (null) [2] |
155 // malloc [3] | 155 // malloc [3] |
156 | 156 |
157 StringDeduplicator string_dedup; | 157 StringDeduplicator string_dedup; |
158 StackFrameDeduplicator dedup(&string_dedup); | 158 StackFrameDeduplicator dedup(&string_dedup); |
159 ASSERT_EQ(3, dedup.Insert(std::begin(bt), std::end(bt))); | 159 ASSERT_EQ(3, dedup.Insert(std::begin(bt), std::end(bt))); |
160 | 160 |
161 auto iter = dedup.begin() + 1; // skip implicit node #0 | 161 auto iter = dedup.begin() + 1; // skip implicit node #0 |
162 ASSERT_EQ(kBrowserMain, (iter + 0)->frame); | 162 ASSERT_EQ(kBrowserMain, (iter + 0)->frame); |
163 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index); | 163 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index); |
164 | 164 |
165 ASSERT_EQ(null_frame, (iter + 1)->frame); | 165 ASSERT_EQ(null_frame, (iter + 1)->frame); |
166 ASSERT_EQ(1, (iter + 1)->parent_frame_index); | 166 ASSERT_EQ(1, (iter + 1)->parent_frame_index); |
167 | 167 |
168 ASSERT_EQ(kMalloc, (iter + 2)->frame); | 168 ASSERT_EQ(kMalloc, (iter + 2)->frame); |
169 ASSERT_EQ(2, (iter + 2)->parent_frame_index); | 169 ASSERT_EQ(2, (iter + 2)->parent_frame_index); |
170 | 170 |
171 ASSERT_EQ(iter + 3, dedup.end()); | 171 ASSERT_TRUE(iter + 3 == dedup.end()); |
172 } | 172 } |
173 | 173 |
174 // Test that there can be different call trees (there can be multiple bottom | 174 // Test that there can be different call trees (there can be multiple bottom |
175 // frames). Also verify that frames with the same name but a different caller | 175 // frames). Also verify that frames with the same name but a different caller |
176 // are represented as distinct nodes. | 176 // are represented as distinct nodes. |
177 TEST(StackFrameDeduplicatorTest, MultipleRoots) { | 177 TEST(StackFrameDeduplicatorTest, MultipleRoots) { |
178 StackFrame bt0[] = {kBrowserMain, kCreateWidget}; | 178 StackFrame bt0[] = {kBrowserMain, kCreateWidget}; |
179 StackFrame bt1[] = {kRendererMain, kCreateWidget}; | 179 StackFrame bt1[] = {kRendererMain, kCreateWidget}; |
180 | 180 |
181 // The call tree should look like this (index in brackets). | 181 // The call tree should look like this (index in brackets). |
(...skipping 17 matching lines...) Expand all Loading... |
199 | 199 |
200 ASSERT_EQ(kCreateWidget, (iter + 1)->frame); | 200 ASSERT_EQ(kCreateWidget, (iter + 1)->frame); |
201 ASSERT_EQ(1, (iter + 1)->parent_frame_index); | 201 ASSERT_EQ(1, (iter + 1)->parent_frame_index); |
202 | 202 |
203 ASSERT_EQ(kRendererMain, (iter + 2)->frame); | 203 ASSERT_EQ(kRendererMain, (iter + 2)->frame); |
204 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 2)->parent_frame_index); | 204 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 2)->parent_frame_index); |
205 | 205 |
206 ASSERT_EQ(kCreateWidget, (iter + 3)->frame); | 206 ASSERT_EQ(kCreateWidget, (iter + 3)->frame); |
207 ASSERT_EQ(3, (iter + 3)->parent_frame_index); | 207 ASSERT_EQ(3, (iter + 3)->parent_frame_index); |
208 | 208 |
209 ASSERT_EQ(iter + 4, dedup.end()); | 209 ASSERT_TRUE(iter + 4 == dedup.end()); |
210 } | 210 } |
211 | 211 |
212 TEST(StackFrameDeduplicatorTest, Deduplication) { | 212 TEST(StackFrameDeduplicatorTest, Deduplication) { |
213 StackFrame bt0[] = {kBrowserMain, kCreateWidget}; | 213 StackFrame bt0[] = {kBrowserMain, kCreateWidget}; |
214 StackFrame bt1[] = {kBrowserMain, kInitialize}; | 214 StackFrame bt1[] = {kBrowserMain, kInitialize}; |
215 | 215 |
216 // The call tree should look like this (index in brackets). | 216 // The call tree should look like this (index in brackets). |
217 // | 217 // |
218 // BrowserMain [1] | 218 // BrowserMain [1] |
219 // CreateWidget [2] | 219 // CreateWidget [2] |
220 // Initialize [3] | 220 // Initialize [3] |
221 // | 221 // |
222 // Note that BrowserMain will be re-used. | 222 // Note that BrowserMain will be re-used. |
223 | 223 |
224 StringDeduplicator string_dedup; | 224 StringDeduplicator string_dedup; |
225 StackFrameDeduplicator dedup(&string_dedup); | 225 StackFrameDeduplicator dedup(&string_dedup); |
226 ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0))); | 226 ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0))); |
227 ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1))); | 227 ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1))); |
228 | 228 |
229 auto iter = dedup.begin() + 1; // skip implicit node #0 | 229 auto iter = dedup.begin() + 1; // skip implicit node #0 |
230 ASSERT_EQ(kBrowserMain, (iter + 0)->frame); | 230 ASSERT_EQ(kBrowserMain, (iter + 0)->frame); |
231 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index); | 231 ASSERT_EQ(kInvalidStackFrameIndex, (iter + 0)->parent_frame_index); |
232 | 232 |
233 ASSERT_EQ(kCreateWidget, (iter + 1)->frame); | 233 ASSERT_EQ(kCreateWidget, (iter + 1)->frame); |
234 ASSERT_EQ(1, (iter + 1)->parent_frame_index); | 234 ASSERT_EQ(1, (iter + 1)->parent_frame_index); |
235 | 235 |
236 ASSERT_EQ(kInitialize, (iter + 2)->frame); | 236 ASSERT_EQ(kInitialize, (iter + 2)->frame); |
237 ASSERT_EQ(1, (iter + 2)->parent_frame_index); | 237 ASSERT_EQ(1, (iter + 2)->parent_frame_index); |
238 | 238 |
239 ASSERT_EQ(iter + 3, dedup.end()); | 239 ASSERT_TRUE(iter + 3 == dedup.end()); |
240 | 240 |
241 // Inserting the same backtrace again should return the index of the existing | 241 // Inserting the same backtrace again should return the index of the existing |
242 // node. | 242 // node. |
243 ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0))); | 243 ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0))); |
244 ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1))); | 244 ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1))); |
245 ASSERT_EQ(4 /* 1 implicit + 3 added */, dedup.end() - dedup.begin()); | 245 ASSERT_EQ(4 /* 1 implicit + 3 added */, dedup.end() - dedup.begin()); |
246 } | 246 } |
247 | 247 |
248 TEST(StackFrameDeduplicatorTest, SerializeIncrementally) { | 248 TEST(StackFrameDeduplicatorTest, SerializeIncrementally) { |
249 StringDeduplicator string_dedup; | 249 StringDeduplicator string_dedup; |
250 StackFrameDeduplicator dedup(&string_dedup); | 250 StackFrameDeduplicator dedup(&string_dedup); |
251 | 251 |
252 StackFrame bt0[] = {kBrowserMain, kCreateWidget}; | 252 StackFrame bt0[] = {kBrowserMain, kCreateWidget}; |
253 ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0))); | 253 ASSERT_EQ(2, dedup.Insert(std::begin(bt0), std::end(bt0))); |
254 | 254 |
255 ExpectIncrementalEntries( | 255 ExpectIncrementalEntries( |
256 &dedup, &string_dedup, | 256 &dedup, &string_dedup, |
257 {{0, kNull}, {1, kBrowserMain}, {2, kCreateWidget, 1}}); | 257 {{0, kNull}, {1, kBrowserMain}, {2, kCreateWidget, 1}}); |
258 | 258 |
259 StackFrame bt1[] = {kBrowserMain, kInitialize}; | 259 StackFrame bt1[] = {kBrowserMain, kInitialize}; |
260 ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1))); | 260 ASSERT_EQ(3, dedup.Insert(std::begin(bt1), std::end(bt1))); |
261 | 261 |
262 ExpectIncrementalEntries(&dedup, &string_dedup, {{3, kInitialize, 1}}); | 262 ExpectIncrementalEntries(&dedup, &string_dedup, {{3, kInitialize, 1}}); |
263 | 263 |
264 ExpectIncrementalEntries(&dedup, &string_dedup, {}); | 264 ExpectIncrementalEntries(&dedup, &string_dedup, {}); |
265 } | 265 } |
266 | 266 |
267 } // namespace trace_event | 267 } // namespace trace_event |
268 } // namespace base | 268 } // namespace base |
OLD | NEW |