Index: base/trace_event/memory_profiler_heap_dump_writer.cc |
diff --git a/base/trace_event/memory_profiler_heap_dump_writer.cc b/base/trace_event/memory_profiler_heap_dump_writer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b2410cf5f70ea2fd554f656cdf90f96399998a2c |
--- /dev/null |
+++ b/base/trace_event/memory_profiler_heap_dump_writer.cc |
@@ -0,0 +1,100 @@ |
+// 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/memory_profiler_heap_dump_writer.h" |
+ |
+#include <numeric> |
+ |
+#include "base/format_macros.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/trace_event/memory_profiler_allocation_register.h" |
+#include "base/trace_event/trace_event_argument.h" |
+ |
+namespace base { |
+namespace trace_event { |
+ |
+namespace { |
+ |
+template <typename T> |
+bool PairSizeGt(const std::pair<T, size_t>& lhs, |
+ const std::pair<T, size_t>& rhs) { |
+ return lhs.second > rhs.second; |
+} |
+ |
+template <typename T> |
+size_t PairSizeAdd(size_t acc, const std::pair<T, size_t>& rhs) { |
+ return acc + rhs.second; |
+} |
+ |
+} // namespace |
+ |
+HeapDumpWriter::HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator) |
+ : traced_value_(new TracedValue()), |
+ stack_frame_deduplicator_(stack_frame_deduplicator) {} |
+ |
+HeapDumpWriter::~HeapDumpWriter() {} |
+ |
+void HeapDumpWriter::InsertAllocation(const AllocationContext& context, |
+ size_t size) { |
+ bytes_by_backtrace_[context.backtrace] += size; |
+} |
+ |
+scoped_refptr<TracedValue> HeapDumpWriter::WriteHeapDump() { |
+ // Sort the backtraces by size in descending order. |
+ std::vector<std::pair<Backtrace, size_t>> sorted_by_backtrace; |
+ |
+ std::copy(bytes_by_backtrace_.begin(), bytes_by_backtrace_.end(), |
+ std::back_inserter(sorted_by_backtrace)); |
+ std::sort(sorted_by_backtrace.begin(), sorted_by_backtrace.end(), |
+ PairSizeGt<Backtrace>); |
+ |
+ traced_value_->BeginArray("entries"); |
+ |
+ // The global size, no column specified. |
+ { |
+ size_t total_size = |
+ std::accumulate(sorted_by_backtrace.begin(), sorted_by_backtrace.end(), |
+ size_t(0), PairSizeAdd<Backtrace>); |
+ traced_value_->BeginDictionary(); |
+ WriteSize(total_size); |
+ traced_value_->EndDictionary(); |
+ } |
+ |
+ // Size per backtrace. |
+ for (auto it = sorted_by_backtrace.begin(); |
+ it != sorted_by_backtrace.end(); it++) { |
+ traced_value_->BeginDictionary(); |
+ // Insert a forward reference to the backtrace that will be written to the |
+ // |stackFrames| dictionary later on. |
+ WriteStackFrameIndex(stack_frame_deduplicator_->Insert(it->first)); |
+ WriteSize(it->second); |
+ traced_value_->EndDictionary(); |
+ } |
+ |
+ traced_value_->EndArray(); // "entries" |
+ |
+ return traced_value_; |
+} |
+ |
+void HeapDumpWriter::WriteStackFrameIndex(int index) { |
+ if (index == -1) { |
+ // An empty backtrace (which will have index -1) is represented by the empty |
+ // string, because there is no leaf frame to reference in |stackFrames|. |
+ traced_value_->SetString("bt", ""); |
+ } else { |
+ // Format index of the leaf frame as a string, because |stackFrames| is a |
+ // dictionary, not an array. |
+ SStringPrintf(&buffer_, "%i", index); |
+ traced_value_->SetString("bt", buffer_); |
+ } |
+} |
+ |
+void HeapDumpWriter::WriteSize(size_t size) { |
+ // Format size as hexadecimal string into |buffer_|. |
+ SStringPrintf(&buffer_, "%" PRIx64, static_cast<uint64_t>(size)); |
+ traced_value_->SetString("size", buffer_); |
+} |
+ |
+} // namespace trace_event |
+} // namespace base |