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

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

Issue 986503002: components/metrics: Add runtime memory leak detector (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix portability issues for sizes and addresses Created 5 years, 4 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/metrics/leak_detector/leak_analyzer.h"
6
7 namespace leak_detector {
8
9 void LeakAnalyzer::AddSample(const RankedList& ranked_list) {
10 // Save the ranked entries from the previous call.
11 prev_ranked_entries_ = ranked_entries_;
12
13 // Save the current entries.
14 ranked_entries_ = ranked_list;
15
16 RankedList ranked_deltas(ranking_size_);
17 for (size_t i = 0; i < ranked_list.size(); ++i) {
18 const RankedEntry& entry = ranked_list.entry(i);
19
20 // Determine what count was recorded for this value last time.
21 uint32_t prev_count = 0;
22 if (GetPreviousCountForValue(entry.value, &prev_count))
23 ranked_deltas.Add(entry.value, entry.count - prev_count);
24 }
25
26 AnalyzeDeltas(ranked_deltas);
27 }
28
29 int LeakAnalyzer::Dump(char* buffer, const int buffer_size) const {
30 int size_remaining = buffer_size;
31 int attempted_size = 0;
32
33 // Dump the top entries.
34 if (size_remaining > 1) {
35 attempted_size =
36 snprintf(buffer, size_remaining, "***** Top %zu %s *****\n",
37 ranked_entries_.size(), string_print_->ValueTypeName(true));
38 size_remaining -= attempted_size;
39 buffer += attempted_size;
40 }
41
42 for (size_t i = 0; i < ranked_entries_.size() && size_remaining > 1; ++i) {
43 const RankedEntry& entry = ranked_entries_.entry(i);
44 if (entry.count == 0)
45 continue;
46
47 // Determine what count was recorded for this value last time.
48 char prev_entry_buffer[256];
49 prev_entry_buffer[0] = '\0';
50
51 uint32_t prev_count = 0;
52 if (GetPreviousCountForValue(entry.value, &prev_count)) {
53 snprintf(prev_entry_buffer, sizeof(prev_entry_buffer),
54 "(%10d)", entry.count - prev_count);
55 }
56
57 int attempted_size =
jar (doing other things) 2015/08/15 03:29:01 nit: Why don't you use the attempted_size declared
Simon Que 2015/08/15 23:28:31 Done.
58 snprintf(buffer, size_remaining, "%s: %10u %s\n",
59 string_print_->ValueToString(entry.value, true), entry.count,
60 prev_entry_buffer);
61 size_remaining -= attempted_size;
62 buffer += attempted_size;
63 }
64
65 // Now report the suspected sizes.
66 if (size_remaining > 1) {
67 attempted_size = snprintf(buffer, size_remaining, "Suspected %s: ",
68 string_print_->ValueTypeName(true));
69 size_remaining -= attempted_size;
70 buffer += attempted_size;
71 }
72 if (size_remaining > 1) {
73 bool wrote_suspected_leak = false;
74 for (const ValueType& leak_value : suspected_leaks_) {
75 attempted_size =
76 snprintf(buffer, size_remaining, "%s, ",
77 string_print_->ValueToString(leak_value, false));
78 size_remaining -= attempted_size;
79 buffer += attempted_size;
80 wrote_suspected_leak = true;
81 }
82 // Erase the last comma and space.
jar (doing other things) 2015/08/15 03:29:01 As mentioned in my earlier comment: How do you kno
Simon Que 2015/08/15 23:28:31 All this logging code is meant to be temporary. In
83 if (wrote_suspected_leak) {
84 buffer -= 2;
85 size_remaining += 2;
86 }
87 }
88 if (size_remaining > 1) {
89 attempted_size = snprintf(buffer, size_remaining, "\n");
90 size_remaining -= attempted_size;
91 buffer += attempted_size;
92 }
93
94 // Return the number of bytes written, excluding the null terminator.
95 return buffer_size - size_remaining;
96 }
97
98 void LeakAnalyzer::AnalyzeDeltas(const RankedList& ranked_deltas) {
99 // First, let the suspicion scores decay to deprecate older suspicions.
100 auto iter = suspected_histogram_.begin();
101 while (iter != suspected_histogram_.end()) {
102 // Suspicion score is the map value.
103 iter->second /= 2;
104
105 // Erase entries whose suspicion score reaches 0.
106 auto erase_iter = iter++;
107 if (iter->second == 0) {
108 suspected_histogram_.erase(erase_iter);
109 }
110 }
111
112 bool found_drop = false;
113 int drop_index = -1;
114 for (int i = 0; i < static_cast<int>(ranked_deltas.size()) - 1; ++i) {
jar (doing other things) 2015/08/15 03:29:01 nit: Prefer to not use casts. I'm not sure I'm fo
Simon Que 2015/08/15 23:28:31 Done.
115 const RankedEntry& entry = ranked_deltas.entry(i);
116 const RankedEntry& next_entry = ranked_deltas.entry(i + 1);
117
118 // If the first entry is 0, that means all deltas are 0 or negative. Do
119 // not treat this as a suspicion of leaks; just quit.
120 if (i == 0 && entry.count == 0)
121 break;
122
123 // Find the first major drop in values.
124 if (entry.count > next_entry.count * 2) {
125 found_drop = true;
126 drop_index = i + 1;
127 break;
128 }
129 }
130
131 // Take the pre-drop sizes and increase their suspicion score.
132 for (int i = 0; found_drop && i < drop_index; ++i) {
jar (doing other things) 2015/08/15 03:29:01 nit: This was a little confusing that you tested f
Simon Que 2015/08/15 23:28:31 Done.
133 const ValueType& value = ranked_deltas.entry(i).value;
134
135 auto iter = suspected_histogram_.find(value);
136 if (iter != suspected_histogram_.end()) {
137 iter->second += score_increase_;
138 } else if (suspected_histogram_.size() < ranking_size_) {
139 // Create a new entry.
140 suspected_histogram_[value] = score_increase_;
141 }
142 }
143
144 // Now check the leak suspicion scores. Make sure to erase the suspected
145 // leaks from the previous call.
146 suspected_leaks_.clear();
147 for (const auto& entry : suspected_histogram_) {
148 if (suspected_leaks_.size() > ranking_size_)
149 break;
150
151 // Only report suspected values that have accumulated a suspicion score.
152 // This is achieved by maintaining suspicion for several cycles, with few
153 // skips.
154 if (entry.second >= score_threshold_)
155 suspected_leaks_.emplace_back(entry.first);
156 }
157 }
158
159 bool LeakAnalyzer::GetPreviousCountForValue(const ValueType& value,
160 uint32_t* count) const {
161 // Determine what count was recorded for this value last time.
162 for (size_t i = 0; i < prev_ranked_entries_.size(); ++i) {
163 if (prev_ranked_entries_.entry(i).value == value) {
164 *count = prev_ranked_entries_.entry(i).count;
165 return true;
166 }
167 }
168 return false;
169 }
170
171 } // namespace leak_detector
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698