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

Unified Diff: components/metrics/leak_detector/leak_detector_impl.cc

Issue 1870233003: Record call site history in LeakDetectorImpl (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add unit test coverage Created 4 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: components/metrics/leak_detector/leak_detector_impl.cc
diff --git a/components/metrics/leak_detector/leak_detector_impl.cc b/components/metrics/leak_detector/leak_detector_impl.cc
index edde53b3cac77051d3b4d8953e00b29cea890397..a2a066515348dac7464dcd32ceebf0352e7c3ba7 100644
--- a/components/metrics/leak_detector/leak_detector_impl.cc
+++ b/components/metrics/leak_detector/leak_detector_impl.cc
@@ -7,7 +7,8 @@
#include <inttypes.h>
#include <stddef.h>
-#include <algorithm>
+#include <algorithm> // For std::move
+#include <iterator> // For std::advance
#include <new>
#include "base/hash.h"
@@ -37,8 +38,14 @@ const int kNumSizeEntries = 2048;
// |LeakDetectorImpl::size_breakdown_history_|.
const int kNumSizeEntriesInHistory = 32;
-// |LeakDetectorImpl::size_breakdown_history_| can have up to this many entries.
-// Any older entries must be discarded to make way for new ones.
+// Record only the top |kNumTopCallStacksInHistory| call sites, ordered by
+// number of allocations at each site, in
+// |AllocSizeEntry::call_site_breakdown_history|.
+const int kNumTopCallStacksInHistory = 32;
+
+// |LeakDetectorImpl::size_breakdown_history_| and
+// |AllocSizeEntry::call_site_breakdown_history| can have up to this many
+// entries. Any older entries must be discarded to make way for new ones.
const int kMaxNumHistoryEntries = 32;
using ValueType = LeakDetectorValueType;
@@ -58,6 +65,11 @@ size_t IndexToSize(size_t index) {
} // namespace
+LeakDetectorImpl::LeakReport::AllocationBreakdown::AllocationBreakdown()
+ : count_for_call_stack(0) {}
+
+LeakDetectorImpl::LeakReport::AllocationBreakdown::~AllocationBreakdown() {}
+
LeakDetectorImpl::LeakReport::LeakReport() : alloc_size_bytes_(0) {}
LeakDetectorImpl::LeakReport::~LeakReport() {}
@@ -165,17 +177,7 @@ void LeakDetectorImpl::TestForLeaks(InternalVector<LeakReport>* reports) {
}
size_leak_analyzer_.AddSample(std::move(size_ranked_set));
- // Record a snapshot of the current size table.
- InternalVector<uint32_t> current_size_table_record;
- current_size_table_record.reserve(kNumSizeEntriesInHistory);
- for (const AllocSizeEntry& entry : size_entries_) {
- if (current_size_table_record.size() == kNumSizeEntriesInHistory)
- break;
- current_size_table_record.push_back(entry.GetNetAllocs());
- }
- size_breakdown_history_.emplace_back(std::move(current_size_table_record));
- if (size_breakdown_history_.size() > kMaxNumHistoryEntries)
- size_breakdown_history_.pop_front();
+ RecordCurrentAllocationDataInHistory();
// Get suspected leaks by size.
for (const ValueType& size_value : size_leak_analyzer_.suspected_leaks()) {
@@ -216,14 +218,15 @@ void LeakDetectorImpl::TestForLeaks(InternalVector<LeakReport>* reports) {
for (size_t j = 0; j < call_stack->depth; ++j) {
report->call_stack_[j] = GetOffset(call_stack->stack[j]);
}
- // Copy over the historical size data.
- report->size_breakdown_history_.reserve(size_breakdown_history_.size());
- report->size_breakdown_history_.assign(size_breakdown_history_.begin(),
- size_breakdown_history_.end());
+
+ StoreHistoricalDataInReport(size, call_stack, report);
}
}
}
+LeakDetectorImpl::AllocSizeEntry::AllocSizeEntry() {}
+LeakDetectorImpl::AllocSizeEntry::~AllocSizeEntry() {}
+
size_t LeakDetectorImpl::AddressHash::operator()(uintptr_t addr) const {
return base::Hash(reinterpret_cast<const char*>(&addr), sizeof(addr));
}
@@ -235,5 +238,71 @@ uintptr_t LeakDetectorImpl::GetOffset(const void* ptr) const {
return ptr_value;
}
+void LeakDetectorImpl::RecordCurrentAllocationDataInHistory() {
+ // Record a snapshot of the current size table.
+ InternalVector<uint32_t> current_size_table_record;
+ current_size_table_record.reserve(kNumSizeEntriesInHistory);
+ for (const AllocSizeEntry& entry : size_entries_) {
+ if (current_size_table_record.size() == kNumSizeEntriesInHistory)
+ break;
+ current_size_table_record.push_back(entry.GetNetAllocs());
+ }
+ size_breakdown_history_.emplace_back(std::move(current_size_table_record));
+ if (size_breakdown_history_.size() > kMaxNumHistoryEntries)
+ size_breakdown_history_.pop_front();
+
+ // For each allocation size that has started profiling by call site, record a
+ // snapshot of the top call sites by number of allocations.
+ for (AllocSizeEntry& entry : size_entries_) {
+ if (!entry.stack_table)
+ continue;
+ RankedSet top_call_stacks(kNumTopCallStacksInHistory);
+ entry.stack_table->GetTopCallStacks(&top_call_stacks);
+ entry.call_site_breakdown_history.push_back(std::move(top_call_stacks));
+ if (entry.call_site_breakdown_history.size() > kMaxNumHistoryEntries)
+ entry.call_site_breakdown_history.pop_front();
+ }
+}
+
+void LeakDetectorImpl::StoreHistoricalDataInReport(size_t size,
+ const CallStack* call_site,
+ LeakReport* report) {
+ using AllocationBreakdown = LeakReport::AllocationBreakdown;
+ // Copy historical allocation data into the report.
+ InternalVector<AllocationBreakdown>* dest = &report->alloc_breakdown_history_;
Will Harris 2016/04/09 20:10:23 why take this into a ptr, can't you just operate d
Simon Que 2016/04/09 21:04:11 Kind of. I am trying to make the rest of this func
Will Harris 2016/04/11 17:26:37 no that's fine. I understand why now.
+ dest->reserve(size_breakdown_history_.size());
+
+ // Store each frame of the breakdown by size.
+ for (const InternalVector<uint32_t>& breakdown : size_breakdown_history_) {
+ dest->push_back(AllocationBreakdown());
+ dest->back().counts_by_size = breakdown;
+ }
+
+ // Store the count of all allocations with size=|size| and made from call site
+ // |call_site|.
+ const InternalList<RankedSet>& src =
+ size_entries_[SizeToIndex(size)].call_site_breakdown_history;
+
+ auto src_iter = src.begin();
+ auto dest_iter = dest->begin();
+ // The call site history and the destination container may be of different
+ // sizes. Adjust their iterators so they are the same distance from the last
+ // element of each container, i.e. they will point to the frames corresponding
+ // to the same time.
+ if (src.size() > dest->size())
+ std::advance(src_iter, src.size() - dest->size());
+ else if (dest->size() > src.size())
+ std::advance(dest_iter, dest->size() - src.size());
+
+ while (src_iter != src.end() && dest_iter != dest->end()) {
+ const RankedSet& ranked_call_sites = *src_iter;
+ auto find_call_site_iter = ranked_call_sites.FindCallStack(call_site);
+ if (find_call_site_iter != ranked_call_sites.end())
+ dest_iter->count_for_call_stack = find_call_site_iter->count;
+ ++src_iter;
+ ++dest_iter;
+ }
+}
+
} // namespace leak_detector
} // namespace metrics

Powered by Google App Engine
This is Rietveld 408576698