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

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

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

Powered by Google App Engine
This is Rietveld 408576698