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/trace_event/heap_profiler_allocation_context.h"
11 #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
12 #include "base/trace_event/trace_event.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16 namespace trace_event {
17
18 // Define all strings once, because the pseudo stack requires pointer equality,
19 // and string interning is unreliable.
20 const char kCupcake[] = "Cupcake";
21 const char kDonut[] = "Donut";
22 const char kEclair[] = "Eclair";
23 const char kFroyo[] = "Froyo";
24 const char kGingerbread[] = "Gingerbread";
25
26 // Asserts that the fixed-size array |expected_backtrace| matches the backtrace
27 // in |AllocationContextTracker::GetContextSnapshot|.
28 template <size_t N>
AssertBacktraceEquals(const StackFrame (& expected_backtrace)[N])29 void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
30 AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
31
32 auto actual = std::begin(ctx.backtrace.frames);
33 auto actual_bottom = std::end(ctx.backtrace.frames);
34 auto expected = std::begin(expected_backtrace);
35 auto expected_bottom = std::end(expected_backtrace);
36
37 // Note that this requires the pointers to be equal, this is not doing a deep
38 // string comparison.
39 for (; actual != actual_bottom && expected != expected_bottom;
40 actual++, expected++)
41 ASSERT_EQ(*expected, *actual);
42
43 // Ensure that the height of the stacks is the same.
44 ASSERT_EQ(actual, actual_bottom);
45 ASSERT_EQ(expected, expected_bottom);
46 }
47
AssertBacktraceEmpty()48 void AssertBacktraceEmpty() {
49 AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
50
51 for (StackFrame frame : ctx.backtrace.frames)
52 ASSERT_EQ(nullptr, frame);
53 }
54
55 class AllocationContextTrackerTest : public testing::Test {
56 public:
SetUp()57 void SetUp() override {
58 TraceConfig config("");
59 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE);
60 AllocationContextTracker::SetCaptureEnabled(true);
61 }
62
TearDown()63 void TearDown() override {
64 AllocationContextTracker::SetCaptureEnabled(false);
65 TraceLog::GetInstance()->SetDisabled();
66 }
67 };
68
69 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
70 // Also check that |GetContextSnapshot| fills the backtrace with null pointers
71 // when the pseudo stack height is less than the capacity.
TEST_F(AllocationContextTrackerTest,PseudoStackScopedTrace)72 TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
73 StackFrame c = kCupcake;
74 StackFrame d = kDonut;
75 StackFrame e = kEclair;
76 StackFrame f = kFroyo;
77
78 AssertBacktraceEmpty();
79
80 {
81 TRACE_EVENT0("Testing", kCupcake);
82 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
83 AssertBacktraceEquals(frame_c);
84
85 {
86 TRACE_EVENT0("Testing", kDonut);
87 StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
88 AssertBacktraceEquals(frame_cd);
89 }
90
91 AssertBacktraceEquals(frame_c);
92
93 {
94 TRACE_EVENT0("Testing", kEclair);
95 StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
96 AssertBacktraceEquals(frame_ce);
97 }
98
99 AssertBacktraceEquals(frame_c);
100 }
101
102 AssertBacktraceEmpty();
103
104 {
105 TRACE_EVENT0("Testing", kFroyo);
106 StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
107 AssertBacktraceEquals(frame_f);
108 }
109
110 AssertBacktraceEmpty();
111 }
112
113 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
114 // |TRACE_EVENT_END| macros.
TEST_F(AllocationContextTrackerTest,PseudoStackBeginEndTrace)115 TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
116 StackFrame c = kCupcake;
117 StackFrame d = kDonut;
118 StackFrame e = kEclair;
119 StackFrame f = kFroyo;
120
121 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
122 StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
123 StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
124 StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
125
126 AssertBacktraceEmpty();
127
128 TRACE_EVENT_BEGIN0("Testing", kCupcake);
129 AssertBacktraceEquals(frame_c);
130
131 TRACE_EVENT_BEGIN0("Testing", kDonut);
132 AssertBacktraceEquals(frame_cd);
133 TRACE_EVENT_END0("Testing", kDonut);
134
135 AssertBacktraceEquals(frame_c);
136
137 TRACE_EVENT_BEGIN0("Testing", kEclair);
138 AssertBacktraceEquals(frame_ce);
139 TRACE_EVENT_END0("Testing", kEclair);
140
141 AssertBacktraceEquals(frame_c);
142 TRACE_EVENT_END0("Testing", kCupcake);
143
144 AssertBacktraceEmpty();
145
146 TRACE_EVENT_BEGIN0("Testing", kFroyo);
147 AssertBacktraceEquals(frame_f);
148 TRACE_EVENT_END0("Testing", kFroyo);
149
150 AssertBacktraceEmpty();
151 }
152
TEST_F(AllocationContextTrackerTest,PseudoStackMixedTrace)153 TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
154 StackFrame c = kCupcake;
155 StackFrame d = kDonut;
156 StackFrame e = kEclair;
157 StackFrame f = kFroyo;
158
159 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
160 StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
161 StackFrame frame_e[] = {e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
162 StackFrame frame_ef[] = {e, f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
163
164 AssertBacktraceEmpty();
165
166 TRACE_EVENT_BEGIN0("Testing", kCupcake);
167 AssertBacktraceEquals(frame_c);
168
169 {
170 TRACE_EVENT0("Testing", kDonut);
171 AssertBacktraceEquals(frame_cd);
172 }
173
174 AssertBacktraceEquals(frame_c);
175 TRACE_EVENT_END0("Testing", kCupcake);
176 AssertBacktraceEmpty();
177
178 {
179 TRACE_EVENT0("Testing", kEclair);
180 AssertBacktraceEquals(frame_e);
181
182 TRACE_EVENT_BEGIN0("Testing", kFroyo);
183 AssertBacktraceEquals(frame_ef);
184 TRACE_EVENT_END0("Testing", kFroyo);
185 AssertBacktraceEquals(frame_e);
186 }
187
188 AssertBacktraceEmpty();
189 }
190
TEST_F(AllocationContextTrackerTest,BacktraceTakesTop)191 TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
192 // Push 12 events onto the pseudo stack.
193 TRACE_EVENT0("Testing", kCupcake);
194 TRACE_EVENT0("Testing", kCupcake);
195 TRACE_EVENT0("Testing", kCupcake);
196 TRACE_EVENT0("Testing", kCupcake);
197
198 TRACE_EVENT0("Testing", kCupcake);
199 TRACE_EVENT0("Testing", kCupcake);
200 TRACE_EVENT0("Testing", kCupcake);
201 TRACE_EVENT0("Testing", kCupcake);
202
203 TRACE_EVENT0("Testing", kCupcake);
204 TRACE_EVENT0("Testing", kDonut);
205 TRACE_EVENT0("Testing", kEclair);
206 TRACE_EVENT0("Testing", kFroyo);
207
208 {
209 TRACE_EVENT0("Testing", kGingerbread);
210 AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
211
212 // The pseudo stack relies on pointer equality, not deep string comparisons.
213 ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
214 ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
215 }
216
217 {
218 AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
219 ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
220 ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
221 }
222 }
223
224 } // namespace trace_event
225 } // namespace base
226