| 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/memory_profiler_allocation_context.h" | 5 #include "base/trace_event/memory_profiler_allocation_context.h" |
| 6 #include "base/trace_event/trace_event.h" | 6 #include "base/trace_event/trace_event.h" |
| 7 #include "testing/gtest/include/gtest/gtest.h" | 7 #include "testing/gtest/include/gtest/gtest.h" |
| 8 | 8 |
| 9 namespace base { | 9 namespace base { |
| 10 namespace trace_event { | 10 namespace trace_event { |
| 11 | 11 |
| 12 // Asserts that the fixed-size array |expected_stack| matches the pseudo | 12 // Returns a pointer past the end of the fixed-size array |array| of |T| of |
| 13 // stack. Syntax note: |const StackFrame (&expected_stack)[N]| is the syntax | 13 // length |N|, identical to C++11 |std::end|. |
| 14 // for "expected_stack is a reference to a const fixed-size array of StackFrame | 14 template <typename T, int N> |
| 15 // of length N". | 15 const T* End(const T(&array)[N]) { |
| 16 return array + N; |
| 17 } |
| 18 |
| 19 // Asserts that the fixed-size array |expected_backtrace| matches the backtrace |
| 20 // in |AllocationContextTracker::GetContext|. |
| 16 template <size_t N> | 21 template <size_t N> |
| 17 void AssertPseudoStackEquals(const StackFrame (&expected_stack)[N]) { | 22 void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) { |
| 18 auto pseudo_stack = AllocationContextTracker::GetPseudoStackForTesting(); | 23 AllocationContext ctx = AllocationContextTracker::GetContext(); |
| 19 auto actual = pseudo_stack->top(); | 24 |
| 20 auto actual_bottom = pseudo_stack->bottom(); | 25 auto actual = ctx.backtrace; |
| 21 auto expected = expected_stack; | 26 auto actual_bottom = End(ctx.backtrace); |
| 22 auto expected_bottom = expected_stack + N; | 27 auto expected = expected_backtrace; |
| 28 auto expected_bottom = End(expected_backtrace); |
| 23 | 29 |
| 24 for (; actual != actual_bottom && expected != expected_bottom; | 30 for (; actual != actual_bottom && expected != expected_bottom; |
| 25 actual++, expected++) { | 31 actual++, expected++) { |
| 26 ASSERT_STREQ(*expected, *actual); | 32 ASSERT_STREQ(*expected, *actual); |
| 27 } | 33 } |
| 28 | 34 |
| 29 // Ensure that the height of the stacks is the same. | 35 // Ensure that the height of the stacks is the same. |
| 30 ASSERT_EQ(actual, actual_bottom); | 36 ASSERT_EQ(actual, actual_bottom); |
| 31 ASSERT_EQ(expected, expected_bottom); | 37 ASSERT_EQ(expected, expected_bottom); |
| 32 } | 38 } |
| 33 | 39 |
| 34 void AssertPseudoStackEmpty() { | 40 void AssertBacktraceEmpty() { |
| 35 auto pseudo_stack = AllocationContextTracker::GetPseudoStackForTesting(); | 41 AllocationContext ctx = AllocationContextTracker::GetContext(); |
| 36 ASSERT_EQ(pseudo_stack->top(), pseudo_stack->bottom()); | 42 |
| 43 for (StackFrame frame : ctx.backtrace) |
| 44 ASSERT_EQ(nullptr, frame); |
| 37 } | 45 } |
| 38 | 46 |
| 39 class AllocationContextTest : public testing::Test { | 47 class AllocationContextTest : public testing::Test { |
| 40 public: | 48 public: |
| 41 void EnableTracing() { | 49 void SetUp() override { |
| 42 TraceConfig config(""); | 50 TraceConfig config(""); |
| 43 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE); | 51 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE); |
| 44 AllocationContextTracker::SetCaptureEnabled(true); | 52 AllocationContextTracker::SetCaptureEnabled(true); |
| 45 } | 53 } |
| 46 | 54 |
| 47 void DisableTracing() { | 55 void TearDown() override { |
| 48 AllocationContextTracker::SetCaptureEnabled(false); | 56 AllocationContextTracker::SetCaptureEnabled(false); |
| 49 TraceLog::GetInstance()->SetDisabled(); | 57 TraceLog::GetInstance()->SetDisabled(); |
| 50 } | 58 } |
| 51 }; | 59 }; |
| 52 | 60 |
| 61 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly. |
| 62 // Also check that |GetContext| fills the backtrace with null pointers when the |
| 63 // pseudo stack height is less than the capacity. |
| 53 TEST_F(AllocationContextTest, PseudoStackScopedTrace) { | 64 TEST_F(AllocationContextTest, PseudoStackScopedTrace) { |
| 54 StackFrame c = "Cupcake"; | 65 StackFrame c = "Cupcake"; |
| 55 StackFrame d = "Donut"; | 66 StackFrame d = "Donut"; |
| 56 StackFrame e = "Eclair"; | 67 StackFrame e = "Eclair"; |
| 57 StackFrame f = "Froyo"; | 68 StackFrame f = "Froyo"; |
| 58 | 69 |
| 59 EnableTracing(); | 70 AssertBacktraceEmpty(); |
| 60 AssertPseudoStackEmpty(); | |
| 61 | 71 |
| 62 { | 72 { |
| 63 TRACE_EVENT0("Testing", "Cupcake"); | 73 TRACE_EVENT0("Testing", "Cupcake"); |
| 64 StackFrame frame_c[] = {c}; | 74 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0}; |
| 65 AssertPseudoStackEquals(frame_c); | 75 AssertBacktraceEquals(frame_c); |
| 66 | 76 |
| 67 { | 77 { |
| 68 TRACE_EVENT0("Testing", "Donut"); | 78 TRACE_EVENT0("Testing", "Donut"); |
| 69 StackFrame frame_dc[] = {d, c}; | 79 StackFrame frame_dc[] = {d, c, 0, 0, 0, 0, 0, 0}; |
| 70 AssertPseudoStackEquals(frame_dc); | 80 AssertBacktraceEquals(frame_dc); |
| 71 } | 81 } |
| 72 | 82 |
| 73 AssertPseudoStackEquals(frame_c); | 83 AssertBacktraceEquals(frame_c); |
| 74 | 84 |
| 75 { | 85 { |
| 76 TRACE_EVENT0("Testing", "Eclair"); | 86 TRACE_EVENT0("Testing", "Eclair"); |
| 77 StackFrame frame_ec[] = {e, c}; | 87 StackFrame frame_ec[] = {e, c, 0, 0, 0, 0, 0, 0}; |
| 78 AssertPseudoStackEquals(frame_ec); | 88 AssertBacktraceEquals(frame_ec); |
| 79 } | 89 } |
| 80 | 90 |
| 81 AssertPseudoStackEquals(frame_c); | 91 AssertBacktraceEquals(frame_c); |
| 82 } | 92 } |
| 83 | 93 |
| 84 AssertPseudoStackEmpty(); | 94 AssertBacktraceEmpty(); |
| 85 | 95 |
| 86 { | 96 { |
| 87 TRACE_EVENT0("Testing", "Froyo"); | 97 TRACE_EVENT0("Testing", "Froyo"); |
| 88 StackFrame frame_f[] = {f}; | 98 StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0}; |
| 89 AssertPseudoStackEquals(frame_f); | 99 AssertBacktraceEquals(frame_f); |
| 90 } | 100 } |
| 91 | 101 |
| 92 AssertPseudoStackEmpty(); | 102 AssertBacktraceEmpty(); |
| 93 DisableTracing(); | |
| 94 } | 103 } |
| 95 | 104 |
| 105 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and |
| 106 // |TRACE_EVENT_END| macros. |
| 96 TEST_F(AllocationContextTest, PseudoStackBeginEndTrace) { | 107 TEST_F(AllocationContextTest, PseudoStackBeginEndTrace) { |
| 97 StackFrame c = "Cupcake"; | 108 StackFrame c = "Cupcake"; |
| 98 StackFrame d = "Donut"; | 109 StackFrame d = "Donut"; |
| 99 StackFrame e = "Eclair"; | 110 StackFrame e = "Eclair"; |
| 100 StackFrame f = "Froyo"; | 111 StackFrame f = "Froyo"; |
| 101 | 112 |
| 102 StackFrame frame_c[] = {c}; | 113 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0}; |
| 103 StackFrame frame_dc[] = {d, c}; | 114 StackFrame frame_dc[] = {d, c, 0, 0, 0, 0, 0, 0}; |
| 104 StackFrame frame_ec[] = {e, c}; | 115 StackFrame frame_ec[] = {e, c, 0, 0, 0, 0, 0, 0}; |
| 105 StackFrame frame_f[] = {f}; | 116 StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0}; |
| 106 | 117 |
| 107 EnableTracing(); | 118 AssertBacktraceEmpty(); |
| 108 AssertPseudoStackEmpty(); | |
| 109 | 119 |
| 110 TRACE_EVENT_BEGIN0("Testing", "Cupcake"); | 120 TRACE_EVENT_BEGIN0("Testing", "Cupcake"); |
| 111 AssertPseudoStackEquals(frame_c); | 121 AssertBacktraceEquals(frame_c); |
| 112 | 122 |
| 113 TRACE_EVENT_BEGIN0("Testing", "Donut"); | 123 TRACE_EVENT_BEGIN0("Testing", "Donut"); |
| 114 AssertPseudoStackEquals(frame_dc); | 124 AssertBacktraceEquals(frame_dc); |
| 115 TRACE_EVENT_END0("Testing", "Donut"); | 125 TRACE_EVENT_END0("Testing", "Donut"); |
| 116 | 126 |
| 117 AssertPseudoStackEquals(frame_c); | 127 AssertBacktraceEquals(frame_c); |
| 118 | 128 |
| 119 TRACE_EVENT_BEGIN0("Testing", "Eclair"); | 129 TRACE_EVENT_BEGIN0("Testing", "Eclair"); |
| 120 AssertPseudoStackEquals(frame_ec); | 130 AssertBacktraceEquals(frame_ec); |
| 121 TRACE_EVENT_END0("Testing", "Eclair"); | 131 TRACE_EVENT_END0("Testing", "Eclair"); |
| 122 | 132 |
| 123 AssertPseudoStackEquals(frame_c); | 133 AssertBacktraceEquals(frame_c); |
| 124 TRACE_EVENT_END0("Testing", "Cupcake"); | 134 TRACE_EVENT_END0("Testing", "Cupcake"); |
| 125 | 135 |
| 126 AssertPseudoStackEmpty(); | 136 AssertBacktraceEmpty(); |
| 127 | 137 |
| 128 TRACE_EVENT_BEGIN0("Testing", "Froyo"); | 138 TRACE_EVENT_BEGIN0("Testing", "Froyo"); |
| 129 AssertPseudoStackEquals(frame_f); | 139 AssertBacktraceEquals(frame_f); |
| 130 TRACE_EVENT_END0("Testing", "Froyo"); | 140 TRACE_EVENT_END0("Testing", "Froyo"); |
| 131 | 141 |
| 132 AssertPseudoStackEmpty(); | 142 AssertBacktraceEmpty(); |
| 133 DisableTracing(); | |
| 134 } | 143 } |
| 135 | 144 |
| 136 TEST_F(AllocationContextTest, PseudoStackMixedTrace) { | 145 TEST_F(AllocationContextTest, PseudoStackMixedTrace) { |
| 137 StackFrame c = "Cupcake"; | 146 StackFrame c = "Cupcake"; |
| 138 StackFrame d = "Donut"; | 147 StackFrame d = "Donut"; |
| 139 StackFrame e = "Eclair"; | 148 StackFrame e = "Eclair"; |
| 140 StackFrame f = "Froyo"; | 149 StackFrame f = "Froyo"; |
| 141 | 150 |
| 142 StackFrame frame_c[] = {c}; | 151 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0}; |
| 143 StackFrame frame_dc[] = {d, c}; | 152 StackFrame frame_dc[] = {d, c, 0, 0, 0, 0, 0, 0}; |
| 144 StackFrame frame_e[] = {e}; | 153 StackFrame frame_e[] = {e, 0, 0, 0, 0, 0, 0, 0}; |
| 145 StackFrame frame_fe[] = {f, e}; | 154 StackFrame frame_fe[] = {f, e, 0, 0, 0, 0, 0, 0}; |
| 146 | 155 |
| 147 EnableTracing(); | 156 AssertBacktraceEmpty(); |
| 148 AssertPseudoStackEmpty(); | |
| 149 | 157 |
| 150 TRACE_EVENT_BEGIN0("Testing", "Cupcake"); | 158 TRACE_EVENT_BEGIN0("Testing", "Cupcake"); |
| 151 AssertPseudoStackEquals(frame_c); | 159 AssertBacktraceEquals(frame_c); |
| 152 | 160 |
| 153 { | 161 { |
| 154 TRACE_EVENT0("Testing", "Donut"); | 162 TRACE_EVENT0("Testing", "Donut"); |
| 155 AssertPseudoStackEquals(frame_dc); | 163 AssertBacktraceEquals(frame_dc); |
| 156 } | 164 } |
| 157 | 165 |
| 158 AssertPseudoStackEquals(frame_c); | 166 AssertBacktraceEquals(frame_c); |
| 159 TRACE_EVENT_END0("Testing", "Cupcake"); | 167 TRACE_EVENT_END0("Testing", "Cupcake"); |
| 160 AssertPseudoStackEmpty(); | 168 AssertBacktraceEmpty(); |
| 161 | 169 |
| 162 { | 170 { |
| 163 TRACE_EVENT0("Testing", "Eclair"); | 171 TRACE_EVENT0("Testing", "Eclair"); |
| 164 AssertPseudoStackEquals(frame_e); | 172 AssertBacktraceEquals(frame_e); |
| 165 | 173 |
| 166 TRACE_EVENT_BEGIN0("Testing", "Froyo"); | 174 TRACE_EVENT_BEGIN0("Testing", "Froyo"); |
| 167 AssertPseudoStackEquals(frame_fe); | 175 AssertBacktraceEquals(frame_fe); |
| 168 TRACE_EVENT_END0("Testing", "Froyo"); | 176 TRACE_EVENT_END0("Testing", "Froyo"); |
| 169 AssertPseudoStackEquals(frame_e); | 177 AssertBacktraceEquals(frame_e); |
| 170 } | 178 } |
| 171 | 179 |
| 172 AssertPseudoStackEmpty(); | 180 AssertBacktraceEmpty(); |
| 173 DisableTracing(); | |
| 174 } | 181 } |
| 175 | 182 |
| 176 TEST_F(AllocationContextTest, PseudoStackEnableWithEventInScope) { | 183 TEST_F(AllocationContextTest, BacktraceTakesTop) { |
| 177 StackFrame h = "Honeycomb"; | 184 TRACE_EVENT0("Testing", "Cupcake"); |
| 185 TRACE_EVENT0("Testing", "Donut"); |
| 186 TRACE_EVENT0("Testing", "Eclair"); |
| 187 TRACE_EVENT0("Testing", "Froyo"); |
| 188 TRACE_EVENT0("Testing", "Gingerbread"); |
| 189 TRACE_EVENT0("Testing", "Honeycomb"); |
| 190 TRACE_EVENT0("Testing", "Ice Cream Sandwich"); |
| 191 TRACE_EVENT0("Testing", "Jelly Bean"); |
| 178 | 192 |
| 179 { | 193 { |
| 180 TRACE_EVENT0("Testing", "Gingerbread"); | 194 TRACE_EVENT0("Testing", "KitKat"); |
| 181 EnableTracing(); | 195 AllocationContext ctx = AllocationContextTracker::GetContext(); |
| 182 AssertPseudoStackEmpty(); | 196 ASSERT_STREQ("KitKat", ctx.backtrace[0]); |
| 197 ASSERT_STREQ("Donut", ctx.backtrace[7]); |
| 198 } |
| 183 | 199 |
| 184 { | 200 { |
| 185 TRACE_EVENT0("Testing", "Honeycomb"); | 201 AllocationContext ctx = AllocationContextTracker::GetContext(); |
| 186 StackFrame frame_h[] = {h}; | 202 ASSERT_STREQ("Jelly Bean", ctx.backtrace[0]); |
| 187 AssertPseudoStackEquals(frame_h); | 203 ASSERT_STREQ("Cupcake", ctx.backtrace[7]); |
| 188 } | |
| 189 | |
| 190 AssertPseudoStackEmpty(); | |
| 191 | |
| 192 // The pop at the end of this scope for the 'Gingerbread' frame must not | |
| 193 // cause a stack underflow. | |
| 194 } | 204 } |
| 195 AssertPseudoStackEmpty(); | |
| 196 DisableTracing(); | |
| 197 } | 205 } |
| 198 | 206 |
| 199 } // namespace trace_event | 207 } // namespace trace_event |
| 200 } // namespace base | 208 } // namespace base |
| OLD | NEW |