| 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 |