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 <stddef.h>
6
7 #include <iterator>
8
9 #include "base/memory/ref_counted.h"
10 #include "base/pending_task.h"
11 #include "base/strings/string_piece.h"
12 #include "base/trace_event/heap_profiler.h"
13 #include "base/trace_event/heap_profiler_allocation_context.h"
14 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
15 #include "base/trace_event/memory_dump_manager.h"
16 #include "base/trace_event/trace_event.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace base {
20 namespace trace_event {
21
22 // Define all strings once, because the pseudo stack requires pointer equality,
23 // and string interning is unreliable.
24 const char kThreadName[] = "TestThread";
25 const char kCupcake[] = "Cupcake";
26 const char kDonut[] = "Donut";
27 const char kEclair[] = "Eclair";
28 const char kFroyo[] = "Froyo";
29 const char kGingerbread[] = "Gingerbread";
30
31 const char kFilteringTraceConfig[] =
32 "{"
33 " \"event_filters\": ["
34 " {"
35 " \"excluded_categories\": [],"
36 " \"filter_args\": {},"
37 " \"filter_predicate\": \"heap_profiler_predicate\","
38 " \"included_categories\": ["
39 " \"*\","
40 " \"" TRACE_DISABLED_BY_DEFAULT("Testing") "\"]"
41 " }"
42 " ]"
43 "}";
44
45 // Asserts that the fixed-size array |expected_backtrace| matches the backtrace
46 // in |AllocationContextTracker::GetContextSnapshot|.
47 template <size_t N>
AssertBacktraceEquals(const StackFrame (& expected_backtrace)[N])48 void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
49 AllocationContext ctx;
50 ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
51 ->GetContextSnapshot(&ctx));
52
53 auto* actual = std::begin(ctx.backtrace.frames);
54 auto* actual_bottom = actual + ctx.backtrace.frame_count;
55 auto expected = std::begin(expected_backtrace);
56 auto expected_bottom = std::end(expected_backtrace);
57
58 // Note that this requires the pointers to be equal, this is not doing a deep
59 // string comparison.
60 for (; actual != actual_bottom && expected != expected_bottom;
61 actual++, expected++)
62 ASSERT_EQ(*expected, *actual);
63
64 // Ensure that the height of the stacks is the same.
65 ASSERT_EQ(actual, actual_bottom);
66 ASSERT_EQ(expected, expected_bottom);
67 }
68
AssertBacktraceContainsOnlyThreadName()69 void AssertBacktraceContainsOnlyThreadName() {
70 StackFrame t = StackFrame::FromThreadName(kThreadName);
71 AllocationContext ctx;
72 ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
73 ->GetContextSnapshot(&ctx));
74
75 ASSERT_EQ(1u, ctx.backtrace.frame_count);
76 ASSERT_EQ(t, ctx.backtrace.frames[0]);
77 }
78
79 class AllocationContextTrackerTest : public testing::Test {
80 public:
SetUp()81 void SetUp() override {
82 AllocationContextTracker::SetCaptureMode(
83 AllocationContextTracker::CaptureMode::PSEUDO_STACK);
84 // Enabling memory-infra category sets default memory dump config which
85 // includes filters for capturing pseudo stack.
86 TraceConfig config(kFilteringTraceConfig);
87 TraceLog::GetInstance()->SetEnabled(config, TraceLog::FILTERING_MODE);
88 AllocationContextTracker::SetCurrentThreadName(kThreadName);
89 }
90
TearDown()91 void TearDown() override {
92 AllocationContextTracker::SetCaptureMode(
93 AllocationContextTracker::CaptureMode::DISABLED);
94 TraceLog::GetInstance()->SetDisabled(TraceLog::FILTERING_MODE);
95 }
96 };
97
98 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
TEST_F(AllocationContextTrackerTest,PseudoStackScopedTrace)99 TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
100 StackFrame t = StackFrame::FromThreadName(kThreadName);
101 StackFrame c = StackFrame::FromTraceEventName(kCupcake);
102 StackFrame d = StackFrame::FromTraceEventName(kDonut);
103 StackFrame e = StackFrame::FromTraceEventName(kEclair);
104 StackFrame f = StackFrame::FromTraceEventName(kFroyo);
105
106 AssertBacktraceContainsOnlyThreadName();
107
108 {
109 TRACE_EVENT0("Testing", kCupcake);
110 StackFrame frame_c[] = {t, c};
111 AssertBacktraceEquals(frame_c);
112
113 {
114 TRACE_EVENT0("Testing", kDonut);
115 StackFrame frame_cd[] = {t, c, d};
116 AssertBacktraceEquals(frame_cd);
117 }
118
119 AssertBacktraceEquals(frame_c);
120
121 {
122 TRACE_EVENT0("Testing", kEclair);
123 StackFrame frame_ce[] = {t, c, e};
124 AssertBacktraceEquals(frame_ce);
125 }
126
127 {
128 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("NotTesting"), kDonut);
129 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("Testing"), kCupcake);
130 StackFrame frame_cc[] = {t, c, c};
131 AssertBacktraceEquals(frame_cc);
132 }
133
134 AssertBacktraceEquals(frame_c);
135 }
136
137 AssertBacktraceContainsOnlyThreadName();
138
139 {
140 TRACE_EVENT0("Testing", kFroyo);
141 StackFrame frame_f[] = {t, f};
142 AssertBacktraceEquals(frame_f);
143 }
144
145 AssertBacktraceContainsOnlyThreadName();
146 }
147
148 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
149 // |TRACE_EVENT_END| macros.
TEST_F(AllocationContextTrackerTest,PseudoStackBeginEndTrace)150 TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
151 StackFrame t = StackFrame::FromThreadName(kThreadName);
152 StackFrame c = StackFrame::FromTraceEventName(kCupcake);
153 StackFrame d = StackFrame::FromTraceEventName(kDonut);
154 StackFrame e = StackFrame::FromTraceEventName(kEclair);
155 StackFrame f = StackFrame::FromTraceEventName(kFroyo);
156
157 StackFrame frame_c[] = {t, c};
158 StackFrame frame_cd[] = {t, c, d};
159 StackFrame frame_ce[] = {t, c, e};
160 StackFrame frame_f[] = {t, f};
161
162 AssertBacktraceContainsOnlyThreadName();
163
164 TRACE_EVENT_BEGIN0("Testing", kCupcake);
165 AssertBacktraceEquals(frame_c);
166
167 TRACE_EVENT_BEGIN0("Testing", kDonut);
168 AssertBacktraceEquals(frame_cd);
169 TRACE_EVENT_END0("Testing", kDonut);
170
171 AssertBacktraceEquals(frame_c);
172
173 TRACE_EVENT_BEGIN0("Testing", kEclair);
174 AssertBacktraceEquals(frame_ce);
175 TRACE_EVENT_END0("Testing", kEclair);
176
177 AssertBacktraceEquals(frame_c);
178 TRACE_EVENT_END0("Testing", kCupcake);
179
180 AssertBacktraceContainsOnlyThreadName();
181
182 TRACE_EVENT_BEGIN0("Testing", kFroyo);
183 AssertBacktraceEquals(frame_f);
184 TRACE_EVENT_END0("Testing", kFroyo);
185
186 AssertBacktraceContainsOnlyThreadName();
187 }
188
TEST_F(AllocationContextTrackerTest,PseudoStackMixedTrace)189 TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
190 StackFrame t = StackFrame::FromThreadName(kThreadName);
191 StackFrame c = StackFrame::FromTraceEventName(kCupcake);
192 StackFrame d = StackFrame::FromTraceEventName(kDonut);
193 StackFrame e = StackFrame::FromTraceEventName(kEclair);
194 StackFrame f = StackFrame::FromTraceEventName(kFroyo);
195
196 StackFrame frame_c[] = {t, c};
197 StackFrame frame_cd[] = {t, c, d};
198 StackFrame frame_e[] = {t, e};
199 StackFrame frame_ef[] = {t, e, f};
200
201 AssertBacktraceContainsOnlyThreadName();
202
203 TRACE_EVENT_BEGIN0("Testing", kCupcake);
204 AssertBacktraceEquals(frame_c);
205
206 {
207 TRACE_EVENT0("Testing", kDonut);
208 AssertBacktraceEquals(frame_cd);
209 }
210
211 AssertBacktraceEquals(frame_c);
212 TRACE_EVENT_END0("Testing", kCupcake);
213 AssertBacktraceContainsOnlyThreadName();
214
215 {
216 TRACE_EVENT0("Testing", kEclair);
217 AssertBacktraceEquals(frame_e);
218
219 TRACE_EVENT_BEGIN0("Testing", kFroyo);
220 AssertBacktraceEquals(frame_ef);
221 TRACE_EVENT_END0("Testing", kFroyo);
222 AssertBacktraceEquals(frame_e);
223 }
224
225 AssertBacktraceContainsOnlyThreadName();
226 }
227
TEST_F(AllocationContextTrackerTest,MixedStackWithProgramCounter)228 TEST_F(AllocationContextTrackerTest, MixedStackWithProgramCounter) {
229 StackFrame t = StackFrame::FromThreadName(kThreadName);
230 StackFrame c = StackFrame::FromTraceEventName(kCupcake);
231 StackFrame f = StackFrame::FromTraceEventName(kFroyo);
232 const void* pc1 = reinterpret_cast<void*>(0x1000);
233 const void* pc2 = reinterpret_cast<void*>(0x2000);
234 StackFrame n1 = StackFrame::FromProgramCounter(pc1);
235 StackFrame n2 = StackFrame::FromProgramCounter(pc2);
236
237 StackFrame frame_c[] = {t, c};
238 StackFrame frame_cd[] = {t, c, n1};
239 StackFrame frame_e[] = {t, n2, n1};
240 StackFrame frame_ef[] = {t, n2, n1, f};
241
242 AssertBacktraceContainsOnlyThreadName();
243
244 AllocationContextTracker::SetCaptureMode(
245 AllocationContextTracker::CaptureMode::MIXED_STACK);
246
247 TRACE_EVENT_BEGIN0("Testing", kCupcake);
248 AssertBacktraceEquals(frame_c);
249
250 {
251 TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER e1(pc1);
252 AssertBacktraceEquals(frame_cd);
253 }
254
255 AssertBacktraceEquals(frame_c);
256 TRACE_EVENT_END0("Testing", kCupcake);
257 AssertBacktraceContainsOnlyThreadName();
258
259 {
260 TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER e1(pc2);
261 TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER e2(pc1);
262 AssertBacktraceEquals(frame_e);
263
264 TRACE_EVENT0("Testing", kFroyo);
265 AssertBacktraceEquals(frame_ef);
266 }
267
268 AssertBacktraceContainsOnlyThreadName();
269 AllocationContextTracker::SetCaptureMode(
270 AllocationContextTracker::CaptureMode::DISABLED);
271 }
272
TEST_F(AllocationContextTrackerTest,BacktraceTakesTop)273 TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
274 StackFrame t = StackFrame::FromThreadName(kThreadName);
275 StackFrame c = StackFrame::FromTraceEventName(kCupcake);
276 StackFrame f = StackFrame::FromTraceEventName(kFroyo);
277
278 // Push 11 events onto the pseudo stack.
279 TRACE_EVENT0("Testing", kCupcake);
280 TRACE_EVENT0("Testing", kCupcake);
281 TRACE_EVENT0("Testing", kCupcake);
282
283 TRACE_EVENT0("Testing", kCupcake);
284 TRACE_EVENT0("Testing", kCupcake);
285 TRACE_EVENT0("Testing", kCupcake);
286 TRACE_EVENT0("Testing", kCupcake);
287
288 TRACE_EVENT0("Testing", kCupcake);
289 TRACE_EVENT0("Testing", kDonut);
290 TRACE_EVENT0("Testing", kEclair);
291 TRACE_EVENT0("Testing", kFroyo);
292
293 {
294 TRACE_EVENT0("Testing", kGingerbread);
295 AllocationContext ctx;
296 ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
297 ->GetContextSnapshot(&ctx));
298
299 // The pseudo stack relies on pointer equality, not deep string comparisons.
300 ASSERT_EQ(t, ctx.backtrace.frames[0]);
301 ASSERT_EQ(c, ctx.backtrace.frames[1]);
302 ASSERT_EQ(f, ctx.backtrace.frames[11]);
303 }
304
305 {
306 AllocationContext ctx;
307 ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
308 ->GetContextSnapshot(&ctx));
309 ASSERT_EQ(t, ctx.backtrace.frames[0]);
310 ASSERT_EQ(c, ctx.backtrace.frames[1]);
311 ASSERT_EQ(f, ctx.backtrace.frames[11]);
312 }
313 }
314
TEST_F(AllocationContextTrackerTest,TrackCategoryName)315 TEST_F(AllocationContextTrackerTest, TrackCategoryName) {
316 const char kContext1[] = "context1";
317 const char kContext2[] = "context2";
318 {
319 // The context from the scoped task event should be used as type name.
320 TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event1(kContext1);
321 AllocationContext ctx1;
322 ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
323 ->GetContextSnapshot(&ctx1));
324 ASSERT_EQ(kContext1, ctx1.type_name);
325
326 // In case of nested events, the last event's context should be used.
327 TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event2(kContext2);
328 AllocationContext ctx2;
329 ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
330 ->GetContextSnapshot(&ctx2));
331 ASSERT_EQ(kContext2, ctx2.type_name);
332 }
333
334 // Type should be nullptr without task event.
335 AllocationContext ctx;
336 ASSERT_TRUE(AllocationContextTracker::GetInstanceForCurrentThread()
337 ->GetContextSnapshot(&ctx));
338 ASSERT_EQ("UntrackedTask", base::StringPiece(ctx.type_name));
339 }
340
TEST_F(AllocationContextTrackerTest,IgnoreAllocationTest)341 TEST_F(AllocationContextTrackerTest, IgnoreAllocationTest) {
342 TRACE_EVENT0("Testing", kCupcake);
343 TRACE_EVENT0("Testing", kDonut);
344 HEAP_PROFILER_SCOPED_IGNORE;
345 AllocationContext ctx;
346 ASSERT_FALSE(AllocationContextTracker::GetInstanceForCurrentThread()
347 ->GetContextSnapshot(&ctx));
348 }
349
350 } // namespace trace_event
351 } // namespace base
352