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 <iterator>
      6 
      7 #include "base/macros.h"
      8 #include "base/memory/ref_counted.h"
      9 #include "base/trace_event/heap_profiler_allocation_context.h"
     10 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace base {
     14 namespace trace_event {
     15 
     16 // Define all strings once, because the deduplicator requires pointer equality,
     17 // and string interning is unreliable.
     18 const char kBrowserMain[] = "BrowserMain";
     19 const char kRendererMain[] = "RendererMain";
     20 const char kCreateWidget[] = "CreateWidget";
     21 const char kInitialize[] = "Initialize";
     22 const char kMalloc[] = "malloc";
     23 
     24 TEST(StackFrameDeduplicatorTest, SingleBacktrace) {
     25   StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc};
     26 
     27   // The call tree should look like this (index in brackets).
     28   //
     29   // BrowserMain [0]
     30   //   CreateWidget [1]
     31   //     malloc [2]
     32 
     33   scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
     34   ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
     35 
     36   auto iter = dedup->begin();
     37   ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
     38   ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
     39 
     40   ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
     41   ASSERT_EQ(0, (iter + 1)->parent_frame_index);
     42 
     43   ASSERT_EQ(kMalloc, (iter + 2)->frame);
     44   ASSERT_EQ(1, (iter + 2)->parent_frame_index);
     45 
     46   ASSERT_EQ(iter + 3, dedup->end());
     47 }
     48 
     49 // Test that there can be different call trees (there can be multiple bottom
     50 // frames). Also verify that frames with the same name but a different caller
     51 // are represented as distinct nodes.
     52 TEST(StackFrameDeduplicatorTest, MultipleRoots) {
     53   StackFrame bt0[] = {kBrowserMain, kCreateWidget};
     54   StackFrame bt1[] = {kRendererMain, kCreateWidget};
     55 
     56   // The call tree should look like this (index in brackets).
     57   //
     58   // BrowserMain [0]
     59   //   CreateWidget [1]
     60   // RendererMain [2]
     61   //   CreateWidget [3]
     62   //
     63   // Note that there will be two instances of CreateWidget,
     64   // with different parents.
     65 
     66   scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
     67   ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
     68   ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1)));
     69 
     70   auto iter = dedup->begin();
     71   ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
     72   ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
     73 
     74   ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
     75   ASSERT_EQ(0, (iter + 1)->parent_frame_index);
     76 
     77   ASSERT_EQ(kRendererMain, (iter + 2)->frame);
     78   ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
     79 
     80   ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
     81   ASSERT_EQ(2, (iter + 3)->parent_frame_index);
     82 
     83   ASSERT_EQ(iter + 4, dedup->end());
     84 }
     85 
     86 TEST(StackFrameDeduplicatorTest, Deduplication) {
     87   StackFrame bt0[] = {kBrowserMain, kCreateWidget};
     88   StackFrame bt1[] = {kBrowserMain, kInitialize};
     89 
     90   // The call tree should look like this (index in brackets).
     91   //
     92   // BrowserMain [0]
     93   //   CreateWidget [1]
     94   //   Initialize [2]
     95   //
     96   // Note that BrowserMain will be re-used.
     97 
     98   scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
     99   ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
    100   ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
    101 
    102   auto iter = dedup->begin();
    103   ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
    104   ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
    105 
    106   ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
    107   ASSERT_EQ(0, (iter + 1)->parent_frame_index);
    108 
    109   ASSERT_EQ(kInitialize, (iter + 2)->frame);
    110   ASSERT_EQ(0, (iter + 2)->parent_frame_index);
    111 
    112   ASSERT_EQ(iter + 3, dedup->end());
    113 
    114   // Inserting the same backtrace again should return the index of the existing
    115   // node.
    116   ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
    117   ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
    118   ASSERT_EQ(dedup->begin() + 3, dedup->end());
    119 }
    120 
    121 TEST(StackFrameDeduplicatorTest, NullPaddingIsRemoved) {
    122   StackFrame bt0[] = {kBrowserMain, nullptr, nullptr, nullptr};
    123 
    124   scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
    125 
    126   // There are four frames in the backtrace, but the null pointers should be
    127   // skipped, so only one frame is inserted, which will have index 0.
    128   ASSERT_EQ(4u, arraysize(bt0));
    129   ASSERT_EQ(0, dedup->Insert(std::begin(bt0), std::end(bt0)));
    130   ASSERT_EQ(dedup->begin() + 1, dedup->end());
    131 }
    132 
    133 }  // namespace trace_event
    134 }  // namespace base
    135