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

Side by Side Diff: components/metrics/leak_detector/leak_detector.cc

Issue 1868193003: Store alloc history data in memory leak report protobuf (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@leak-history
Patch Set: Add dependency on protobufs to leak detector tests 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "components/metrics/leak_detector/leak_detector.h" 5 #include "components/metrics/leak_detector/leak_detector.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <algorithm>
10
9 #include "base/allocator/allocator_extension.h" 11 #include "base/allocator/allocator_extension.h"
10 #include "base/bind.h" 12 #include "base/bind.h"
11 #include "base/lazy_instance.h" 13 #include "base/lazy_instance.h"
12 #include "base/logging.h" 14 #include "base/logging.h"
13 #include "base/numerics/safe_conversions.h" 15 #include "base/numerics/safe_conversions.h"
14 #include "base/threading/thread_local.h" 16 #include "base/threading/thread_local.h"
15 #include "components/metrics/leak_detector/custom_allocator.h" 17 #include "components/metrics/leak_detector/custom_allocator.h"
16 #include "components/metrics/leak_detector/leak_detector_impl.h" 18 #include "components/metrics/leak_detector/leak_detector_impl.h"
17 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
18 20
19 #if defined(OS_CHROMEOS) 21 #if defined(OS_CHROMEOS)
20 #include <link.h> // for dl_iterate_phdr 22 #include <link.h> // for dl_iterate_phdr
21 #else 23 #else
22 #error "Getting binary mapping info is not supported on this platform." 24 #error "Getting binary mapping info is not supported on this platform."
23 #endif // defined(OS_CHROMEOS) 25 #endif // defined(OS_CHROMEOS)
24 26
25 namespace metrics { 27 namespace metrics {
26 28
27 using LeakReport = LeakDetector::LeakReport;
28 using InternalLeakReport = leak_detector::LeakDetectorImpl::LeakReport; 29 using InternalLeakReport = leak_detector::LeakDetectorImpl::LeakReport;
29 template <typename T> 30 template <typename T>
30 using InternalVector = leak_detector::LeakDetectorImpl::InternalVector<T>; 31 using InternalVector = leak_detector::LeakDetectorImpl::InternalVector<T>;
31 32
32 namespace { 33 namespace {
33 34
34 // Add the thread-local alloc size count to the shared alloc size count 35 // Add the thread-local alloc size count to the shared alloc size count
35 // (LeakDetector::total_alloc_size_) whenever the local counter reaches 36 // (LeakDetector::total_alloc_size_) whenever the local counter reaches
36 // |LeakDetector::analysis_interval_bytes_| divided by this value. Choose a 37 // |LeakDetector::analysis_interval_bytes_| divided by this value. Choose a
37 // high enough value that there is plenty of granularity, but low enough that a 38 // high enough value that there is plenty of granularity, but low enough that a
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 // Convert a pointer to a hash value. Returns only the upper eight bits. 94 // Convert a pointer to a hash value. Returns only the upper eight bits.
94 inline uint64_t PointerToHash(const void* ptr) { 95 inline uint64_t PointerToHash(const void* ptr) {
95 // The input data is the pointer address, not the location in memory pointed 96 // The input data is the pointer address, not the location in memory pointed
96 // to by the pointer. 97 // to by the pointer.
97 // The multiplier is taken from Farmhash code: 98 // The multiplier is taken from Farmhash code:
98 // https://github.com/google/farmhash/blob/master/src/farmhash.cc 99 // https://github.com/google/farmhash/blob/master/src/farmhash.cc
99 const uint64_t kMultiplier = 0x9ddfea08eb382d69ULL; 100 const uint64_t kMultiplier = 0x9ddfea08eb382d69ULL;
100 return reinterpret_cast<uint64_t>(ptr) * kMultiplier; 101 return reinterpret_cast<uint64_t>(ptr) * kMultiplier;
101 } 102 }
102 103
103 // Converts a vector of leak reports generated by LeakDetectorImpl 104 // Converts an memory leak report generated by LeakDetectorImpl
104 // (InternalLeakReport) to a vector of leak reports suitable for sending to 105 // (InternalLeakReport) to protobuf format (MemoryLeakReportProto).
105 // LeakDetector's observers (LeakReport). 106 MemoryLeakReportProto ConvertLeakReportToProto(
106 void GetReportsForObservers( 107 const InternalLeakReport& report) {
107 const InternalVector<InternalLeakReport>& leak_reports, 108 MemoryLeakReportProto proto;
108 std::vector<LeakReport>* reports_for_observers) {
109 reports_for_observers->clear();
110 reports_for_observers->reserve(leak_reports.size());
111 for (const InternalLeakReport& report : leak_reports) {
112 reports_for_observers->push_back(LeakReport());
113 LeakReport* new_report = &reports_for_observers->back();
114 109
115 new_report->alloc_size_bytes = report.alloc_size_bytes(); 110 proto.set_size_bytes(report.alloc_size_bytes());
116 if (!report.call_stack().empty()) { 111 for (auto call_stack_entry : report.call_stack()) {
117 new_report->call_stack.resize(report.call_stack().size()); 112 proto.add_call_stack(call_stack_entry);
118 memcpy(new_report->call_stack.data(), report.call_stack().data(), 113 }
119 report.call_stack().size() * sizeof(report.call_stack()[0])); 114
115 for (const auto& entry : report.alloc_breakdown_history()) {
116 auto* proto_entry = proto.add_alloc_breakdown_history();
117 for (const uint32_t count : entry.counts_by_size) {
118 proto_entry->add_counts_by_size(count);
120 } 119 }
120 proto_entry->set_count_for_call_stack(entry.count_for_call_stack);
121 } 121 }
122
123 return proto;
122 } 124 }
123 125
124 // The only instance of LeakDetector that should be used. 126 // The only instance of LeakDetector that should be used.
125 base::LazyInstance<LeakDetector>::Leaky g_instance = LAZY_INSTANCE_INITIALIZER; 127 base::LazyInstance<LeakDetector>::Leaky g_instance = LAZY_INSTANCE_INITIALIZER;
126 128
127 // Thread-specific data to be used by hook functions. 129 // Thread-specific data to be used by hook functions.
128 base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky g_hook_data_tls = 130 base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky g_hook_data_tls =
129 LAZY_INSTANCE_INITIALIZER; 131 LAZY_INSTANCE_INITIALIZER;
130 132
131 // Returns the contents of |g_hook_data_tls| as a HookData structure. 133 // Returns the contents of |g_hook_data_tls| as a HookData structure.
(...skipping 14 matching lines...) Expand all
146 inline void StoreHookDataToTLS(HookData hook_data) { 148 inline void StoreHookDataToTLS(HookData hook_data) {
147 // NOTE: |alloc_size| loses its upper bit when it gets stored in the TLS here. 149 // NOTE: |alloc_size| loses its upper bit when it gets stored in the TLS here.
148 // The effective max value of |alloc_size| is thus half its nominal max value. 150 // The effective max value of |alloc_size| is thus half its nominal max value.
149 uintptr_t ptr_value = 151 uintptr_t ptr_value =
150 (hook_data.entered_hook ? 1 : 0) | (hook_data.alloc_size << 1); 152 (hook_data.entered_hook ? 1 : 0) | (hook_data.alloc_size << 1);
151 g_hook_data_tls.Get().Set(reinterpret_cast<void*>(ptr_value)); 153 g_hook_data_tls.Get().Set(reinterpret_cast<void*>(ptr_value));
152 } 154 }
153 155
154 } // namespace 156 } // namespace
155 157
156 LeakDetector::LeakReport::LeakReport() {}
157
158 LeakDetector::LeakReport::LeakReport(const LeakReport& other) = default;
159
160 LeakDetector::LeakReport::~LeakReport() {}
161
162 // static 158 // static
163 LeakDetector* LeakDetector::GetInstance() { 159 LeakDetector* LeakDetector::GetInstance() {
164 return g_instance.Pointer(); 160 return g_instance.Pointer();
165 } 161 }
166 162
167 void LeakDetector::Init(float sampling_rate, 163 void LeakDetector::Init(float sampling_rate,
168 size_t max_call_stack_unwind_depth, 164 size_t max_call_stack_unwind_depth,
169 uint64_t analysis_interval_bytes, 165 uint64_t analysis_interval_bytes,
170 uint32_t size_suspicion_threshold, 166 uint32_t size_suspicion_threshold,
171 uint32_t call_stack_suspicion_threshold) { 167 uint32_t call_stack_suspicion_threshold) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 if (total_alloc_size > 263 if (total_alloc_size >
268 detector->last_analysis_alloc_size_ + analysis_interval_bytes) { 264 detector->last_analysis_alloc_size_ + analysis_interval_bytes) {
269 // Try to maintain regular intervals of size |analysis_interval_bytes_|. 265 // Try to maintain regular intervals of size |analysis_interval_bytes_|.
270 detector->last_analysis_alloc_size_ = 266 detector->last_analysis_alloc_size_ =
271 total_alloc_size - total_alloc_size % analysis_interval_bytes; 267 total_alloc_size - total_alloc_size % analysis_interval_bytes;
272 268
273 InternalVector<InternalLeakReport> leak_reports; 269 InternalVector<InternalLeakReport> leak_reports;
274 detector->impl_->TestForLeaks(&leak_reports); 270 detector->impl_->TestForLeaks(&leak_reports);
275 271
276 // Pass leak reports to observers. 272 // Pass leak reports to observers.
277 std::vector<LeakReport> leak_reports_for_observers; 273 std::vector<MemoryLeakReportProto> leak_report_protos;
278 GetReportsForObservers(leak_reports, &leak_reports_for_observers); 274 std::transform(leak_reports.begin(), leak_reports.end(),
279 detector->NotifyObservers(leak_reports_for_observers); 275 leak_report_protos.begin(), &ConvertLeakReportToProto);
276 detector->NotifyObservers(leak_report_protos);
280 } 277 }
281 } 278 }
282 279
283 { 280 {
284 // The internal memory of |stack| should be freed before setting 281 // The internal memory of |stack| should be freed before setting
285 // |entered_hook| to false at the end of this function. Free it here by 282 // |entered_hook| to false at the end of this function. Free it here by
286 // moving the internal memory to a temporary variable that will go out of 283 // moving the internal memory to a temporary variable that will go out of
287 // scope. 284 // scope.
288 std::vector<void*> dummy_stack; 285 std::vector<void*> dummy_stack;
289 dummy_stack.swap(stack); 286 dummy_stack.swap(stack);
(...skipping 22 matching lines...) Expand all
312 } 309 }
313 310
314 hook_data.entered_hook = false; 311 hook_data.entered_hook = false;
315 StoreHookDataToTLS(hook_data); 312 StoreHookDataToTLS(hook_data);
316 } 313 }
317 314
318 inline bool LeakDetector::ShouldSample(const void* ptr) const { 315 inline bool LeakDetector::ShouldSample(const void* ptr) const {
319 return PointerToHash(ptr) < sampling_factor_; 316 return PointerToHash(ptr) < sampling_factor_;
320 } 317 }
321 318
322 void LeakDetector::NotifyObservers(const std::vector<LeakReport>& reports) { 319 void LeakDetector::NotifyObservers(
320 const std::vector<MemoryLeakReportProto>& reports) {
323 if (reports.empty()) 321 if (reports.empty())
324 return; 322 return;
325 323
326 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { 324 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
327 content::BrowserThread::PostTask( 325 content::BrowserThread::PostTask(
328 content::BrowserThread::UI, FROM_HERE, 326 content::BrowserThread::UI, FROM_HERE,
329 base::Bind(&LeakDetector::NotifyObservers, base::Unretained(this), 327 base::Bind(&LeakDetector::NotifyObservers, base::Unretained(this),
330 reports)); 328 reports));
331 return; 329 return;
332 } 330 }
333 331
334 for (const LeakReport& report : reports) { 332 {
335 base::AutoLock lock(observers_lock_); 333 base::AutoLock lock(observers_lock_);
336 FOR_EACH_OBSERVER(Observer, observers_, OnLeakFound(report)); 334 FOR_EACH_OBSERVER(Observer, observers_, OnLeaksFound(reports));
337 } 335 }
338 } 336 }
339 337
340 } // namespace metrics 338 } // namespace metrics
OLDNEW
« no previous file with comments | « components/metrics/leak_detector/leak_detector.h ('k') | components/metrics/leak_detector/leak_detector_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698