| 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 |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 if (call_stack) { | 166 if (call_stack) { |
| 167 if (entry->stack_table) | 167 if (entry->stack_table) |
| 168 entry->stack_table->Remove(call_stack); | 168 entry->stack_table->Remove(call_stack); |
| 169 } | 169 } |
| 170 ++num_frees_; | 170 ++num_frees_; |
| 171 free_size_ += alloc_info.size; | 171 free_size_ += alloc_info.size; |
| 172 | 172 |
| 173 address_map_.erase(iter); | 173 address_map_.erase(iter); |
| 174 } | 174 } |
| 175 | 175 |
| 176 void LeakDetectorImpl::TestForLeaks(InternalVector<LeakReport>* reports, | 176 void LeakDetectorImpl::TestForLeaks(InternalVector<LeakReport>* reports) { |
| 177 size_t timestamp) { | |
| 178 // Add net alloc counts for each size to a ranked list. | 177 // Add net alloc counts for each size to a ranked list. |
| 179 RankedSet size_ranked_set(kRankedSetSize); | 178 RankedSet size_ranked_set(kRankedSetSize); |
| 180 for (size_t i = 0; i < size_entries_.size(); ++i) { | 179 for (size_t i = 0; i < size_entries_.size(); ++i) { |
| 181 const AllocSizeEntry& entry = size_entries_[i]; | 180 const AllocSizeEntry& entry = size_entries_[i]; |
| 182 ValueType size_value(IndexToSize(i)); | 181 ValueType size_value(IndexToSize(i)); |
| 183 size_ranked_set.Add(size_value, entry.GetNetAllocs()); | 182 size_ranked_set.Add(size_value, entry.GetNetAllocs()); |
| 184 } | 183 } |
| 185 size_leak_analyzer_.AddSample(std::move(size_ranked_set)); | 184 size_leak_analyzer_.AddSample(std::move(size_ranked_set)); |
| 186 | 185 |
| 187 RecordCurrentAllocationDataInHistory(timestamp); | 186 RecordCurrentAllocationDataInHistory(); |
| 188 | 187 |
| 189 UpdateLeakCooldowns(); | 188 UpdateLeakCooldowns(); |
| 190 | 189 |
| 191 // Get suspected leaks by size. | 190 // Get suspected leaks by size. |
| 192 for (const ValueType& size_value : size_leak_analyzer_.suspected_leaks()) { | 191 for (const ValueType& size_value : size_leak_analyzer_.suspected_leaks()) { |
| 193 uint32_t size = size_value.size(); | 192 uint32_t size = size_value.size(); |
| 194 AllocSizeEntry* entry = &size_entries_[SizeToIndex(size)]; | 193 AllocSizeEntry* entry = &size_entries_[SizeToIndex(size)]; |
| 195 if (entry->stack_table) | 194 if (entry->stack_table) |
| 196 continue; | 195 continue; |
| 197 entry->stack_table = new (CustomAllocator::Allocate(sizeof(CallStackTable))) | 196 entry->stack_table = new (CustomAllocator::Allocate(sizeof(CallStackTable))) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 224 | 223 |
| 225 // Return reports by storing in |*reports|. | 224 // Return reports by storing in |*reports|. |
| 226 reports->resize(reports->size() + 1); | 225 reports->resize(reports->size() + 1); |
| 227 LeakReport* report = &reports->back(); | 226 LeakReport* report = &reports->back(); |
| 228 report->alloc_size_bytes_ = size; | 227 report->alloc_size_bytes_ = size; |
| 229 report->call_stack_.resize(call_stack->depth); | 228 report->call_stack_.resize(call_stack->depth); |
| 230 for (size_t j = 0; j < call_stack->depth; ++j) { | 229 for (size_t j = 0; j < call_stack->depth; ++j) { |
| 231 report->call_stack_[j] = GetOffset(call_stack->stack[j]); | 230 report->call_stack_[j] = GetOffset(call_stack->stack[j]); |
| 232 } | 231 } |
| 233 | 232 |
| 234 StoreHistoricalDataInReport(size, call_stack, report, timestamp); | 233 StoreHistoricalDataInReport(size, call_stack, report); |
| 235 ResetLeakCooldown(size, call_stack); | 234 ResetLeakCooldown(size, call_stack); |
| 236 } | 235 } |
| 237 } | 236 } |
| 238 } | 237 } |
| 239 | 238 |
| 240 LeakDetectorImpl::AllocSizeEntry::AllocSizeEntry() : num_allocs(0), | 239 LeakDetectorImpl::AllocSizeEntry::AllocSizeEntry() : num_allocs(0), |
| 241 num_frees(0), | 240 num_frees(0), |
| 242 stack_table(nullptr) {} | 241 stack_table(nullptr) {} |
| 243 | 242 |
| 244 LeakDetectorImpl::AllocSizeEntry::~AllocSizeEntry() {} | 243 LeakDetectorImpl::AllocSizeEntry::~AllocSizeEntry() {} |
| 245 | 244 |
| 246 size_t LeakDetectorImpl::AddressHash::operator()(uintptr_t addr) const { | 245 size_t LeakDetectorImpl::AddressHash::operator()(uintptr_t addr) const { |
| 247 return base::Hash(reinterpret_cast<const char*>(&addr), sizeof(addr)); | 246 return base::Hash(reinterpret_cast<const char*>(&addr), sizeof(addr)); |
| 248 } | 247 } |
| 249 | 248 |
| 250 uintptr_t LeakDetectorImpl::GetOffset(const void* ptr) const { | 249 uintptr_t LeakDetectorImpl::GetOffset(const void* ptr) const { |
| 251 uintptr_t ptr_value = reinterpret_cast<uintptr_t>(ptr); | 250 uintptr_t ptr_value = reinterpret_cast<uintptr_t>(ptr); |
| 252 if (ptr_value >= mapping_addr_ && ptr_value < mapping_addr_ + mapping_size_) | 251 if (ptr_value >= mapping_addr_ && ptr_value < mapping_addr_ + mapping_size_) |
| 253 return ptr_value - mapping_addr_; | 252 return ptr_value - mapping_addr_; |
| 254 return UINTPTR_MAX; | 253 return UINTPTR_MAX; |
| 255 } | 254 } |
| 256 | 255 |
| 257 void LeakDetectorImpl::RecordCurrentAllocationDataInHistory(size_t timestamp) { | 256 void LeakDetectorImpl::RecordCurrentAllocationDataInHistory() { |
| 258 // Record a snapshot of the current size table. | 257 // Record a snapshot of the current size table. |
| 259 InternalVector<uint32_t> current_size_table_record; | 258 InternalVector<uint32_t> current_size_table_record; |
| 260 current_size_table_record.reserve(kNumSizeEntriesInHistory); | 259 current_size_table_record.reserve(kNumSizeEntriesInHistory); |
| 261 for (const AllocSizeEntry& entry : size_entries_) { | 260 for (const AllocSizeEntry& entry : size_entries_) { |
| 262 if (current_size_table_record.size() == kNumSizeEntriesInHistory) | 261 if (current_size_table_record.size() == kNumSizeEntriesInHistory) |
| 263 break; | 262 break; |
| 264 current_size_table_record.push_back(entry.GetNetAllocs()); | 263 current_size_table_record.push_back(entry.GetNetAllocs()); |
| 265 } | 264 } |
| 266 size_breakdown_history_.emplace_back(std::move(current_size_table_record)); | 265 size_breakdown_history_.emplace_back(std::move(current_size_table_record)); |
| 267 if (size_breakdown_history_.size() > kMaxNumHistoryEntries) | 266 if (size_breakdown_history_.size() > kMaxNumHistoryEntries) |
| 268 size_breakdown_history_.pop_front(); | 267 size_breakdown_history_.pop_front(); |
| 269 | 268 |
| 270 // For each allocation size that has started profiling by call site, record a | 269 // For each allocation size that has started profiling by call site, record a |
| 271 // snapshot of the top call sites by number of allocations. | 270 // snapshot of the top call sites by number of allocations. |
| 272 for (AllocSizeEntry& entry : size_entries_) { | 271 for (AllocSizeEntry& entry : size_entries_) { |
| 273 if (!entry.stack_table) | 272 if (!entry.stack_table) |
| 274 continue; | 273 continue; |
| 275 RankedSet top_call_stacks(kNumTopCallStacksInHistory); | 274 RankedSet top_call_stacks(kNumTopCallStacksInHistory); |
| 276 entry.stack_table->GetTopCallStacks(&top_call_stacks); | 275 entry.stack_table->GetTopCallStacks(&top_call_stacks); |
| 277 entry.stack_table->UpdateLastDropInfo(timestamp); | |
| 278 entry.call_site_breakdown_history.push_back(std::move(top_call_stacks)); | 276 entry.call_site_breakdown_history.push_back(std::move(top_call_stacks)); |
| 279 if (entry.call_site_breakdown_history.size() > kMaxNumHistoryEntries) | 277 if (entry.call_site_breakdown_history.size() > kMaxNumHistoryEntries) |
| 280 entry.call_site_breakdown_history.pop_front(); | 278 entry.call_site_breakdown_history.pop_front(); |
| 281 } | 279 } |
| 282 } | 280 } |
| 283 | 281 |
| 284 void LeakDetectorImpl::StoreHistoricalDataInReport(size_t size, | 282 void LeakDetectorImpl::StoreHistoricalDataInReport(size_t size, |
| 285 const CallStack* call_site, | 283 const CallStack* call_site, |
| 286 LeakReport* report, | 284 LeakReport* report) { |
| 287 size_t timestamp) { | |
| 288 using AllocationBreakdown = LeakReport::AllocationBreakdown; | 285 using AllocationBreakdown = LeakReport::AllocationBreakdown; |
| 289 // Copy historical allocation data into the report. | 286 // Copy historical allocation data into the report. |
| 290 InternalVector<AllocationBreakdown>* dest = &report->alloc_breakdown_history_; | 287 InternalVector<AllocationBreakdown>* dest = &report->alloc_breakdown_history_; |
| 291 dest->reserve(size_breakdown_history_.size()); | 288 dest->reserve(size_breakdown_history_.size()); |
| 292 | 289 |
| 293 // Store each frame of the breakdown by size. | 290 // Store each frame of the breakdown by size. |
| 294 for (const InternalVector<uint32_t>& breakdown : size_breakdown_history_) { | 291 for (const InternalVector<uint32_t>& breakdown : size_breakdown_history_) { |
| 295 dest->push_back(AllocationBreakdown()); | 292 dest->push_back(AllocationBreakdown()); |
| 296 dest->back().counts_by_size = breakdown; | 293 dest->back().counts_by_size = breakdown; |
| 297 } | 294 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 313 std::advance(dest_iter, dest->size() - src.size()); | 310 std::advance(dest_iter, dest->size() - src.size()); |
| 314 | 311 |
| 315 while (src_iter != src.end() && dest_iter != dest->end()) { | 312 while (src_iter != src.end() && dest_iter != dest->end()) { |
| 316 const RankedSet& ranked_call_sites = *src_iter; | 313 const RankedSet& ranked_call_sites = *src_iter; |
| 317 auto find_call_site_iter = ranked_call_sites.FindCallStack(call_site); | 314 auto find_call_site_iter = ranked_call_sites.FindCallStack(call_site); |
| 318 if (find_call_site_iter != ranked_call_sites.end()) | 315 if (find_call_site_iter != ranked_call_sites.end()) |
| 319 dest_iter->count_for_call_stack = find_call_site_iter->count; | 316 dest_iter->count_for_call_stack = find_call_site_iter->count; |
| 320 ++src_iter; | 317 ++src_iter; |
| 321 ++dest_iter; | 318 ++dest_iter; |
| 322 } | 319 } |
| 323 | |
| 324 size_entries_[SizeToIndex(size)].stack_table->GetLastUptrendInfo( | |
| 325 call_site, timestamp, &report->num_rising_intervals_, | |
| 326 &report->num_allocs_increase_); | |
| 327 } | 320 } |
| 328 | 321 |
| 329 bool LeakDetectorImpl::ReadyToGenerateReport( | 322 bool LeakDetectorImpl::ReadyToGenerateReport( |
| 330 size_t size, | 323 size_t size, |
| 331 const CallStack* call_stack) const { | 324 const CallStack* call_stack) const { |
| 332 return cooldowns_per_leak_.find(std::make_pair(size, call_stack)) == | 325 return cooldowns_per_leak_.find(std::make_pair(size, call_stack)) == |
| 333 cooldowns_per_leak_.end(); | 326 cooldowns_per_leak_.end(); |
| 334 } | 327 } |
| 335 | 328 |
| 336 void LeakDetectorImpl::ResetLeakCooldown(size_t size, | 329 void LeakDetectorImpl::ResetLeakCooldown(size_t size, |
| 337 const CallStack* call_stack) { | 330 const CallStack* call_stack) { |
| 338 cooldowns_per_leak_[std::make_pair(size, call_stack)] = | 331 cooldowns_per_leak_[std::make_pair(size, call_stack)] = |
| 339 kNumSizeEntriesInHistory; | 332 kNumSizeEntriesInHistory; |
| 340 } | 333 } |
| 341 | 334 |
| 342 void LeakDetectorImpl::UpdateLeakCooldowns() { | 335 void LeakDetectorImpl::UpdateLeakCooldowns() { |
| 343 for (auto iter = cooldowns_per_leak_.begin(); | 336 for (auto iter = cooldowns_per_leak_.begin(); |
| 344 iter != cooldowns_per_leak_.end(); | 337 iter != cooldowns_per_leak_.end(); |
| 345 /* No iterating here */) { | 338 /* No iterating here */) { |
| 346 if (--iter->second > 0) { | 339 if (--iter->second > 0) { |
| 347 ++iter; | 340 ++iter; |
| 348 } else { | 341 } else { |
| 349 cooldowns_per_leak_.erase(iter++); | 342 cooldowns_per_leak_.erase(iter++); |
| 350 } | 343 } |
| 351 } | 344 } |
| 352 } | 345 } |
| 353 | 346 |
| 354 } // namespace leak_detector | 347 } // namespace leak_detector |
| 355 } // namespace metrics | 348 } // namespace metrics |
| OLD | NEW |