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..f6fb413bb6e16a192998c5ee6216e7cf13aaa6bd 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 hash = 0; |
+ for (; begin != end; begin++) { |
+ hash += reinterpret_cast<uintptr_t>(begin->value); |
+ } |
+ return hash; |
+} |
+ |
+} // 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); |
} |