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