Chromium Code Reviews| Index: base/trace_event/heap_profiler_stack_frame_deduplicator.cc |
| diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc |
| index 5e314984749925da7d2efc5f1f3e7852b5be8302..788b27a159598e5007fc614917cd9f52884c1c64 100644 |
| --- a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc |
| +++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc |
| @@ -7,9 +7,11 @@ |
| #include <inttypes.h> |
| #include <stddef.h> |
| +#include <algorithm> |
| #include <string> |
| #include <utility> |
| +#include "base/hash.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/trace_event/heap_profiler_string_deduplicator.h" |
| #include "base/trace_event/memory_usage_estimator.h" |
| @@ -19,6 +21,20 @@ |
| namespace base { |
| namespace trace_event { |
| +namespace { |
| + |
| +// Dumb hash function that nevertheless works surprisingly well and |
| +// produces ~0 collisions on real backtraces. |
| +size_t HashBacktrace(const StackFrame* begin, const StackFrame* end) { |
| + size_t summary = 0; |
|
Primiano Tucci (use gerrit)
2017/07/13 17:47:00
summary -> hash ?
|
| + for (; begin != end; begin++) { |
| + summary += reinterpret_cast<uintptr_t>(begin->value); |
| + } |
| + return summary; |
| +} |
| + |
| +} // namespace |
| + |
| StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame, |
| int parent_frame_index) |
| : frame(frame), parent_frame_index(parent_frame_index) {} |
| @@ -38,18 +54,55 @@ StackFrameDeduplicator::StackFrameDeduplicator( |
| } |
| StackFrameDeduplicator::~StackFrameDeduplicator() {} |
| -int StackFrameDeduplicator::Insert(const StackFrame* beginFrame, |
| - const StackFrame* endFrame) { |
| - if (beginFrame == endFrame) { |
| +bool StackFrameDeduplicator::Match(int frame_index, |
| + const StackFrame* begin_frame, |
| + const StackFrame* end_frame) const { |
| + // |frame_index| identifies the bottom frame, i.e. we need to walk |
| + // backtrace backwards. |
| + const StackFrame* current_frame = end_frame - 1; |
| + for (; current_frame >= begin_frame; --current_frame) { |
| + const FrameNode& node = frames_[frame_index]; |
| + if (node.frame != *current_frame) { |
| + break; |
| + } |
| + |
| + frame_index = node.parent_frame_index; |
| + if (frame_index == FrameNode::kInvalidFrameIndex) { |
| + if (current_frame == begin_frame) { |
| + // We're at the top node and we matched all backtrace frames, |
| + // i.e. we successfully matched the backtrace. |
| + return true; |
| + } |
| + break; |
| + } |
| + } |
| + |
| + return false; |
| +} |
| + |
| +int StackFrameDeduplicator::Insert(const StackFrame* begin_frame, |
| + const StackFrame* end_frame) { |
| + if (begin_frame == end_frame) { |
| // Empty backtraces are mapped to id 0. |
| return 0; |
| } |
| + size_t backtrace_hash = HashBacktrace(begin_frame, end_frame); |
| + |
| + // Check if we know about this backtrace. |
| + auto backtrace_it = backtrace_lookup_table_.find(backtrace_hash); |
| + if (backtrace_it != backtrace_lookup_table_.end()) { |
| + int backtrace_index = backtrace_it->second; |
| + if (Match(backtrace_index, begin_frame, end_frame)) { |
| + return backtrace_index; |
| + } |
| + } |
| + |
| int frame_index = FrameNode::kInvalidFrameIndex; |
| - std::map<StackFrame, int>* nodes = &roots_; |
| + base::flat_map<StackFrame, int>* nodes = &roots_; |
| // Loop through the frames, early out when a frame is null. |
| - for (const StackFrame* it = beginFrame; it != endFrame; it++) { |
| + for (const StackFrame* it = begin_frame; it != end_frame; it++) { |
| StackFrame frame = *it; |
| auto node = nodes->find(frame); |
| @@ -76,6 +129,9 @@ int StackFrameDeduplicator::Insert(const StackFrame* beginFrame, |
| nodes = &frames_[frame_index].children; |
| } |
| + // Remember the backtrace. |
| + backtrace_lookup_table_[backtrace_hash] = frame_index; |
| + |
| return frame_index; |
| } |
| @@ -120,8 +176,9 @@ void StackFrameDeduplicator::SerializeIncrementally(TracedValue* traced_value) { |
| void StackFrameDeduplicator::EstimateTraceMemoryOverhead( |
| TraceEventMemoryOverhead* overhead) { |
| - size_t memory_usage = |
| - EstimateMemoryUsage(frames_) + EstimateMemoryUsage(roots_); |
| + size_t memory_usage = EstimateMemoryUsage(frames_) + |
| + EstimateMemoryUsage(roots_) + |
| + EstimateMemoryUsage(backtrace_lookup_table_); |
| overhead->Add(TraceEventMemoryOverhead::kHeapProfilerStackFrameDeduplicator, |
| sizeof(StackFrameDeduplicator) + memory_usage); |
| } |