1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
#include <iterator>
#include <memory>
#include "base/macros.h"
#include "base/trace_event/heap_profiler_allocation_context.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace trace_event {
// Define all strings once, because the deduplicator requires pointer equality,
// and string interning is unreliable.
StackFrame kBrowserMain = StackFrame::FromTraceEventName("BrowserMain");
StackFrame kRendererMain = StackFrame::FromTraceEventName("RendererMain");
StackFrame kCreateWidget = StackFrame::FromTraceEventName("CreateWidget");
StackFrame kInitialize = StackFrame::FromTraceEventName("Initialize");
StackFrame kMalloc = StackFrame::FromTraceEventName("malloc");
TEST(StackFrameDeduplicatorTest, SingleBacktrace) {
StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc};
// The call tree should look like this (index in brackets).
//
// BrowserMain [0]
// CreateWidget [1]
// malloc [2]
std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
auto iter = dedup->begin();
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
ASSERT_EQ(0, (iter + 1)->parent_frame_index);
ASSERT_EQ(kMalloc, (iter + 2)->frame);
ASSERT_EQ(1, (iter + 2)->parent_frame_index);
ASSERT_EQ(iter + 3, dedup->end());
}
TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) {
StackFrame null_frame = StackFrame::FromTraceEventName(nullptr);
StackFrame bt[] = {kBrowserMain, null_frame, kMalloc};
// Deduplicator doesn't care about what's inside StackFrames,
// and handles nullptr StackFrame values as any other.
//
// So the call tree should look like this (index in brackets).
//
// BrowserMain [0]
// (null) [1]
// malloc [2]
std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
auto iter = dedup->begin();
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
ASSERT_EQ(null_frame, (iter + 1)->frame);
ASSERT_EQ(0, (iter + 1)->parent_frame_index);
ASSERT_EQ(kMalloc, (iter + 2)->frame);
ASSERT_EQ(1, (iter + 2)->parent_frame_index);
ASSERT_EQ(iter + 3, dedup->end());
}
// Test that there can be different call trees (there can be multiple bottom
// frames). Also verify that frames with the same name but a different caller
// are represented as distinct nodes.
TEST(StackFrameDeduplicatorTest, MultipleRoots) {
StackFrame bt0[] = {kBrowserMain, kCreateWidget};
StackFrame bt1[] = {kRendererMain, kCreateWidget};
// The call tree should look like this (index in brackets).
//
// BrowserMain [0]
// CreateWidget [1]
// RendererMain [2]
// CreateWidget [3]
//
// Note that there will be two instances of CreateWidget,
// with different parents.
std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1)));
auto iter = dedup->begin();
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
ASSERT_EQ(0, (iter + 1)->parent_frame_index);
ASSERT_EQ(kRendererMain, (iter + 2)->frame);
ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
ASSERT_EQ(2, (iter + 3)->parent_frame_index);
ASSERT_EQ(iter + 4, dedup->end());
}
TEST(StackFrameDeduplicatorTest, Deduplication) {
StackFrame bt0[] = {kBrowserMain, kCreateWidget};
StackFrame bt1[] = {kBrowserMain, kInitialize};
// The call tree should look like this (index in brackets).
//
// BrowserMain [0]
// CreateWidget [1]
// Initialize [2]
//
// Note that BrowserMain will be re-used.
std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
auto iter = dedup->begin();
ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
ASSERT_EQ(0, (iter + 1)->parent_frame_index);
ASSERT_EQ(kInitialize, (iter + 2)->frame);
ASSERT_EQ(0, (iter + 2)->parent_frame_index);
ASSERT_EQ(iter + 3, dedup->end());
// Inserting the same backtrace again should return the index of the existing
// node.
ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
ASSERT_EQ(dedup->begin() + 3, dedup->end());
}
} // namespace trace_event
} // namespace base
|