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> 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 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: 57 void SetUp() override { 58 TraceConfig config(""); 59 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE); 60 AllocationContextTracker::SetCaptureEnabled(true); 61 } 62 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. 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. 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 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 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