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