Home | History | Annotate | Download | only in trace_event
      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