| 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" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 | 26 |
| 27 // Asserts that the fixed-size array |expected_backtrace| matches the backtrace | 27 // Asserts that the fixed-size array |expected_backtrace| matches the backtrace |
| 28 // in |AllocationContextTracker::GetContextSnapshot|. | 28 // in |AllocationContextTracker::GetContextSnapshot|. |
| 29 template <size_t N> | 29 template <size_t N> |
| 30 void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) { | 30 void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) { |
| 31 AllocationContext ctx = | 31 AllocationContext ctx = |
| 32 AllocationContextTracker::GetInstanceForCurrentThread() | 32 AllocationContextTracker::GetInstanceForCurrentThread() |
| 33 ->GetContextSnapshot(); | 33 ->GetContextSnapshot(); |
| 34 | 34 |
| 35 auto actual = std::begin(ctx.backtrace.frames); | 35 auto actual = std::begin(ctx.backtrace.frames); |
| 36 auto actual_bottom = actual + ctx.backtrace.frame_count; | 36 auto actual_bottom = std::end(ctx.backtrace.frames); |
| 37 auto expected = std::begin(expected_backtrace); | 37 auto expected = std::begin(expected_backtrace); |
| 38 auto expected_bottom = std::end(expected_backtrace); | 38 auto expected_bottom = std::end(expected_backtrace); |
| 39 | 39 |
| 40 // Note that this requires the pointers to be equal, this is not doing a deep | 40 // Note that this requires the pointers to be equal, this is not doing a deep |
| 41 // string comparison. | 41 // string comparison. |
| 42 for (; actual != actual_bottom && expected != expected_bottom; | 42 for (; actual != actual_bottom && expected != expected_bottom; |
| 43 actual++, expected++) | 43 actual++, expected++) |
| 44 ASSERT_EQ(*expected, *actual); | 44 ASSERT_EQ(*expected, *actual); |
| 45 | 45 |
| 46 // Ensure that the height of the stacks is the same. | 46 // Ensure that the height of the stacks is the same. |
| 47 ASSERT_EQ(actual, actual_bottom); | 47 ASSERT_EQ(actual, actual_bottom); |
| 48 ASSERT_EQ(expected, expected_bottom); | 48 ASSERT_EQ(expected, expected_bottom); |
| 49 } | 49 } |
| 50 | 50 |
| 51 void AssertBacktraceEmpty() { | 51 void AssertBacktraceEmpty() { |
| 52 AllocationContext ctx = | 52 AllocationContext ctx = |
| 53 AllocationContextTracker::GetInstanceForCurrentThread() | 53 AllocationContextTracker::GetInstanceForCurrentThread() |
| 54 ->GetContextSnapshot(); | 54 ->GetContextSnapshot(); |
| 55 | 55 |
| 56 ASSERT_EQ(0u, ctx.backtrace.frame_count); | 56 for (StackFrame frame : ctx.backtrace.frames) |
| 57 ASSERT_EQ(nullptr, frame); |
| 57 } | 58 } |
| 58 | 59 |
| 59 class AllocationContextTrackerTest : public testing::Test { | 60 class AllocationContextTrackerTest : public testing::Test { |
| 60 public: | 61 public: |
| 61 void SetUp() override { | 62 void SetUp() override { |
| 62 TraceConfig config(""); | 63 TraceConfig config(""); |
| 63 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE); | 64 TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE); |
| 64 AllocationContextTracker::SetCaptureEnabled(true); | 65 AllocationContextTracker::SetCaptureEnabled(true); |
| 65 } | 66 } |
| 66 | 67 |
| 67 void TearDown() override { | 68 void TearDown() override { |
| 68 AllocationContextTracker::SetCaptureEnabled(false); | 69 AllocationContextTracker::SetCaptureEnabled(false); |
| 69 TraceLog::GetInstance()->SetDisabled(); | 70 TraceLog::GetInstance()->SetDisabled(); |
| 70 } | 71 } |
| 71 }; | 72 }; |
| 72 | 73 |
| 73 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly. | 74 // Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly. |
| 75 // Also check that |GetContextSnapshot| fills the backtrace with null pointers |
| 76 // when the pseudo stack height is less than the capacity. |
| 74 TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) { | 77 TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) { |
| 75 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | 78 StackFrame c = kCupcake; |
| 76 StackFrame d = StackFrame::FromTraceEventName(kDonut); | 79 StackFrame d = kDonut; |
| 77 StackFrame e = StackFrame::FromTraceEventName(kEclair); | 80 StackFrame e = kEclair; |
| 78 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | 81 StackFrame f = kFroyo; |
| 79 | 82 |
| 80 AssertBacktraceEmpty(); | 83 AssertBacktraceEmpty(); |
| 81 | 84 |
| 82 { | 85 { |
| 83 TRACE_EVENT0("Testing", kCupcake); | 86 TRACE_EVENT0("Testing", kCupcake); |
| 84 StackFrame frame_c[] = {c}; | 87 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 85 AssertBacktraceEquals(frame_c); | 88 AssertBacktraceEquals(frame_c); |
| 86 | 89 |
| 87 { | 90 { |
| 88 TRACE_EVENT0("Testing", kDonut); | 91 TRACE_EVENT0("Testing", kDonut); |
| 89 StackFrame frame_cd[] = {c, d}; | 92 StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 90 AssertBacktraceEquals(frame_cd); | 93 AssertBacktraceEquals(frame_cd); |
| 91 } | 94 } |
| 92 | 95 |
| 93 AssertBacktraceEquals(frame_c); | 96 AssertBacktraceEquals(frame_c); |
| 94 | 97 |
| 95 { | 98 { |
| 96 TRACE_EVENT0("Testing", kEclair); | 99 TRACE_EVENT0("Testing", kEclair); |
| 97 StackFrame frame_ce[] = {c, e}; | 100 StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 98 AssertBacktraceEquals(frame_ce); | 101 AssertBacktraceEquals(frame_ce); |
| 99 } | 102 } |
| 100 | 103 |
| 101 AssertBacktraceEquals(frame_c); | 104 AssertBacktraceEquals(frame_c); |
| 102 } | 105 } |
| 103 | 106 |
| 104 AssertBacktraceEmpty(); | 107 AssertBacktraceEmpty(); |
| 105 | 108 |
| 106 { | 109 { |
| 107 TRACE_EVENT0("Testing", kFroyo); | 110 TRACE_EVENT0("Testing", kFroyo); |
| 108 StackFrame frame_f[] = {f}; | 111 StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 109 AssertBacktraceEquals(frame_f); | 112 AssertBacktraceEquals(frame_f); |
| 110 } | 113 } |
| 111 | 114 |
| 112 AssertBacktraceEmpty(); | 115 AssertBacktraceEmpty(); |
| 113 } | 116 } |
| 114 | 117 |
| 115 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and | 118 // Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and |
| 116 // |TRACE_EVENT_END| macros. | 119 // |TRACE_EVENT_END| macros. |
| 117 TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) { | 120 TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) { |
| 118 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | 121 StackFrame c = kCupcake; |
| 119 StackFrame d = StackFrame::FromTraceEventName(kDonut); | 122 StackFrame d = kDonut; |
| 120 StackFrame e = StackFrame::FromTraceEventName(kEclair); | 123 StackFrame e = kEclair; |
| 121 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | 124 StackFrame f = kFroyo; |
| 122 | 125 |
| 123 StackFrame frame_c[] = {c}; | 126 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 124 StackFrame frame_cd[] = {c, d}; | 127 StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 125 StackFrame frame_ce[] = {c, e}; | 128 StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 126 StackFrame frame_f[] = {f}; | 129 StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 127 | 130 |
| 128 AssertBacktraceEmpty(); | 131 AssertBacktraceEmpty(); |
| 129 | 132 |
| 130 TRACE_EVENT_BEGIN0("Testing", kCupcake); | 133 TRACE_EVENT_BEGIN0("Testing", kCupcake); |
| 131 AssertBacktraceEquals(frame_c); | 134 AssertBacktraceEquals(frame_c); |
| 132 | 135 |
| 133 TRACE_EVENT_BEGIN0("Testing", kDonut); | 136 TRACE_EVENT_BEGIN0("Testing", kDonut); |
| 134 AssertBacktraceEquals(frame_cd); | 137 AssertBacktraceEquals(frame_cd); |
| 135 TRACE_EVENT_END0("Testing", kDonut); | 138 TRACE_EVENT_END0("Testing", kDonut); |
| 136 | 139 |
| 137 AssertBacktraceEquals(frame_c); | 140 AssertBacktraceEquals(frame_c); |
| 138 | 141 |
| 139 TRACE_EVENT_BEGIN0("Testing", kEclair); | 142 TRACE_EVENT_BEGIN0("Testing", kEclair); |
| 140 AssertBacktraceEquals(frame_ce); | 143 AssertBacktraceEquals(frame_ce); |
| 141 TRACE_EVENT_END0("Testing", kEclair); | 144 TRACE_EVENT_END0("Testing", kEclair); |
| 142 | 145 |
| 143 AssertBacktraceEquals(frame_c); | 146 AssertBacktraceEquals(frame_c); |
| 144 TRACE_EVENT_END0("Testing", kCupcake); | 147 TRACE_EVENT_END0("Testing", kCupcake); |
| 145 | 148 |
| 146 AssertBacktraceEmpty(); | 149 AssertBacktraceEmpty(); |
| 147 | 150 |
| 148 TRACE_EVENT_BEGIN0("Testing", kFroyo); | 151 TRACE_EVENT_BEGIN0("Testing", kFroyo); |
| 149 AssertBacktraceEquals(frame_f); | 152 AssertBacktraceEquals(frame_f); |
| 150 TRACE_EVENT_END0("Testing", kFroyo); | 153 TRACE_EVENT_END0("Testing", kFroyo); |
| 151 | 154 |
| 152 AssertBacktraceEmpty(); | 155 AssertBacktraceEmpty(); |
| 153 } | 156 } |
| 154 | 157 |
| 155 TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) { | 158 TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) { |
| 156 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | 159 StackFrame c = kCupcake; |
| 157 StackFrame d = StackFrame::FromTraceEventName(kDonut); | 160 StackFrame d = kDonut; |
| 158 StackFrame e = StackFrame::FromTraceEventName(kEclair); | 161 StackFrame e = kEclair; |
| 159 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | 162 StackFrame f = kFroyo; |
| 160 | 163 |
| 161 StackFrame frame_c[] = {c}; | 164 StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 162 StackFrame frame_cd[] = {c, d}; | 165 StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 163 StackFrame frame_e[] = {e}; | 166 StackFrame frame_e[] = {e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 164 StackFrame frame_ef[] = {e, f}; | 167 StackFrame frame_ef[] = {e, f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 165 | 168 |
| 166 AssertBacktraceEmpty(); | 169 AssertBacktraceEmpty(); |
| 167 | 170 |
| 168 TRACE_EVENT_BEGIN0("Testing", kCupcake); | 171 TRACE_EVENT_BEGIN0("Testing", kCupcake); |
| 169 AssertBacktraceEquals(frame_c); | 172 AssertBacktraceEquals(frame_c); |
| 170 | 173 |
| 171 { | 174 { |
| 172 TRACE_EVENT0("Testing", kDonut); | 175 TRACE_EVENT0("Testing", kDonut); |
| 173 AssertBacktraceEquals(frame_cd); | 176 AssertBacktraceEquals(frame_cd); |
| 174 } | 177 } |
| 175 | 178 |
| 176 AssertBacktraceEquals(frame_c); | 179 AssertBacktraceEquals(frame_c); |
| 177 TRACE_EVENT_END0("Testing", kCupcake); | 180 TRACE_EVENT_END0("Testing", kCupcake); |
| 178 AssertBacktraceEmpty(); | 181 AssertBacktraceEmpty(); |
| 179 | 182 |
| 180 { | 183 { |
| 181 TRACE_EVENT0("Testing", kEclair); | 184 TRACE_EVENT0("Testing", kEclair); |
| 182 AssertBacktraceEquals(frame_e); | 185 AssertBacktraceEquals(frame_e); |
| 183 | 186 |
| 184 TRACE_EVENT_BEGIN0("Testing", kFroyo); | 187 TRACE_EVENT_BEGIN0("Testing", kFroyo); |
| 185 AssertBacktraceEquals(frame_ef); | 188 AssertBacktraceEquals(frame_ef); |
| 186 TRACE_EVENT_END0("Testing", kFroyo); | 189 TRACE_EVENT_END0("Testing", kFroyo); |
| 187 AssertBacktraceEquals(frame_e); | 190 AssertBacktraceEquals(frame_e); |
| 188 } | 191 } |
| 189 | 192 |
| 190 AssertBacktraceEmpty(); | 193 AssertBacktraceEmpty(); |
| 191 } | 194 } |
| 192 | 195 |
| 193 TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) { | 196 TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) { |
| 194 StackFrame c = StackFrame::FromTraceEventName(kCupcake); | |
| 195 StackFrame f = StackFrame::FromTraceEventName(kFroyo); | |
| 196 | |
| 197 // Push 12 events onto the pseudo stack. | 197 // Push 12 events onto the pseudo stack. |
| 198 TRACE_EVENT0("Testing", kCupcake); | 198 TRACE_EVENT0("Testing", kCupcake); |
| 199 TRACE_EVENT0("Testing", kCupcake); | 199 TRACE_EVENT0("Testing", kCupcake); |
| 200 TRACE_EVENT0("Testing", kCupcake); | 200 TRACE_EVENT0("Testing", kCupcake); |
| 201 TRACE_EVENT0("Testing", kCupcake); | 201 TRACE_EVENT0("Testing", kCupcake); |
| 202 | 202 |
| 203 TRACE_EVENT0("Testing", kCupcake); | 203 TRACE_EVENT0("Testing", kCupcake); |
| 204 TRACE_EVENT0("Testing", kCupcake); | 204 TRACE_EVENT0("Testing", kCupcake); |
| 205 TRACE_EVENT0("Testing", kCupcake); | 205 TRACE_EVENT0("Testing", kCupcake); |
| 206 TRACE_EVENT0("Testing", kCupcake); | 206 TRACE_EVENT0("Testing", kCupcake); |
| 207 | 207 |
| 208 TRACE_EVENT0("Testing", kCupcake); | 208 TRACE_EVENT0("Testing", kCupcake); |
| 209 TRACE_EVENT0("Testing", kDonut); | 209 TRACE_EVENT0("Testing", kDonut); |
| 210 TRACE_EVENT0("Testing", kEclair); | 210 TRACE_EVENT0("Testing", kEclair); |
| 211 TRACE_EVENT0("Testing", kFroyo); | 211 TRACE_EVENT0("Testing", kFroyo); |
| 212 | 212 |
| 213 { | 213 { |
| 214 TRACE_EVENT0("Testing", kGingerbread); | 214 TRACE_EVENT0("Testing", kGingerbread); |
| 215 AllocationContext ctx = | 215 AllocationContext ctx = |
| 216 AllocationContextTracker::GetInstanceForCurrentThread() | 216 AllocationContextTracker::GetInstanceForCurrentThread() |
| 217 ->GetContextSnapshot(); | 217 ->GetContextSnapshot(); |
| 218 | 218 |
| 219 // The pseudo stack relies on pointer equality, not deep string comparisons. | 219 // The pseudo stack relies on pointer equality, not deep string comparisons. |
| 220 ASSERT_EQ(c, ctx.backtrace.frames[0]); | 220 ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]); |
| 221 ASSERT_EQ(f, ctx.backtrace.frames[11]); | 221 ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]); |
| 222 } | 222 } |
| 223 | 223 |
| 224 { | 224 { |
| 225 AllocationContext ctx = | 225 AllocationContext ctx = |
| 226 AllocationContextTracker::GetInstanceForCurrentThread() | 226 AllocationContextTracker::GetInstanceForCurrentThread() |
| 227 ->GetContextSnapshot(); | 227 ->GetContextSnapshot(); |
| 228 ASSERT_EQ(c, ctx.backtrace.frames[0]); | 228 ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]); |
| 229 ASSERT_EQ(f, ctx.backtrace.frames[11]); | 229 ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]); |
| 230 } | 230 } |
| 231 } | 231 } |
| 232 | 232 |
| 233 TEST_F(AllocationContextTrackerTest, SetCurrentThreadName) { | 233 TEST_F(AllocationContextTrackerTest, SetCurrentThreadName) { |
| 234 TRACE_EVENT0("Testing", kCupcake); | 234 TRACE_EVENT0("Testing", kCupcake); |
| 235 | 235 |
| 236 // Test if the thread name is inserted into backtrace. | 236 // Test if the thread name is inserted into backtrace. |
| 237 const char kThread1[] = "thread1"; | 237 const char kThread1[] = "thread1"; |
| 238 AllocationContextTracker::SetCurrentThreadName(kThread1); | 238 AllocationContextTracker::SetCurrentThreadName(kThread1); |
| 239 AllocationContext ctx1 = | 239 AllocationContext ctx1 = |
| 240 AllocationContextTracker::GetInstanceForCurrentThread() | 240 AllocationContextTracker::GetInstanceForCurrentThread() |
| 241 ->GetContextSnapshot(); | 241 ->GetContextSnapshot(); |
| 242 ASSERT_EQ(StackFrame::FromThreadName(kThread1), ctx1.backtrace.frames[0]); | 242 ASSERT_EQ(kThread1, ctx1.backtrace.frames[0]); |
| 243 ASSERT_EQ(StackFrame::FromTraceEventName(kCupcake), ctx1.backtrace.frames[1]); | 243 ASSERT_EQ(kCupcake, ctx1.backtrace.frames[1]); |
| 244 | 244 |
| 245 // Test if the thread name is reset. | 245 // Test if the thread name is reset. |
| 246 const char kThread2[] = "thread2"; | 246 const char kThread2[] = "thread2"; |
| 247 AllocationContextTracker::SetCurrentThreadName(kThread2); | 247 AllocationContextTracker::SetCurrentThreadName(kThread2); |
| 248 AllocationContext ctx2 = | 248 AllocationContext ctx2 = |
| 249 AllocationContextTracker::GetInstanceForCurrentThread() | 249 AllocationContextTracker::GetInstanceForCurrentThread() |
| 250 ->GetContextSnapshot(); | 250 ->GetContextSnapshot(); |
| 251 ASSERT_EQ(StackFrame::FromThreadName(kThread2), ctx2.backtrace.frames[0]); | 251 ASSERT_EQ(kThread2, ctx2.backtrace.frames[0]); |
| 252 ASSERT_EQ(StackFrame::FromTraceEventName(kCupcake), ctx2.backtrace.frames[1]); | 252 ASSERT_EQ(kCupcake, ctx2.backtrace.frames[1]); |
| 253 } | 253 } |
| 254 | 254 |
| 255 TEST_F(AllocationContextTrackerTest, TrackTaskContext) { | 255 TEST_F(AllocationContextTrackerTest, TrackTaskContext) { |
| 256 const char kContext1[] = "context1"; | 256 const char kContext1[] = "context1"; |
| 257 const char kContext2[] = "context2"; | 257 const char kContext2[] = "context2"; |
| 258 { | 258 { |
| 259 // The context from the scoped task event should be used as type name. | 259 // The context from the scoped task event should be used as type name. |
| 260 TRACE_EVENT_API_SCOPED_TASK_EXECUTION_EVENT event1(kContext1); | 260 TRACE_EVENT_API_SCOPED_TASK_EXECUTION_EVENT event1(kContext1); |
| 261 AllocationContext ctx1 = | 261 AllocationContext ctx1 = |
| 262 AllocationContextTracker::GetInstanceForCurrentThread() | 262 AllocationContextTracker::GetInstanceForCurrentThread() |
| (...skipping 10 matching lines...) Expand all Loading... |
| 273 | 273 |
| 274 // Type should be nullptr without task event. | 274 // Type should be nullptr without task event. |
| 275 AllocationContext ctx = | 275 AllocationContext ctx = |
| 276 AllocationContextTracker::GetInstanceForCurrentThread() | 276 AllocationContextTracker::GetInstanceForCurrentThread() |
| 277 ->GetContextSnapshot(); | 277 ->GetContextSnapshot(); |
| 278 ASSERT_FALSE(ctx.type_name); | 278 ASSERT_FALSE(ctx.type_name); |
| 279 } | 279 } |
| 280 | 280 |
| 281 } // namespace trace_event | 281 } // namespace trace_event |
| 282 } // namespace base | 282 } // namespace base |
| OLD | NEW |