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

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: Call MergeFrom(); Update comment about repeated fields; Use braces for single-line for loops 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(),
119 report.call_stack().size() * sizeof(report.call_stack()[0]));
120 }
121 } 113 }
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);
Ilya Sherman 2016/04/14 02:30:04 nit: Curly braces here too
Simon Que 2016/04/14 03:04:49 Done.
119 proto_entry->set_count_for_call_stack(entry.count_for_call_stack);
120 }
121
122 return proto;
122 } 123 }
123 124
124 // The only instance of LeakDetector that should be used. 125 // The only instance of LeakDetector that should be used.
125 base::LazyInstance<LeakDetector>::Leaky g_instance = LAZY_INSTANCE_INITIALIZER; 126 base::LazyInstance<LeakDetector>::Leaky g_instance = LAZY_INSTANCE_INITIALIZER;
126 127
127 // Thread-specific data to be used by hook functions. 128 // Thread-specific data to be used by hook functions.
128 base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky g_hook_data_tls = 129 base::LazyInstance<base::ThreadLocalPointer<void>>::Leaky g_hook_data_tls =
129 LAZY_INSTANCE_INITIALIZER; 130 LAZY_INSTANCE_INITIALIZER;
130 131
131 // Returns the contents of |g_hook_data_tls| as a HookData structure. 132 // 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) { 147 inline void StoreHookDataToTLS(HookData hook_data) {
147 // NOTE: |alloc_size| loses its upper bit when it gets stored in the TLS here. 148 // 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. 149 // The effective max value of |alloc_size| is thus half its nominal max value.
149 uintptr_t ptr_value = 150 uintptr_t ptr_value =
150 (hook_data.entered_hook ? 1 : 0) | (hook_data.alloc_size << 1); 151 (hook_data.entered_hook ? 1 : 0) | (hook_data.alloc_size << 1);
151 g_hook_data_tls.Get().Set(reinterpret_cast<void*>(ptr_value)); 152 g_hook_data_tls.Get().Set(reinterpret_cast<void*>(ptr_value));
152 } 153 }
153 154
154 } // namespace 155 } // namespace
155 156
156 LeakDetector::LeakReport::LeakReport() {}
157
158 LeakDetector::LeakReport::LeakReport(const LeakReport& other) = default;
159
160 LeakDetector::LeakReport::~LeakReport() {}
161
162 // static 157 // static
163 LeakDetector* LeakDetector::GetInstance() { 158 LeakDetector* LeakDetector::GetInstance() {
164 return g_instance.Pointer(); 159 return g_instance.Pointer();
165 } 160 }
166 161
167 void LeakDetector::Init(float sampling_rate, 162 void LeakDetector::Init(float sampling_rate,
168 size_t max_call_stack_unwind_depth, 163 size_t max_call_stack_unwind_depth,
169 uint64_t analysis_interval_bytes, 164 uint64_t analysis_interval_bytes,
170 uint32_t size_suspicion_threshold, 165 uint32_t size_suspicion_threshold,
171 uint32_t call_stack_suspicion_threshold) { 166 uint32_t call_stack_suspicion_threshold) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 if (total_alloc_size > 262 if (total_alloc_size >
268 detector->last_analysis_alloc_size_ + analysis_interval_bytes) { 263 detector->last_analysis_alloc_size_ + analysis_interval_bytes) {
269 // Try to maintain regular intervals of size |analysis_interval_bytes_|. 264 // Try to maintain regular intervals of size |analysis_interval_bytes_|.
270 detector->last_analysis_alloc_size_ = 265 detector->last_analysis_alloc_size_ =
271 total_alloc_size - total_alloc_size % analysis_interval_bytes; 266 total_alloc_size - total_alloc_size % analysis_interval_bytes;
272 267
273 InternalVector<InternalLeakReport> leak_reports; 268 InternalVector<InternalLeakReport> leak_reports;
274 detector->impl_->TestForLeaks(&leak_reports); 269 detector->impl_->TestForLeaks(&leak_reports);
275 270
276 // Pass leak reports to observers. 271 // Pass leak reports to observers.
277 std::vector<LeakReport> leak_reports_for_observers; 272 std::vector<MemoryLeakReportProto> leak_report_protos;
278 GetReportsForObservers(leak_reports, &leak_reports_for_observers); 273 std::transform(leak_reports.begin(), leak_reports.end(),
279 detector->NotifyObservers(leak_reports_for_observers); 274 leak_report_protos.begin(), &ConvertLeakReportToProto);
275 detector->NotifyObservers(leak_report_protos);
280 } 276 }
281 } 277 }
282 278
283 { 279 {
284 // The internal memory of |stack| should be freed before setting 280 // 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 281 // |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 282 // moving the internal memory to a temporary variable that will go out of
287 // scope. 283 // scope.
288 std::vector<void*> dummy_stack; 284 std::vector<void*> dummy_stack;
289 dummy_stack.swap(stack); 285 dummy_stack.swap(stack);
(...skipping 22 matching lines...) Expand all
312 } 308 }
313 309
314 hook_data.entered_hook = false; 310 hook_data.entered_hook = false;
315 StoreHookDataToTLS(hook_data); 311 StoreHookDataToTLS(hook_data);
316 } 312 }
317 313
318 inline bool LeakDetector::ShouldSample(const void* ptr) const { 314 inline bool LeakDetector::ShouldSample(const void* ptr) const {
319 return PointerToHash(ptr) < sampling_factor_; 315 return PointerToHash(ptr) < sampling_factor_;
320 } 316 }
321 317
322 void LeakDetector::NotifyObservers(const std::vector<LeakReport>& reports) { 318 void LeakDetector::NotifyObservers(
319 const std::vector<MemoryLeakReportProto>& reports) {
323 if (reports.empty()) 320 if (reports.empty())
324 return; 321 return;
325 322
326 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { 323 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
327 content::BrowserThread::PostTask( 324 content::BrowserThread::PostTask(
328 content::BrowserThread::UI, FROM_HERE, 325 content::BrowserThread::UI, FROM_HERE,
329 base::Bind(&LeakDetector::NotifyObservers, base::Unretained(this), 326 base::Bind(&LeakDetector::NotifyObservers, base::Unretained(this),
330 reports)); 327 reports));
331 return; 328 return;
332 } 329 }
333 330
334 for (const LeakReport& report : reports) { 331 {
335 base::AutoLock lock(observers_lock_); 332 base::AutoLock lock(observers_lock_);
336 FOR_EACH_OBSERVER(Observer, observers_, OnLeakFound(report)); 333 FOR_EACH_OBSERVER(Observer, observers_, OnLeaksFound(reports));
337 } 334 }
338 } 335 }
339 336
340 } // namespace metrics 337 } // 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