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 <stddef.h> | 5 #include <stddef.h> |
6 | 6 |
7 #include <iterator> | 7 #include <iterator> |
8 | 8 |
9 #include "base/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
10 #include "base/pending_task.h" | 10 #include "base/pending_task.h" |
11 #include "base/trace_event/heap_profiler.h" | 11 #include "base/trace_event/heap_profiler.h" |
12 #include "base/trace_event/heap_profiler_allocation_context.h" | 12 #include "base/trace_event/heap_profiler_allocation_context.h" |
13 #include "base/trace_event/heap_profiler_allocation_context_tracker.h" | 13 #include "base/trace_event/heap_profiler_allocation_context_tracker.h" |
14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
16 | 16 |
17 namespace base { | 17 namespace base { |
18 namespace trace_event { | 18 namespace trace_event { |
19 | 19 |
20 // Define all strings once, because the pseudo stack requires pointer equality, | 20 // Define all strings once, because the pseudo stack requires pointer equality, |
21 // and string interning is unreliable. | 21 // and string interning is unreliable. |
| 22 const char kThreadName[] = "TestThread"; |
22 const char kCupcake[] = "Cupcake"; | 23 const char kCupcake[] = "Cupcake"; |
23 const char kDonut[] = "Donut"; | 24 const char kDonut[] = "Donut"; |
24 const char kEclair[] = "Eclair"; | 25 const char kEclair[] = "Eclair"; |
25 const char kFroyo[] = "Froyo"; | 26 const char kFroyo[] = "Froyo"; |
26 const char kGingerbread[] = "Gingerbread"; | 27 const char kGingerbread[] = "Gingerbread"; |
27 | 28 |
28 // Asserts that the fixed-size array |expected_backtrace| matches the backtrace | 29 // Asserts that the fixed-size array |expected_backtrace| matches the backtrace |
29 // in |AllocationContextTracker::GetContextSnapshot|. | 30 // in |AllocationContextTracker::GetContextSnapshot|. |
30 template <size_t N> | 31 template <size_t N> |
31 void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) { | 32 void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) { |
(...skipping 10 matching lines...) Expand all Loading... |
42 // string comparison. | 43 // string comparison. |
43 for (; actual != actual_bottom && expected != expected_bottom; | 44 for (; actual != actual_bottom && expected != expected_bottom; |
44 actual++, expected++) | 45 actual++, expected++) |
45 ASSERT_EQ(*expected, *actual); | 46 ASSERT_EQ(*expected, *actual); |
46 | 47 |
47 // Ensure that the height of the stacks is the same. | 48 // Ensure that the height of the stacks is the same. |
48 ASSERT_EQ(actual, actual_bottom); | 49 ASSERT_EQ(actual, actual_bottom); |
49 ASSERT_EQ(expected, expected_bottom); | 50 ASSERT_EQ(expected, expected_bottom); |
50 } | 51 } |
51 | 52 |
52 void AssertBacktraceEmpty() { | 53 void AssertBacktraceContainsOnlyThreadName() { |
| 54 StackFrame t = StackFrame::FromThreadName(kThreadName); |
53 AllocationContext ctx = | 55 AllocationContext ctx = |
54 AllocationContextTracker::GetInstanceForCurrentThread() | 56 AllocationContextTracker::GetInstanceForCurrentThread() |
55 ->GetContextSnapshot(); | 57 ->GetContextSnapshot(); |
56 | 58 |
57 ASSERT_EQ(0u, ctx.backtrace.frame_count); | 59 ASSERT_EQ(1u, ctx.backtrace.frame_count); |
| 60 ASSERT_EQ(t, ctx.backtrace.frames[0]); |
58 } | 61 } |
59 | 62 |
60 class AllocationContextTrackerTest : public testing::Test { | 63 class AllocationContextTrackerTest : public testing::Test { |
61 public: | 64 public: |
62 void SetUp() override { | 65 void SetUp() override { |
63 TraceConfig config(""); | 66 TraceConfig config(""); |
64 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE); | 67 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE); |
65 AllocationContextTracker::SetCaptureMode( | 68 AllocationContextTracker::SetCaptureMode( |
66 AllocationContextTracker::CaptureMode::PSEUDO_STACK); | 69 AllocationContextTracker::CaptureMode::PSEUDO_STACK); |
| 70 AllocationContextTracker::SetCurrentThreadName(kThreadName); |
67 } | 71 } |
68 | 72 |
69 void TearDown() override { | 73 void TearDown() override { |
70 AllocationContextTracker::SetCaptureMode( | 74 AllocationContextTracker::SetCaptureMode( |
71 AllocationContextTracker::CaptureMode::DISABLED); | 75 AllocationContextTracker::CaptureMode::DISABLED); |
72 TraceLog::GetInstance()->SetDisabled(); | 76 TraceLog::GetInstance()->SetDisabled(); |
73 } | 77 } |
74 }; | 78 }; |
75 | 79 |
76 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly. | 80 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly. |
77 TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) { | 81 TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) { |
| 82 StackFrame t = StackFrame::FromThreadName(kThreadName); |
78 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | 83 StackFrame c = StackFrame::FromTraceEventName(kCupcake); |
79 StackFrame d = StackFrame::FromTraceEventName(kDonut); | 84 StackFrame d = StackFrame::FromTraceEventName(kDonut); |
80 StackFrame e = StackFrame::FromTraceEventName(kEclair); | 85 StackFrame e = StackFrame::FromTraceEventName(kEclair); |
81 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | 86 StackFrame f = StackFrame::FromTraceEventName(kFroyo); |
82 | 87 |
83 AssertBacktraceEmpty(); | 88 AssertBacktraceContainsOnlyThreadName(); |
84 | 89 |
85 { | 90 { |
86 TRACE_EVENT0("Testing", kCupcake); | 91 TRACE_EVENT0("Testing", kCupcake); |
87 StackFrame frame_c[] = {c}; | 92 StackFrame frame_c[] = {t, c}; |
88 AssertBacktraceEquals(frame_c); | 93 AssertBacktraceEquals(frame_c); |
89 | 94 |
90 { | 95 { |
91 TRACE_EVENT0("Testing", kDonut); | 96 TRACE_EVENT0("Testing", kDonut); |
92 StackFrame frame_cd[] = {c, d}; | 97 StackFrame frame_cd[] = {t, c, d}; |
93 AssertBacktraceEquals(frame_cd); | 98 AssertBacktraceEquals(frame_cd); |
94 } | 99 } |
95 | 100 |
96 AssertBacktraceEquals(frame_c); | 101 AssertBacktraceEquals(frame_c); |
97 | 102 |
98 { | 103 { |
99 TRACE_EVENT0("Testing", kEclair); | 104 TRACE_EVENT0("Testing", kEclair); |
100 StackFrame frame_ce[] = {c, e}; | 105 StackFrame frame_ce[] = {t, c, e}; |
101 AssertBacktraceEquals(frame_ce); | 106 AssertBacktraceEquals(frame_ce); |
102 } | 107 } |
103 | 108 |
104 AssertBacktraceEquals(frame_c); | 109 AssertBacktraceEquals(frame_c); |
105 } | 110 } |
106 | 111 |
107 AssertBacktraceEmpty(); | 112 AssertBacktraceContainsOnlyThreadName(); |
108 | 113 |
109 { | 114 { |
110 TRACE_EVENT0("Testing", kFroyo); | 115 TRACE_EVENT0("Testing", kFroyo); |
111 StackFrame frame_f[] = {f}; | 116 StackFrame frame_f[] = {t, f}; |
112 AssertBacktraceEquals(frame_f); | 117 AssertBacktraceEquals(frame_f); |
113 } | 118 } |
114 | 119 |
115 AssertBacktraceEmpty(); | 120 AssertBacktraceContainsOnlyThreadName(); |
116 } | 121 } |
117 | 122 |
118 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and | 123 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and |
119 // |TRACE_EVENT_END| macros. | 124 // |TRACE_EVENT_END| macros. |
120 TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) { | 125 TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) { |
| 126 StackFrame t = StackFrame::FromThreadName(kThreadName); |
121 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | 127 StackFrame c = StackFrame::FromTraceEventName(kCupcake); |
122 StackFrame d = StackFrame::FromTraceEventName(kDonut); | 128 StackFrame d = StackFrame::FromTraceEventName(kDonut); |
123 StackFrame e = StackFrame::FromTraceEventName(kEclair); | 129 StackFrame e = StackFrame::FromTraceEventName(kEclair); |
124 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | 130 StackFrame f = StackFrame::FromTraceEventName(kFroyo); |
125 | 131 |
126 StackFrame frame_c[] = {c}; | 132 StackFrame frame_c[] = {t, c}; |
127 StackFrame frame_cd[] = {c, d}; | 133 StackFrame frame_cd[] = {t, c, d}; |
128 StackFrame frame_ce[] = {c, e}; | 134 StackFrame frame_ce[] = {t, c, e}; |
129 StackFrame frame_f[] = {f}; | 135 StackFrame frame_f[] = {t, f}; |
130 | 136 |
131 AssertBacktraceEmpty(); | 137 AssertBacktraceContainsOnlyThreadName(); |
132 | 138 |
133 TRACE_EVENT_BEGIN0("Testing", kCupcake); | 139 TRACE_EVENT_BEGIN0("Testing", kCupcake); |
134 AssertBacktraceEquals(frame_c); | 140 AssertBacktraceEquals(frame_c); |
135 | 141 |
136 TRACE_EVENT_BEGIN0("Testing", kDonut); | 142 TRACE_EVENT_BEGIN0("Testing", kDonut); |
137 AssertBacktraceEquals(frame_cd); | 143 AssertBacktraceEquals(frame_cd); |
138 TRACE_EVENT_END0("Testing", kDonut); | 144 TRACE_EVENT_END0("Testing", kDonut); |
139 | 145 |
140 AssertBacktraceEquals(frame_c); | 146 AssertBacktraceEquals(frame_c); |
141 | 147 |
142 TRACE_EVENT_BEGIN0("Testing", kEclair); | 148 TRACE_EVENT_BEGIN0("Testing", kEclair); |
143 AssertBacktraceEquals(frame_ce); | 149 AssertBacktraceEquals(frame_ce); |
144 TRACE_EVENT_END0("Testing", kEclair); | 150 TRACE_EVENT_END0("Testing", kEclair); |
145 | 151 |
146 AssertBacktraceEquals(frame_c); | 152 AssertBacktraceEquals(frame_c); |
147 TRACE_EVENT_END0("Testing", kCupcake); | 153 TRACE_EVENT_END0("Testing", kCupcake); |
148 | 154 |
149 AssertBacktraceEmpty(); | 155 AssertBacktraceContainsOnlyThreadName(); |
150 | 156 |
151 TRACE_EVENT_BEGIN0("Testing", kFroyo); | 157 TRACE_EVENT_BEGIN0("Testing", kFroyo); |
152 AssertBacktraceEquals(frame_f); | 158 AssertBacktraceEquals(frame_f); |
153 TRACE_EVENT_END0("Testing", kFroyo); | 159 TRACE_EVENT_END0("Testing", kFroyo); |
154 | 160 |
155 AssertBacktraceEmpty(); | 161 AssertBacktraceContainsOnlyThreadName(); |
156 } | 162 } |
157 | 163 |
158 TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) { | 164 TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) { |
| 165 StackFrame t = StackFrame::FromThreadName(kThreadName); |
159 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | 166 StackFrame c = StackFrame::FromTraceEventName(kCupcake); |
160 StackFrame d = StackFrame::FromTraceEventName(kDonut); | 167 StackFrame d = StackFrame::FromTraceEventName(kDonut); |
161 StackFrame e = StackFrame::FromTraceEventName(kEclair); | 168 StackFrame e = StackFrame::FromTraceEventName(kEclair); |
162 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | 169 StackFrame f = StackFrame::FromTraceEventName(kFroyo); |
163 | 170 |
164 StackFrame frame_c[] = {c}; | 171 StackFrame frame_c[] = {t, c}; |
165 StackFrame frame_cd[] = {c, d}; | 172 StackFrame frame_cd[] = {t, c, d}; |
166 StackFrame frame_e[] = {e}; | 173 StackFrame frame_e[] = {t, e}; |
167 StackFrame frame_ef[] = {e, f}; | 174 StackFrame frame_ef[] = {t, e, f}; |
168 | 175 |
169 AssertBacktraceEmpty(); | 176 AssertBacktraceContainsOnlyThreadName(); |
170 | 177 |
171 TRACE_EVENT_BEGIN0("Testing", kCupcake); | 178 TRACE_EVENT_BEGIN0("Testing", kCupcake); |
172 AssertBacktraceEquals(frame_c); | 179 AssertBacktraceEquals(frame_c); |
173 | 180 |
174 { | 181 { |
175 TRACE_EVENT0("Testing", kDonut); | 182 TRACE_EVENT0("Testing", kDonut); |
176 AssertBacktraceEquals(frame_cd); | 183 AssertBacktraceEquals(frame_cd); |
177 } | 184 } |
178 | 185 |
179 AssertBacktraceEquals(frame_c); | 186 AssertBacktraceEquals(frame_c); |
180 TRACE_EVENT_END0("Testing", kCupcake); | 187 TRACE_EVENT_END0("Testing", kCupcake); |
181 AssertBacktraceEmpty(); | 188 AssertBacktraceContainsOnlyThreadName(); |
182 | 189 |
183 { | 190 { |
184 TRACE_EVENT0("Testing", kEclair); | 191 TRACE_EVENT0("Testing", kEclair); |
185 AssertBacktraceEquals(frame_e); | 192 AssertBacktraceEquals(frame_e); |
186 | 193 |
187 TRACE_EVENT_BEGIN0("Testing", kFroyo); | 194 TRACE_EVENT_BEGIN0("Testing", kFroyo); |
188 AssertBacktraceEquals(frame_ef); | 195 AssertBacktraceEquals(frame_ef); |
189 TRACE_EVENT_END0("Testing", kFroyo); | 196 TRACE_EVENT_END0("Testing", kFroyo); |
190 AssertBacktraceEquals(frame_e); | 197 AssertBacktraceEquals(frame_e); |
191 } | 198 } |
192 | 199 |
193 AssertBacktraceEmpty(); | 200 AssertBacktraceContainsOnlyThreadName(); |
194 } | 201 } |
195 | 202 |
196 TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) { | 203 TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) { |
| 204 StackFrame t = StackFrame::FromThreadName(kThreadName); |
197 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | 205 StackFrame c = StackFrame::FromTraceEventName(kCupcake); |
198 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | 206 StackFrame f = StackFrame::FromTraceEventName(kFroyo); |
199 | 207 |
200 // Push 12 events onto the pseudo stack. | 208 // Push 11 events onto the pseudo stack. |
201 TRACE_EVENT0("Testing", kCupcake); | 209 TRACE_EVENT0("Testing", kCupcake); |
202 TRACE_EVENT0("Testing", kCupcake); | 210 TRACE_EVENT0("Testing", kCupcake); |
203 TRACE_EVENT0("Testing", kCupcake); | 211 TRACE_EVENT0("Testing", kCupcake); |
204 TRACE_EVENT0("Testing", kCupcake); | |
205 | 212 |
206 TRACE_EVENT0("Testing", kCupcake); | 213 TRACE_EVENT0("Testing", kCupcake); |
207 TRACE_EVENT0("Testing", kCupcake); | 214 TRACE_EVENT0("Testing", kCupcake); |
208 TRACE_EVENT0("Testing", kCupcake); | 215 TRACE_EVENT0("Testing", kCupcake); |
209 TRACE_EVENT0("Testing", kCupcake); | 216 TRACE_EVENT0("Testing", kCupcake); |
210 | 217 |
211 TRACE_EVENT0("Testing", kCupcake); | 218 TRACE_EVENT0("Testing", kCupcake); |
212 TRACE_EVENT0("Testing", kDonut); | 219 TRACE_EVENT0("Testing", kDonut); |
213 TRACE_EVENT0("Testing", kEclair); | 220 TRACE_EVENT0("Testing", kEclair); |
214 TRACE_EVENT0("Testing", kFroyo); | 221 TRACE_EVENT0("Testing", kFroyo); |
215 | 222 |
216 { | 223 { |
217 TRACE_EVENT0("Testing", kGingerbread); | 224 TRACE_EVENT0("Testing", kGingerbread); |
218 AllocationContext ctx = | 225 AllocationContext ctx = |
219 AllocationContextTracker::GetInstanceForCurrentThread() | 226 AllocationContextTracker::GetInstanceForCurrentThread() |
220 ->GetContextSnapshot(); | 227 ->GetContextSnapshot(); |
221 | 228 |
222 // The pseudo stack relies on pointer equality, not deep string comparisons. | 229 // The pseudo stack relies on pointer equality, not deep string comparisons. |
223 ASSERT_EQ(c, ctx.backtrace.frames[0]); | 230 ASSERT_EQ(t, ctx.backtrace.frames[0]); |
| 231 ASSERT_EQ(c, ctx.backtrace.frames[1]); |
224 ASSERT_EQ(f, ctx.backtrace.frames[11]); | 232 ASSERT_EQ(f, ctx.backtrace.frames[11]); |
225 } | 233 } |
226 | 234 |
227 { | 235 { |
228 AllocationContext ctx = | 236 AllocationContext ctx = |
229 AllocationContextTracker::GetInstanceForCurrentThread() | 237 AllocationContextTracker::GetInstanceForCurrentThread() |
230 ->GetContextSnapshot(); | 238 ->GetContextSnapshot(); |
231 ASSERT_EQ(c, ctx.backtrace.frames[0]); | 239 ASSERT_EQ(t, ctx.backtrace.frames[0]); |
| 240 ASSERT_EQ(c, ctx.backtrace.frames[1]); |
232 ASSERT_EQ(f, ctx.backtrace.frames[11]); | 241 ASSERT_EQ(f, ctx.backtrace.frames[11]); |
233 } | 242 } |
234 } | 243 } |
235 | 244 |
236 TEST_F(AllocationContextTrackerTest, SetCurrentThreadName) { | |
237 TRACE_EVENT0("Testing", kCupcake); | |
238 | |
239 // Test if the thread name is inserted into backtrace. | |
240 const char kThread1[] = "thread1"; | |
241 AllocationContextTracker::SetCurrentThreadName(kThread1); | |
242 AllocationContext ctx1 = | |
243 AllocationContextTracker::GetInstanceForCurrentThread() | |
244 ->GetContextSnapshot(); | |
245 ASSERT_EQ(StackFrame::FromThreadName(kThread1), ctx1.backtrace.frames[0]); | |
246 ASSERT_EQ(StackFrame::FromTraceEventName(kCupcake), ctx1.backtrace.frames[1]); | |
247 | |
248 // Test if the thread name is reset. | |
249 const char kThread2[] = "thread2"; | |
250 AllocationContextTracker::SetCurrentThreadName(kThread2); | |
251 AllocationContext ctx2 = | |
252 AllocationContextTracker::GetInstanceForCurrentThread() | |
253 ->GetContextSnapshot(); | |
254 ASSERT_EQ(StackFrame::FromThreadName(kThread2), ctx2.backtrace.frames[0]); | |
255 ASSERT_EQ(StackFrame::FromTraceEventName(kCupcake), ctx2.backtrace.frames[1]); | |
256 } | |
257 | |
258 TEST_F(AllocationContextTrackerTest, TrackTaskContext) { | 245 TEST_F(AllocationContextTrackerTest, TrackTaskContext) { |
259 const char kContext1[] = "context1"; | 246 const char kContext1[] = "context1"; |
260 const char kContext2[] = "context2"; | 247 const char kContext2[] = "context2"; |
261 { | 248 { |
262 // The context from the scoped task event should be used as type name. | 249 // The context from the scoped task event should be used as type name. |
263 TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event1(kContext1); | 250 TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event1(kContext1); |
264 AllocationContext ctx1 = | 251 AllocationContext ctx1 = |
265 AllocationContextTracker::GetInstanceForCurrentThread() | 252 AllocationContextTracker::GetInstanceForCurrentThread() |
266 ->GetContextSnapshot(); | 253 ->GetContextSnapshot(); |
267 ASSERT_EQ(kContext1, ctx1.type_name); | 254 ASSERT_EQ(kContext1, ctx1.type_name); |
(...skipping 21 matching lines...) Expand all Loading... |
289 AllocationContextTracker::GetInstanceForCurrentThread() | 276 AllocationContextTracker::GetInstanceForCurrentThread() |
290 ->GetContextSnapshot(); | 277 ->GetContextSnapshot(); |
291 const StringPiece kTracingOverhead("tracing_overhead"); | 278 const StringPiece kTracingOverhead("tracing_overhead"); |
292 ASSERT_EQ(kTracingOverhead, | 279 ASSERT_EQ(kTracingOverhead, |
293 static_cast<const char*>(ctx.backtrace.frames[0].value)); | 280 static_cast<const char*>(ctx.backtrace.frames[0].value)); |
294 ASSERT_EQ(1u, ctx.backtrace.frame_count); | 281 ASSERT_EQ(1u, ctx.backtrace.frame_count); |
295 } | 282 } |
296 | 283 |
297 } // namespace trace_event | 284 } // namespace trace_event |
298 } // namespace base | 285 } // namespace base |
OLD | NEW |