Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: base/trace_event/heap_profiler_stack_frame_deduplicator.cc

Issue 2977783002: [tracing] Optimize StackFrameDeduplicator. (Closed)
Patch Set: Don't use ASSERT_EQ on deque iterators (see goo.gl/9gkBf7) Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "base/trace_event/heap_profiler_stack_frame_deduplicator.h" 5 #include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
6 6
7 #include <inttypes.h> 7 #include <inttypes.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 9
10 #include <algorithm>
10 #include <string> 11 #include <string>
11 #include <utility> 12 #include <utility>
12 13
14 #include "base/hash.h"
13 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
14 #include "base/trace_event/heap_profiler_string_deduplicator.h" 16 #include "base/trace_event/heap_profiler_string_deduplicator.h"
15 #include "base/trace_event/memory_usage_estimator.h" 17 #include "base/trace_event/memory_usage_estimator.h"
16 #include "base/trace_event/trace_event_argument.h" 18 #include "base/trace_event/trace_event_argument.h"
17 #include "base/trace_event/trace_event_memory_overhead.h" 19 #include "base/trace_event/trace_event_memory_overhead.h"
18 20
19 namespace base { 21 namespace base {
20 namespace trace_event { 22 namespace trace_event {
21 23
24 namespace {
25
26 // Dumb hash function that nevertheless works surprisingly well and
27 // produces ~0 collisions on real backtraces.
28 size_t HashBacktrace(const StackFrame* begin, const StackFrame* end) {
29 size_t hash = 0;
30 for (; begin != end; begin++) {
31 hash += reinterpret_cast<uintptr_t>(begin->value);
32 }
33 return hash;
34 }
35
36 } // namespace
37
22 StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame, 38 StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
23 int parent_frame_index) 39 int parent_frame_index)
24 : frame(frame), parent_frame_index(parent_frame_index) {} 40 : frame(frame), parent_frame_index(parent_frame_index) {}
25 StackFrameDeduplicator::FrameNode::FrameNode(const FrameNode& other) = default; 41 StackFrameDeduplicator::FrameNode::FrameNode(const FrameNode& other) = default;
26 StackFrameDeduplicator::FrameNode::~FrameNode() {} 42 StackFrameDeduplicator::FrameNode::~FrameNode() {}
27 43
28 size_t StackFrameDeduplicator::FrameNode::EstimateMemoryUsage() const { 44 size_t StackFrameDeduplicator::FrameNode::EstimateMemoryUsage() const {
29 return base::trace_event::EstimateMemoryUsage(children); 45 return base::trace_event::EstimateMemoryUsage(children);
30 } 46 }
31 47
32 StackFrameDeduplicator::StackFrameDeduplicator( 48 StackFrameDeduplicator::StackFrameDeduplicator(
33 StringDeduplicator* string_deduplicator) 49 StringDeduplicator* string_deduplicator)
34 : string_deduplicator_(string_deduplicator), last_exported_index_(0) { 50 : string_deduplicator_(string_deduplicator), last_exported_index_(0) {
35 // Add implicit entry for id 0 (empty backtraces). 51 // Add implicit entry for id 0 (empty backtraces).
36 frames_.push_back(FrameNode(StackFrame::FromTraceEventName(nullptr), 52 frames_.push_back(FrameNode(StackFrame::FromTraceEventName(nullptr),
37 FrameNode::kInvalidFrameIndex)); 53 FrameNode::kInvalidFrameIndex));
38 } 54 }
39 StackFrameDeduplicator::~StackFrameDeduplicator() {} 55 StackFrameDeduplicator::~StackFrameDeduplicator() {}
40 56
41 int StackFrameDeduplicator::Insert(const StackFrame* beginFrame, 57 bool StackFrameDeduplicator::Match(int frame_index,
42 const StackFrame* endFrame) { 58 const StackFrame* begin_frame,
43 if (beginFrame == endFrame) { 59 const StackFrame* end_frame) const {
60 // |frame_index| identifies the bottom frame, i.e. we need to walk
61 // backtrace backwards.
62 const StackFrame* current_frame = end_frame - 1;
63 for (; current_frame >= begin_frame; --current_frame) {
64 const FrameNode& node = frames_[frame_index];
65 if (node.frame != *current_frame) {
66 break;
67 }
68
69 frame_index = node.parent_frame_index;
70 if (frame_index == FrameNode::kInvalidFrameIndex) {
71 if (current_frame == begin_frame) {
72 // We're at the top node and we matched all backtrace frames,
73 // i.e. we successfully matched the backtrace.
74 return true;
75 }
76 break;
77 }
78 }
79
80 return false;
81 }
82
83 int StackFrameDeduplicator::Insert(const StackFrame* begin_frame,
84 const StackFrame* end_frame) {
85 if (begin_frame == end_frame) {
44 // Empty backtraces are mapped to id 0. 86 // Empty backtraces are mapped to id 0.
45 return 0; 87 return 0;
46 } 88 }
47 89
90 size_t backtrace_hash = HashBacktrace(begin_frame, end_frame);
91
92 // Check if we know about this backtrace.
93 auto backtrace_it = backtrace_lookup_table_.find(backtrace_hash);
94 if (backtrace_it != backtrace_lookup_table_.end()) {
95 int backtrace_index = backtrace_it->second;
96 if (Match(backtrace_index, begin_frame, end_frame)) {
97 return backtrace_index;
98 }
99 }
100
48 int frame_index = FrameNode::kInvalidFrameIndex; 101 int frame_index = FrameNode::kInvalidFrameIndex;
49 std::map<StackFrame, int>* nodes = &roots_; 102 base::flat_map<StackFrame, int>* nodes = &roots_;
50 103
51 // Loop through the frames, early out when a frame is null. 104 // Loop through the frames, early out when a frame is null.
52 for (const StackFrame* it = beginFrame; it != endFrame; it++) { 105 for (const StackFrame* it = begin_frame; it != end_frame; it++) {
53 StackFrame frame = *it; 106 StackFrame frame = *it;
54 107
55 auto node = nodes->find(frame); 108 auto node = nodes->find(frame);
56 if (node == nodes->end()) { 109 if (node == nodes->end()) {
57 // There is no tree node for this frame yet, create it. The parent node 110 // There is no tree node for this frame yet, create it. The parent node
58 // is the node associated with the previous frame. 111 // is the node associated with the previous frame.
59 FrameNode frame_node(frame, frame_index); 112 FrameNode frame_node(frame, frame_index);
60 113
61 // The new frame node will be appended, so its index is the current size 114 // The new frame node will be appended, so its index is the current size
62 // of the vector. 115 // of the vector.
63 frame_index = static_cast<int>(frames_.size()); 116 frame_index = static_cast<int>(frames_.size());
64 117
65 // Add the node to the trie so it will be found next time. 118 // Add the node to the trie so it will be found next time.
66 nodes->insert(std::make_pair(frame, frame_index)); 119 nodes->insert(std::make_pair(frame, frame_index));
67 120
68 // Append the node after modifying |nodes|, because the |frames_| vector 121 // Append the node after modifying |nodes|, because the |frames_| vector
69 // might need to resize, and this invalidates the |nodes| pointer. 122 // might need to resize, and this invalidates the |nodes| pointer.
70 frames_.push_back(frame_node); 123 frames_.push_back(frame_node);
71 } else { 124 } else {
72 // A tree node for this frame exists. Look for the next one. 125 // A tree node for this frame exists. Look for the next one.
73 frame_index = node->second; 126 frame_index = node->second;
74 } 127 }
75 128
76 nodes = &frames_[frame_index].children; 129 nodes = &frames_[frame_index].children;
77 } 130 }
78 131
132 // Remember the backtrace.
133 backtrace_lookup_table_[backtrace_hash] = frame_index;
134
79 return frame_index; 135 return frame_index;
80 } 136 }
81 137
82 void StackFrameDeduplicator::SerializeIncrementally(TracedValue* traced_value) { 138 void StackFrameDeduplicator::SerializeIncrementally(TracedValue* traced_value) {
83 std::string stringify_buffer; 139 std::string stringify_buffer;
84 140
85 for (; last_exported_index_ < frames_.size(); ++last_exported_index_) { 141 for (; last_exported_index_ < frames_.size(); ++last_exported_index_) {
86 const auto& frame_node = frames_[last_exported_index_]; 142 const auto& frame_node = frames_[last_exported_index_];
87 traced_value->BeginDictionary(); 143 traced_value->BeginDictionary();
88 144
(...skipping 24 matching lines...) Expand all
113 if (frame_node.parent_frame_index != FrameNode::kInvalidFrameIndex) { 169 if (frame_node.parent_frame_index != FrameNode::kInvalidFrameIndex) {
114 traced_value->SetInteger("parent", frame_node.parent_frame_index); 170 traced_value->SetInteger("parent", frame_node.parent_frame_index);
115 } 171 }
116 172
117 traced_value->EndDictionary(); 173 traced_value->EndDictionary();
118 } 174 }
119 } 175 }
120 176
121 void StackFrameDeduplicator::EstimateTraceMemoryOverhead( 177 void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
122 TraceEventMemoryOverhead* overhead) { 178 TraceEventMemoryOverhead* overhead) {
123 size_t memory_usage = 179 size_t memory_usage = EstimateMemoryUsage(frames_) +
124 EstimateMemoryUsage(frames_) + EstimateMemoryUsage(roots_); 180 EstimateMemoryUsage(roots_) +
181 EstimateMemoryUsage(backtrace_lookup_table_);
125 overhead->Add(TraceEventMemoryOverhead::kHeapProfilerStackFrameDeduplicator, 182 overhead->Add(TraceEventMemoryOverhead::kHeapProfilerStackFrameDeduplicator,
126 sizeof(StackFrameDeduplicator) + memory_usage); 183 sizeof(StackFrameDeduplicator) + memory_usage);
127 } 184 }
128 185
129 } // namespace trace_event 186 } // namespace trace_event
130 } // namespace base 187 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698