| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "leak_detector_impl.h" | 5 #include "leak_detector_impl.h" |
| 6 | 6 |
| 7 #include <inttypes.h> | 7 #include <inttypes.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <algorithm> // For std::move | 10 #include <algorithm> // For std::move |
| 11 #include <iterator> // For std::advance | 11 #include <iterator> // For std::advance |
| 12 #include <new> | 12 #include <new> |
| 13 #include <utility> |
| 13 | 14 |
| 14 #include "base/hash.h" | 15 #include "base/hash.h" |
| 15 #include "base/process/process_handle.h" | 16 #include "base/process/process_handle.h" |
| 16 #include "components/metrics/leak_detector/call_stack_table.h" | 17 #include "components/metrics/leak_detector/call_stack_table.h" |
| 17 #include "components/metrics/leak_detector/custom_allocator.h" | 18 #include "components/metrics/leak_detector/custom_allocator.h" |
| 18 #include "components/metrics/leak_detector/ranked_set.h" | 19 #include "components/metrics/leak_detector/ranked_set.h" |
| 19 | 20 |
| 20 namespace metrics { | 21 namespace metrics { |
| 21 namespace leak_detector { | 22 namespace leak_detector { |
| 22 | 23 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 RankedSet size_ranked_set(kRankedSetSize); | 178 RankedSet size_ranked_set(kRankedSetSize); |
| 178 for (size_t i = 0; i < size_entries_.size(); ++i) { | 179 for (size_t i = 0; i < size_entries_.size(); ++i) { |
| 179 const AllocSizeEntry& entry = size_entries_[i]; | 180 const AllocSizeEntry& entry = size_entries_[i]; |
| 180 ValueType size_value(IndexToSize(i)); | 181 ValueType size_value(IndexToSize(i)); |
| 181 size_ranked_set.Add(size_value, entry.GetNetAllocs()); | 182 size_ranked_set.Add(size_value, entry.GetNetAllocs()); |
| 182 } | 183 } |
| 183 size_leak_analyzer_.AddSample(std::move(size_ranked_set)); | 184 size_leak_analyzer_.AddSample(std::move(size_ranked_set)); |
| 184 | 185 |
| 185 RecordCurrentAllocationDataInHistory(); | 186 RecordCurrentAllocationDataInHistory(); |
| 186 | 187 |
| 188 UpdateLeakCooldowns(); |
| 189 |
| 187 // Get suspected leaks by size. | 190 // Get suspected leaks by size. |
| 188 for (const ValueType& size_value : size_leak_analyzer_.suspected_leaks()) { | 191 for (const ValueType& size_value : size_leak_analyzer_.suspected_leaks()) { |
| 189 uint32_t size = size_value.size(); | 192 uint32_t size = size_value.size(); |
| 190 AllocSizeEntry* entry = &size_entries_[SizeToIndex(size)]; | 193 AllocSizeEntry* entry = &size_entries_[SizeToIndex(size)]; |
| 191 if (entry->stack_table) | 194 if (entry->stack_table) |
| 192 continue; | 195 continue; |
| 193 entry->stack_table = new (CustomAllocator::Allocate(sizeof(CallStackTable))) | 196 entry->stack_table = new (CustomAllocator::Allocate(sizeof(CallStackTable))) |
| 194 CallStackTable(call_stack_suspicion_threshold_); | 197 CallStackTable(call_stack_suspicion_threshold_); |
| 195 ++num_stack_tables_; | 198 ++num_stack_tables_; |
| 196 } | 199 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 208 continue; | 211 continue; |
| 209 | 212 |
| 210 size_t size = IndexToSize(i); | 213 size_t size = IndexToSize(i); |
| 211 | 214 |
| 212 // Get suspected leaks by call stack. | 215 // Get suspected leaks by call stack. |
| 213 stack_table->TestForLeaks(); | 216 stack_table->TestForLeaks(); |
| 214 const LeakAnalyzer& leak_analyzer = stack_table->leak_analyzer(); | 217 const LeakAnalyzer& leak_analyzer = stack_table->leak_analyzer(); |
| 215 for (const ValueType& call_stack_value : leak_analyzer.suspected_leaks()) { | 218 for (const ValueType& call_stack_value : leak_analyzer.suspected_leaks()) { |
| 216 const CallStack* call_stack = call_stack_value.call_stack(); | 219 const CallStack* call_stack = call_stack_value.call_stack(); |
| 217 | 220 |
| 221 if (!ReadyToGenerateReport(size, call_stack)) |
| 222 continue; |
| 223 |
| 218 // Return reports by storing in |*reports|. | 224 // Return reports by storing in |*reports|. |
| 219 reports->resize(reports->size() + 1); | 225 reports->resize(reports->size() + 1); |
| 220 LeakReport* report = &reports->back(); | 226 LeakReport* report = &reports->back(); |
| 221 report->alloc_size_bytes_ = size; | 227 report->alloc_size_bytes_ = size; |
| 222 report->call_stack_.resize(call_stack->depth); | 228 report->call_stack_.resize(call_stack->depth); |
| 223 for (size_t j = 0; j < call_stack->depth; ++j) { | 229 for (size_t j = 0; j < call_stack->depth; ++j) { |
| 224 report->call_stack_[j] = GetOffset(call_stack->stack[j]); | 230 report->call_stack_[j] = GetOffset(call_stack->stack[j]); |
| 225 } | 231 } |
| 226 | 232 |
| 227 StoreHistoricalDataInReport(size, call_stack, report); | 233 StoreHistoricalDataInReport(size, call_stack, report); |
| 234 ResetLeakCooldown(size, call_stack); |
| 228 } | 235 } |
| 229 } | 236 } |
| 230 } | 237 } |
| 231 | 238 |
| 232 LeakDetectorImpl::AllocSizeEntry::AllocSizeEntry() : num_allocs(0), | 239 LeakDetectorImpl::AllocSizeEntry::AllocSizeEntry() : num_allocs(0), |
| 233 num_frees(0), | 240 num_frees(0), |
| 234 stack_table(nullptr) {} | 241 stack_table(nullptr) {} |
| 235 | 242 |
| 236 LeakDetectorImpl::AllocSizeEntry::~AllocSizeEntry() {} | 243 LeakDetectorImpl::AllocSizeEntry::~AllocSizeEntry() {} |
| 237 | 244 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 while (src_iter != src.end() && dest_iter != dest->end()) { | 312 while (src_iter != src.end() && dest_iter != dest->end()) { |
| 306 const RankedSet& ranked_call_sites = *src_iter; | 313 const RankedSet& ranked_call_sites = *src_iter; |
| 307 auto find_call_site_iter = ranked_call_sites.FindCallStack(call_site); | 314 auto find_call_site_iter = ranked_call_sites.FindCallStack(call_site); |
| 308 if (find_call_site_iter != ranked_call_sites.end()) | 315 if (find_call_site_iter != ranked_call_sites.end()) |
| 309 dest_iter->count_for_call_stack = find_call_site_iter->count; | 316 dest_iter->count_for_call_stack = find_call_site_iter->count; |
| 310 ++src_iter; | 317 ++src_iter; |
| 311 ++dest_iter; | 318 ++dest_iter; |
| 312 } | 319 } |
| 313 } | 320 } |
| 314 | 321 |
| 322 bool LeakDetectorImpl::ReadyToGenerateReport( |
| 323 size_t size, |
| 324 const CallStack* call_stack) const { |
| 325 return cooldowns_per_leak_.find(std::make_pair(size, call_stack)) == |
| 326 cooldowns_per_leak_.end(); |
| 327 } |
| 328 |
| 329 void LeakDetectorImpl::ResetLeakCooldown(size_t size, |
| 330 const CallStack* call_stack) { |
| 331 cooldowns_per_leak_[std::make_pair(size, call_stack)] = |
| 332 kNumSizeEntriesInHistory; |
| 333 } |
| 334 |
| 335 void LeakDetectorImpl::UpdateLeakCooldowns() { |
| 336 for (auto iter = cooldowns_per_leak_.begin(); |
| 337 iter != cooldowns_per_leak_.end(); |
| 338 /* No iterating here */) { |
| 339 if (--iter->second > 0) { |
| 340 ++iter; |
| 341 } else { |
| 342 cooldowns_per_leak_.erase(iter++); |
| 343 } |
| 344 } |
| 345 } |
| 346 |
| 315 } // namespace leak_detector | 347 } // namespace leak_detector |
| 316 } // namespace metrics | 348 } // namespace metrics |
| OLD | NEW |