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

Side by Side Diff: base/metrics/histogram.cc

Issue 10834011: Refactor of Histogram related code (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 // Histogram is an object that aggregates statistics, and can summarize them in 5 // Histogram is an object that aggregates statistics, and can summarize them in
6 // various forms, including ASCII graphical, HTML, and numerically (as a 6 // various forms, including ASCII graphical, HTML, and numerically (as a
7 // vector of numbers corresponding to each of the aggregating buckets). 7 // vector of numbers corresponding to each of the aggregating buckets).
8 // See header file for details and examples. 8 // See header file for details and examples.
9 9
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 11
12 #include <math.h> 12 #include <math.h>
13 13
14 #include <algorithm> 14 #include <algorithm>
15 #include <string> 15 #include <string>
16 16
17 #include "base/logging.h" 17 #include "base/logging.h"
18 #include "base/metrics/statistics_recorder.h" 18 #include "base/metrics/statistics_recorder.h"
19 #include "base/pickle.h" 19 #include "base/pickle.h"
20 #include "base/stringprintf.h" 20 #include "base/stringprintf.h"
21 #include "base/synchronization/lock.h" 21 #include "base/synchronization/lock.h"
22 22
23 using std::string;
24 using std::vector;
25
23 namespace base { 26 namespace base {
24 27
25 // Static table of checksums for all possible 8 bit bytes. 28 typedef HistogramBase::Count Count;
26 const uint32 Histogram::kCrcTable[256] = {0x0, 0x77073096L, 0xee0e612cL, 29 typedef HistogramBase::Sample Sample;
27 0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L,
28 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
29 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL,
30 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL,
31 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
32 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL,
33 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
34 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L,
35 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL,
36 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
37 0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L,
38 0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
39 0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L,
40 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L,
41 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
42 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L,
43 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
44 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL,
45 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L,
46 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
47 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L,
48 0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
49 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL,
50 0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L,
51 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
52 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L,
53 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
54 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L,
55 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL,
56 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
57 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L,
58 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
59 0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L,
60 0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L,
61 0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
62 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL,
63 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
64 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL,
65 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L,
66 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
67 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL,
68 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
69 0x2d02ef8dL,
70 };
71
72 typedef Histogram::Count Count;
73 30
74 // static 31 // static
75 const size_t Histogram::kBucketCount_MAX = 16384u; 32 const size_t Histogram::kBucketCount_MAX = 16384u;
76 33
77 Histogram* Histogram::FactoryGet(const std::string& name, 34 Histogram* Histogram::FactoryGet(const string& name,
78 Sample minimum, 35 Sample minimum,
79 Sample maximum, 36 Sample maximum,
80 size_t bucket_count, 37 size_t bucket_count,
81 Flags flags) { 38 Flags flags) {
82 // Defensive code. 39 CHECK(InspectConstructionArguments(name, &minimum, &maximum, &bucket_count));
83 if (minimum < 1)
84 minimum = 1;
85 if (maximum > kSampleType_MAX - 1)
86 maximum = kSampleType_MAX - 1;
87
88 DCHECK_GT(maximum, minimum);
89 DCHECK_GT((Sample) bucket_count, 2);
90 DCHECK_LE((Sample) bucket_count, maximum - minimum + 2);
91 40
92 Histogram* histogram = StatisticsRecorder::FindHistogram(name); 41 Histogram* histogram = StatisticsRecorder::FindHistogram(name);
93 if (!histogram) { 42 if (!histogram) {
94 // Extra variable is not needed... but this keeps this section basically
95 // identical to other derived classes in this file (and compiler will
96 // optimize away the extra variable.
97 // To avoid racy destruction at shutdown, the following will be leaked. 43 // To avoid racy destruction at shutdown, the following will be leaked.
44 BucketRanges* ranges = new BucketRanges(bucket_count + 1);
45 InitializeBucketRanges(minimum, maximum, bucket_count, ranges);
46 const BucketRanges* registered_ranges =
47 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
48
98 Histogram* tentative_histogram = 49 Histogram* tentative_histogram =
99 new Histogram(name, minimum, maximum, bucket_count); 50 new Histogram(name, minimum, maximum, bucket_count, registered_ranges);
100 tentative_histogram->InitializeBucketRange();
101 tentative_histogram->SetFlags(flags); 51 tentative_histogram->SetFlags(flags);
102 histogram = 52 histogram =
103 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); 53 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
104 } 54 }
105 55
106 DCHECK_EQ(HISTOGRAM, histogram->histogram_type()); 56 CHECK_EQ(HISTOGRAM, histogram->histogram_type());
107 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); 57 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count));
108 return histogram; 58 return histogram;
109 } 59 }
110 60
111 Histogram* Histogram::FactoryTimeGet(const std::string& name, 61 Histogram* Histogram::FactoryTimeGet(const string& name,
112 TimeDelta minimum, 62 TimeDelta minimum,
113 TimeDelta maximum, 63 TimeDelta maximum,
114 size_t bucket_count, 64 size_t bucket_count,
115 Flags flags) { 65 Flags flags) {
116 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), 66 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
117 bucket_count, flags); 67 bucket_count, flags);
118 } 68 }
119 69
120 TimeTicks Histogram::DebugNow() { 70 TimeTicks Histogram::DebugNow() {
121 #ifndef NDEBUG 71 #ifndef NDEBUG
122 return TimeTicks::Now(); 72 return TimeTicks::Now();
123 #else 73 #else
124 return TimeTicks(); 74 return TimeTicks();
125 #endif 75 #endif
126 } 76 }
127 77
128 void Histogram::Add(int value) {
129 if (value > kSampleType_MAX - 1)
130 value = kSampleType_MAX - 1;
131 if (value < 0)
132 value = 0;
133 size_t index = BucketIndex(value);
134 DCHECK_GE(value, ranges(index));
135 DCHECK_LT(value, ranges(index + 1));
136 Accumulate(value, 1, index);
137 }
138
139 void Histogram::AddBoolean(bool value) {
140 DCHECK(false);
141 }
142
143 void Histogram::AddSampleSet(const SampleSet& sample) {
144 sample_.Add(sample);
145 }
146
147 void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
148 DCHECK(false);
149 }
150
151 // The following methods provide a graphical histogram display.
152 void Histogram::WriteHTMLGraph(std::string* output) const {
153 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
154 output->append("<PRE>");
155 WriteAsciiImpl(true, "<br>", output);
156 output->append("</PRE>");
157 }
158
159 void Histogram::WriteAscii(std::string* output) const {
160 WriteAsciiImpl(true, "\n", output);
161 }
162
163 void Histogram::WriteAsciiImpl(bool graph_it,
164 const std::string& newline,
165 std::string* output) const {
166 // Get local (stack) copies of all effectively volatile class data so that we
167 // are consistent across our output activities.
168 SampleSet snapshot;
169 SnapshotSample(&snapshot);
170 Count sample_count = snapshot.TotalCount();
171
172 WriteAsciiHeader(snapshot, sample_count, output);
173 output->append(newline);
174
175 // Prepare to normalize graphical rendering of bucket contents.
176 double max_size = 0;
177 if (graph_it)
178 max_size = GetPeakBucketSize(snapshot);
179
180 // Calculate space needed to print bucket range numbers. Leave room to print
181 // nearly the largest bucket range without sliding over the histogram.
182 size_t largest_non_empty_bucket = bucket_count() - 1;
183 while (0 == snapshot.counts(largest_non_empty_bucket)) {
184 if (0 == largest_non_empty_bucket)
185 break; // All buckets are empty.
186 --largest_non_empty_bucket;
187 }
188
189 // Calculate largest print width needed for any of our bucket range displays.
190 size_t print_width = 1;
191 for (size_t i = 0; i < bucket_count(); ++i) {
192 if (snapshot.counts(i)) {
193 size_t width = GetAsciiBucketRange(i).size() + 1;
194 if (width > print_width)
195 print_width = width;
196 }
197 }
198
199 int64 remaining = sample_count;
200 int64 past = 0;
201 // Output the actual histogram graph.
202 for (size_t i = 0; i < bucket_count(); ++i) {
203 Count current = snapshot.counts(i);
204 if (!current && !PrintEmptyBucket(i))
205 continue;
206 remaining -= current;
207 std::string range = GetAsciiBucketRange(i);
208 output->append(range);
209 for (size_t j = 0; range.size() + j < print_width + 1; ++j)
210 output->push_back(' ');
211 if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) {
212 while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1))
213 ++i;
214 output->append("... ");
215 output->append(newline);
216 continue; // No reason to plot emptiness.
217 }
218 double current_size = GetBucketSize(current, i);
219 if (graph_it)
220 WriteAsciiBucketGraph(current_size, max_size, output);
221 WriteAsciiBucketContext(past, current, remaining, i, output);
222 output->append(newline);
223 past += current;
224 }
225 DCHECK_EQ(sample_count, past);
226 }
227
228 // static 78 // static
229 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, 79 string Histogram::SerializeHistogramInfo(const Histogram& histogram,
230 const SampleSet& snapshot) { 80 const SampleSet& snapshot) {
231 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); 81 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
82 DCHECK(histogram.bucket_ranges()->HasValidChecksum());
232 83
233 Pickle pickle; 84 Pickle pickle;
234 pickle.WriteString(histogram.histogram_name()); 85 pickle.WriteString(histogram.histogram_name());
235 pickle.WriteInt(histogram.declared_min()); 86 pickle.WriteInt(histogram.declared_min());
236 pickle.WriteInt(histogram.declared_max()); 87 pickle.WriteInt(histogram.declared_max());
237 pickle.WriteUInt64(histogram.bucket_count()); 88 pickle.WriteUInt64(histogram.bucket_count());
238 pickle.WriteUInt32(histogram.range_checksum());
239 pickle.WriteInt(histogram.histogram_type()); 89 pickle.WriteInt(histogram.histogram_type());
240 pickle.WriteInt(histogram.flags()); 90 pickle.WriteInt(histogram.flags());
241 91
242 snapshot.Serialize(&pickle); 92 snapshot.Serialize(&pickle);
243 93
244 histogram.SerializeRanges(&pickle); 94 histogram.SerializeRanges(&pickle);
245 95
246 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); 96 return string(static_cast<const char*>(pickle.data()), pickle.size());
247 } 97 }
248 98
249 // static 99 // static
250 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { 100 bool Histogram::DeserializeHistogramInfo(const string& histogram_info) {
251 if (histogram_info.empty()) { 101 if (histogram_info.empty()) {
252 return false; 102 return false;
253 } 103 }
254 104
255 Pickle pickle(histogram_info.data(), 105 Pickle pickle(histogram_info.data(),
256 static_cast<int>(histogram_info.size())); 106 static_cast<int>(histogram_info.size()));
257 std::string histogram_name; 107 string histogram_name;
258 int declared_min; 108 int declared_min;
259 int declared_max; 109 int declared_max;
260 uint64 bucket_count; 110 uint64 bucket_count;
261 uint32 range_checksum;
262 int histogram_type; 111 int histogram_type;
263 int pickle_flags; 112 int pickle_flags;
264 SampleSet sample; 113 SampleSet sample;
265 114
266 PickleIterator iter(pickle); 115 PickleIterator iter(pickle);
267 if (!iter.ReadString(&histogram_name) || 116 if (!iter.ReadString(&histogram_name) ||
268 !iter.ReadInt(&declared_min) || 117 !iter.ReadInt(&declared_min) ||
269 !iter.ReadInt(&declared_max) || 118 !iter.ReadInt(&declared_max) ||
270 !iter.ReadUInt64(&bucket_count) || 119 !iter.ReadUInt64(&bucket_count) ||
271 !iter.ReadUInt32(&range_checksum) ||
272 !iter.ReadInt(&histogram_type) || 120 !iter.ReadInt(&histogram_type) ||
273 !iter.ReadInt(&pickle_flags) || 121 !iter.ReadInt(&pickle_flags) ||
274 !sample.Histogram::SampleSet::Deserialize(&iter)) { 122 !sample.Histogram::SampleSet::Deserialize(&iter)) {
275 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; 123 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
276 return false; 124 return false;
277 } 125 }
278 126
279 DCHECK(pickle_flags & kIPCSerializationSourceFlag); 127 DCHECK(pickle_flags & kIPCSerializationSourceFlag);
280 // Since these fields may have come from an untrusted renderer, do additional 128 // Since these fields may have come from an untrusted renderer, do additional
281 // checks above and beyond those in Histogram::Initialize() 129 // checks above and beyond those in Histogram::Initialize()
(...skipping 11 matching lines...) Expand all
293 141
294 if (histogram_type == HISTOGRAM) { 142 if (histogram_type == HISTOGRAM) {
295 render_histogram = Histogram::FactoryGet( 143 render_histogram = Histogram::FactoryGet(
296 histogram_name, declared_min, declared_max, bucket_count, flags); 144 histogram_name, declared_min, declared_max, bucket_count, flags);
297 } else if (histogram_type == LINEAR_HISTOGRAM) { 145 } else if (histogram_type == LINEAR_HISTOGRAM) {
298 render_histogram = LinearHistogram::FactoryGet( 146 render_histogram = LinearHistogram::FactoryGet(
299 histogram_name, declared_min, declared_max, bucket_count, flags); 147 histogram_name, declared_min, declared_max, bucket_count, flags);
300 } else if (histogram_type == BOOLEAN_HISTOGRAM) { 148 } else if (histogram_type == BOOLEAN_HISTOGRAM) {
301 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags); 149 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
302 } else if (histogram_type == CUSTOM_HISTOGRAM) { 150 } else if (histogram_type == CUSTOM_HISTOGRAM) {
303 std::vector<Histogram::Sample> sample_ranges(bucket_count); 151 vector<Sample> sample_ranges(bucket_count);
304 if (!CustomHistogram::DeserializeRanges(&iter, &sample_ranges)) { 152 if (!CustomHistogram::DeserializeRanges(&iter, &sample_ranges)) {
305 DLOG(ERROR) << "Pickle error decoding ranges: " << histogram_name; 153 DLOG(ERROR) << "Pickle error decoding ranges: " << histogram_name;
306 return false; 154 return false;
307 } 155 }
308 render_histogram = 156 render_histogram =
309 CustomHistogram::FactoryGet(histogram_name, sample_ranges, flags); 157 CustomHistogram::FactoryGet(histogram_name, sample_ranges, flags);
310 } else { 158 } else {
311 DLOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " 159 DLOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
312 << histogram_type; 160 << histogram_type;
313 return false; 161 return false;
314 } 162 }
315 163
316 DCHECK_EQ(render_histogram->declared_min(), declared_min); 164 DCHECK_EQ(render_histogram->declared_min(), declared_min);
317 DCHECK_EQ(render_histogram->declared_max(), declared_max); 165 DCHECK_EQ(render_histogram->declared_max(), declared_max);
318 DCHECK_EQ(render_histogram->bucket_count(), bucket_count); 166 DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
319 DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
jar (doing other things) 2012/08/01 00:26:10 Perhaps this should be preserved, induce a return
kaiwang 2012/08/01 04:13:21 Done.
320 DCHECK_EQ(render_histogram->histogram_type(), histogram_type); 167 DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
321 168
322 if (render_histogram->flags() & kIPCSerializationSourceFlag) { 169 if (render_histogram->flags() & kIPCSerializationSourceFlag) {
323 DVLOG(1) << "Single process mode, histogram observed and not copied: " 170 DVLOG(1) << "Single process mode, histogram observed and not copied: "
324 << histogram_name; 171 << histogram_name;
325 } else { 172 } else {
326 DCHECK_EQ(flags & render_histogram->flags(), flags); 173 DCHECK_EQ(flags & render_histogram->flags(), flags);
327 render_histogram->AddSampleSet(sample); 174 render_histogram->AddSampleSet(sample);
328 } 175 }
329 176
330 return true; 177 return true;
331 } 178 }
332 179
180 void Histogram::Add(int value) {
181 if (value > kSampleType_MAX - 1)
182 value = kSampleType_MAX - 1;
183 if (value < 0)
184 value = 0;
185 size_t index = BucketIndex(value);
186 DCHECK_GE(value, ranges(index));
187 DCHECK_LT(value, ranges(index + 1));
188 Accumulate(value, 1, index);
189 }
190
191 void Histogram::AddBoolean(bool value) {
192 DCHECK(false);
193 }
194
195 void Histogram::AddSampleSet(const SampleSet& sample) {
196 sample_.Add(sample);
197 }
198
199 void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
200 DCHECK(false);
201 }
202
203 // The following methods provide a graphical histogram display.
204 void Histogram::WriteHTMLGraph(string* output) const {
205 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
206 output->append("<PRE>");
207 WriteAsciiImpl(true, "<br>", output);
208 output->append("</PRE>");
209 }
210
211 void Histogram::WriteAscii(string* output) const {
212 WriteAsciiImpl(true, "\n", output);
213 }
214
215 void Histogram::WriteAsciiImpl(bool graph_it,
216 const string& newline,
217 string* output) const {
218 // Get local (stack) copies of all effectively volatile class data so that we
219 // are consistent across our output activities.
220 SampleSet snapshot;
221 SnapshotSample(&snapshot);
222 Count sample_count = snapshot.TotalCount();
223
224 WriteAsciiHeader(snapshot, sample_count, output);
225 output->append(newline);
226
227 // Prepare to normalize graphical rendering of bucket contents.
228 double max_size = 0;
229 if (graph_it)
230 max_size = GetPeakBucketSize(snapshot);
231
232 // Calculate space needed to print bucket range numbers. Leave room to print
233 // nearly the largest bucket range without sliding over the histogram.
234 size_t largest_non_empty_bucket = bucket_count() - 1;
235 while (0 == snapshot.counts(largest_non_empty_bucket)) {
236 if (0 == largest_non_empty_bucket)
237 break; // All buckets are empty.
238 --largest_non_empty_bucket;
239 }
240
241 // Calculate largest print width needed for any of our bucket range displays.
242 size_t print_width = 1;
243 for (size_t i = 0; i < bucket_count(); ++i) {
244 if (snapshot.counts(i)) {
245 size_t width = GetAsciiBucketRange(i).size() + 1;
246 if (width > print_width)
247 print_width = width;
248 }
249 }
250
251 int64 remaining = sample_count;
252 int64 past = 0;
253 // Output the actual histogram graph.
254 for (size_t i = 0; i < bucket_count(); ++i) {
255 Count current = snapshot.counts(i);
256 if (!current && !PrintEmptyBucket(i))
257 continue;
258 remaining -= current;
259 string range = GetAsciiBucketRange(i);
260 output->append(range);
261 for (size_t j = 0; range.size() + j < print_width + 1; ++j)
262 output->push_back(' ');
263 if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) {
264 while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1))
265 ++i;
266 output->append("... ");
267 output->append(newline);
268 continue; // No reason to plot emptiness.
269 }
270 double current_size = GetBucketSize(current, i);
271 if (graph_it)
272 WriteAsciiBucketGraph(current_size, max_size, output);
273 WriteAsciiBucketContext(past, current, remaining, i, output);
274 output->append(newline);
275 past += current;
276 }
277 DCHECK_EQ(sample_count, past);
278 }
279
333 //------------------------------------------------------------------------------ 280 //------------------------------------------------------------------------------
334 // Methods for the validating a sample and a related histogram. 281 // Methods for the validating a sample and a related histogram.
335 //------------------------------------------------------------------------------ 282 //------------------------------------------------------------------------------
336 283
337 Histogram::Inconsistencies Histogram::FindCorruption( 284 Histogram::Inconsistencies Histogram::FindCorruption(
338 const SampleSet& snapshot) const { 285 const SampleSet& snapshot) const {
339 int inconsistencies = NO_INCONSISTENCIES; 286 int inconsistencies = NO_INCONSISTENCIES;
340 Sample previous_range = -1; // Bottom range is always 0. 287 Sample previous_range = -1; // Bottom range is always 0.
341 int64 count = 0; 288 int64 count = 0;
342 for (size_t index = 0; index < bucket_count(); ++index) { 289 for (size_t index = 0; index < bucket_count(); ++index) {
343 count += snapshot.counts(index); 290 count += snapshot.counts(index);
344 int new_range = ranges(index); 291 int new_range = ranges(index);
345 if (previous_range >= new_range) 292 if (previous_range >= new_range)
346 inconsistencies |= BUCKET_ORDER_ERROR; 293 inconsistencies |= BUCKET_ORDER_ERROR;
347 previous_range = new_range; 294 previous_range = new_range;
348 } 295 }
349 296
350 if (!HasValidRangeChecksum()) 297 if (!bucket_ranges()->HasValidChecksum())
351 inconsistencies |= RANGE_CHECKSUM_ERROR; 298 inconsistencies |= RANGE_CHECKSUM_ERROR;
352 299
353 int64 delta64 = snapshot.redundant_count() - count; 300 int64 delta64 = snapshot.redundant_count() - count;
354 if (delta64 != 0) { 301 if (delta64 != 0) {
355 int delta = static_cast<int>(delta64); 302 int delta = static_cast<int>(delta64);
356 if (delta != delta64) 303 if (delta != delta64)
357 delta = INT_MAX; // Flag all giant errors as INT_MAX. 304 delta = INT_MAX; // Flag all giant errors as INT_MAX.
358 // Since snapshots of histograms are taken asynchronously relative to 305 // Since snapshots of histograms are taken asynchronously relative to
359 // sampling (and snapped from different threads), it is pretty likely that 306 // sampling (and snapped from different threads), it is pretty likely that
360 // we'll catch a redundant count that doesn't match the sample count. We 307 // we'll catch a redundant count that doesn't match the sample count. We
(...skipping 14 matching lines...) Expand all
375 inconsistencies |= COUNT_LOW_ERROR; 322 inconsistencies |= COUNT_LOW_ERROR;
376 } 323 }
377 } 324 }
378 return static_cast<Inconsistencies>(inconsistencies); 325 return static_cast<Inconsistencies>(inconsistencies);
379 } 326 }
380 327
381 Histogram::ClassType Histogram::histogram_type() const { 328 Histogram::ClassType Histogram::histogram_type() const {
382 return HISTOGRAM; 329 return HISTOGRAM;
383 } 330 }
384 331
385 Histogram::Sample Histogram::ranges(size_t i) const { 332 Sample Histogram::ranges(size_t i) const {
386 return bucket_ranges_->range(i); 333 return bucket_ranges_->range(i);
387 } 334 }
388 335
389 size_t Histogram::bucket_count() const { 336 size_t Histogram::bucket_count() const {
390 return bucket_count_; 337 return bucket_count_;
391 } 338 }
392 339
393 // Do a safe atomic snapshot of sample data. 340 // Do a safe atomic snapshot of sample data.
394 // This implementation assumes we are on a safe single thread. 341 // This implementation assumes we are on a safe single thread.
395 void Histogram::SnapshotSample(SampleSet* sample) const { 342 void Histogram::SnapshotSample(SampleSet* sample) const {
396 // Note locking not done in this version!!! 343 // Note locking not done in this version!!!
397 *sample = sample_; 344 *sample = sample_;
398 } 345 }
399 346
400 bool Histogram::HasConstructorArguments(Sample minimum, 347 bool Histogram::HasConstructionArguments(Sample minimum,
401 Sample maximum, 348 Sample maximum,
402 size_t bucket_count) { 349 size_t bucket_count) {
403 return ((minimum == declared_min_) && (maximum == declared_max_) && 350 return ((minimum == declared_min_) && (maximum == declared_max_) &&
404 (bucket_count == bucket_count_)); 351 (bucket_count == bucket_count_));
405 } 352 }
406 353
407 bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum, 354 Histogram::Histogram(const string& name,
408 TimeDelta maximum, 355 Sample minimum,
409 size_t bucket_count) { 356 Sample maximum,
410 return ((minimum.InMilliseconds() == declared_min_) && 357 size_t bucket_count,
411 (maximum.InMilliseconds() == declared_max_) && 358 const BucketRanges* ranges)
412 (bucket_count == bucket_count_));
413 }
414
415 bool Histogram::HasValidRangeChecksum() const {
416 return CalculateRangeChecksum() == range_checksum_;
417 }
418
419 Histogram::Histogram(const std::string& name, Sample minimum,
420 Sample maximum, size_t bucket_count)
421 : HistogramBase(name), 359 : HistogramBase(name),
360 bucket_ranges_(ranges),
422 declared_min_(minimum), 361 declared_min_(minimum),
423 declared_max_(maximum), 362 declared_max_(maximum),
424 bucket_count_(bucket_count), 363 bucket_count_(bucket_count),
425 flags_(kNoFlags), 364 flags_(kNoFlags),
426 bucket_ranges_(new BucketRanges(bucket_count + 1)), 365 sample_(bucket_count) {
427 range_checksum_(0),
428 sample_() {
429 Initialize();
430 }
431
432 Histogram::Histogram(const std::string& name, TimeDelta minimum,
433 TimeDelta maximum, size_t bucket_count)
434 : HistogramBase(name),
435 declared_min_(static_cast<int> (minimum.InMilliseconds())),
436 declared_max_(static_cast<int> (maximum.InMilliseconds())),
437 bucket_count_(bucket_count),
438 flags_(kNoFlags),
439 bucket_ranges_(new BucketRanges(bucket_count + 1)),
440 range_checksum_(0),
441 sample_() {
442 Initialize();
443 } 366 }
444 367
445 Histogram::~Histogram() { 368 Histogram::~Histogram() {
446 if (StatisticsRecorder::dump_on_exit()) { 369 if (StatisticsRecorder::dump_on_exit()) {
447 std::string output; 370 string output;
448 WriteAsciiImpl(true, "\n", &output); 371 WriteAsciiImpl(true, "\n", &output);
449 DLOG(INFO) << output; 372 DLOG(INFO) << output;
450 } 373 }
451
452 // Just to make sure most derived class did this properly...
453 DCHECK(ValidateBucketRanges());
454 } 374 }
455 375
456 bool Histogram::SerializeRanges(Pickle* pickle) const { 376 bool Histogram::SerializeRanges(Pickle* pickle) const {
457 return true; 377 return true;
458 } 378 }
459 379
460 // Calculate what range of values are held in each bucket.
461 // We have to be careful that we don't pick a ratio between starting points in
462 // consecutive buckets that is sooo small, that the integer bounds are the same
463 // (effectively making one bucket get no values). We need to avoid:
464 // ranges(i) == ranges(i + 1)
465 // To avoid that, we just do a fine-grained bucket width as far as we need to
466 // until we get a ratio that moves us along at least 2 units at a time. From
467 // that bucket onward we do use the exponential growth of buckets.
468 void Histogram::InitializeBucketRange() {
469 double log_max = log(static_cast<double>(declared_max()));
470 double log_ratio;
471 double log_next;
472 size_t bucket_index = 1;
473 Sample current = declared_min();
474 SetBucketRange(bucket_index, current);
475 while (bucket_count() > ++bucket_index) {
476 double log_current;
477 log_current = log(static_cast<double>(current));
478 // Calculate the count'th root of the range.
479 log_ratio = (log_max - log_current) / (bucket_count() - bucket_index);
480 // See where the next bucket would start.
481 log_next = log_current + log_ratio;
482 int next;
483 next = static_cast<int>(floor(exp(log_next) + 0.5));
484 if (next > current)
485 current = next;
486 else
487 ++current; // Just do a narrow bucket, and keep trying.
488 SetBucketRange(bucket_index, current);
489 }
490 ResetRangeChecksum();
491
492 DCHECK_EQ(bucket_count(), bucket_index);
493 }
494
495 bool Histogram::PrintEmptyBucket(size_t index) const { 380 bool Histogram::PrintEmptyBucket(size_t index) const {
496 return true; 381 return true;
497 } 382 }
498 383
499 size_t Histogram::BucketIndex(Sample value) const { 384 size_t Histogram::BucketIndex(Sample value) const {
500 // Use simple binary search. This is very general, but there are better 385 // Use simple binary search. This is very general, but there are better
501 // approaches if we knew that the buckets were linearly distributed. 386 // approaches if we knew that the buckets were linearly distributed.
502 DCHECK_LE(ranges(0), value); 387 DCHECK_LE(ranges(0), value);
503 DCHECK_GT(ranges(bucket_count()), value); 388 DCHECK_GT(ranges(bucket_count()), value);
504 size_t under = 0; 389 size_t under = 0;
(...skipping 23 matching lines...) Expand all
528 // not have 0-graphical-height buckets. 413 // not have 0-graphical-height buckets.
529 double Histogram::GetBucketSize(Count current, size_t i) const { 414 double Histogram::GetBucketSize(Count current, size_t i) const {
530 DCHECK_GT(ranges(i + 1), ranges(i)); 415 DCHECK_GT(ranges(i + 1), ranges(i));
531 static const double kTransitionWidth = 5; 416 static const double kTransitionWidth = 5;
532 double denominator = ranges(i + 1) - ranges(i); 417 double denominator = ranges(i + 1) - ranges(i);
533 if (denominator > kTransitionWidth) 418 if (denominator > kTransitionWidth)
534 denominator = kTransitionWidth; // Stop trying to normalize. 419 denominator = kTransitionWidth; // Stop trying to normalize.
535 return current/denominator; 420 return current/denominator;
536 } 421 }
537 422
538 void Histogram::ResetRangeChecksum() { 423 const string Histogram::GetAsciiBucketRange(size_t i) const {
539 range_checksum_ = CalculateRangeChecksum(); 424 string result;
540 }
541
542 const std::string Histogram::GetAsciiBucketRange(size_t i) const {
543 std::string result;
544 if (kHexRangePrintingFlag & flags_) 425 if (kHexRangePrintingFlag & flags_)
545 StringAppendF(&result, "%#x", ranges(i)); 426 StringAppendF(&result, "%#x", ranges(i));
546 else 427 else
547 StringAppendF(&result, "%d", ranges(i)); 428 StringAppendF(&result, "%d", ranges(i));
548 return result; 429 return result;
549 } 430 }
550 431
551 // Update histogram data with new sample. 432 // Update histogram data with new sample.
552 void Histogram::Accumulate(Sample value, Count count, size_t index) { 433 void Histogram::Accumulate(Sample value, Count count, size_t index) {
553 // Note locking not done in this version!!! 434 // Note locking not done in this version!!!
554 sample_.Accumulate(value, count, index); 435 sample_.Accumulate(value, count, index);
555 } 436 }
556 437
557 void Histogram::SetBucketRange(size_t i, Sample value) { 438 // static
558 DCHECK_GT(bucket_count_, i); 439 bool Histogram::InspectConstructionArguments(const string& name,
559 DCHECK_GE(value, 0); 440 Sample* minimum,
560 bucket_ranges_->set_range(i, value); 441 Sample* maximum,
561 } 442 size_t* bucket_count) {
443 // Defensive code for backward compatibility.
444 if (*minimum < 1) {
445 DLOG(WARNING) << "Histogram: " << name << " Bad minimum: " << *minimum;
446 *minimum = 1;
447 }
448 if (*maximum >= kSampleType_MAX) {
449 DLOG(WARNING) << "Histogram: " << name << " Bad maximum: " << *maximum;
450 *maximum = kSampleType_MAX;
451 }
562 452
563 bool Histogram::ValidateBucketRanges() const { 453 if (*bucket_count < 3 || *bucket_count >= kBucketCount_MAX)
564 // Standard assertions that all bucket ranges should satisfy. 454 return false;
565 DCHECK_EQ(bucket_count_ + 1, bucket_ranges_->size()); 455 if (*bucket_count > static_cast<size_t>(*maximum - *minimum + 2))
566 DCHECK_EQ(0, ranges(0)); 456 return false;
567 DCHECK_EQ(declared_min(), ranges(1));
568 DCHECK_EQ(declared_max(), ranges(bucket_count_ - 1));
569 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count_));
570 return true; 457 return true;
571 } 458 }
572 459
573 uint32 Histogram::CalculateRangeChecksum() const { 460 // Calculate what range of values are held in each bucket.
574 DCHECK_EQ(bucket_ranges_->size(), bucket_count() + 1); 461 // We have to be careful that we don't pick a ratio between starting points in
575 // Seed checksum. 462 // consecutive buckets that is sooo small, that the integer bounds are the same
576 uint32 checksum = static_cast<uint32>(bucket_ranges_->size()); 463 // (effectively making one bucket get no values). We need to avoid:
577 for (size_t index = 0; index < bucket_count(); ++index) 464 // ranges(i) == ranges(i + 1)
578 checksum = Crc32(checksum, ranges(index)); 465 // To avoid that, we just do a fine-grained bucket width as far as we need to
579 return checksum; 466 // until we get a ratio that moves us along at least 2 units at a time. From
580 } 467 // that bucket onward we do use the exponential growth of buckets.
581 468 //
582 void Histogram::Initialize() { 469 // static
583 sample_.Resize(*this); 470 void Histogram::InitializeBucketRanges(Sample minimum,
584 if (declared_min_ < 1) 471 Sample maximum,
585 declared_min_ = 1; 472 size_t bucket_count,
586 if (declared_max_ > kSampleType_MAX - 1) 473 BucketRanges* ranges) {
587 declared_max_ = kSampleType_MAX - 1; 474 DCHECK_EQ(ranges->size(), bucket_count + 1);
588 DCHECK_LE(declared_min_, declared_max_); 475 double log_max = log(static_cast<double>(maximum));
589 DCHECK_GT(bucket_count_, 1u); 476 double log_ratio;
590 CHECK_LT(bucket_count_, kBucketCount_MAX); 477 double log_next;
591 size_t maximal_bucket_count = declared_max_ - declared_min_ + 2; 478 size_t bucket_index = 1;
592 DCHECK_LE(bucket_count_, maximal_bucket_count); 479 Sample current = minimum;
593 DCHECK_EQ(0, ranges(0)); 480 ranges->set_range(bucket_index, current);
594 bucket_ranges_->set_range(bucket_count_, kSampleType_MAX); 481 while (bucket_count > ++bucket_index) {
595 } 482 double log_current;
596 483 log_current = log(static_cast<double>(current));
597 // We generate the CRC-32 using the low order bits to select whether to XOR in 484 // Calculate the count'th root of the range.
598 // the reversed polynomial 0xedb88320L. This is nice and simple, and allows us 485 log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
599 // to keep the quotient in a uint32. Since we're not concerned about the nature 486 // See where the next bucket would start.
600 // of corruptions (i.e., we don't care about bit sequencing, since we are 487 log_next = log_current + log_ratio;
601 // handling memory changes, which are more grotesque) so we don't bother to 488 Sample next;
602 // get the CRC correct for big-endian vs little-ending calculations. All we 489 next = static_cast<int>(floor(exp(log_next) + 0.5));
603 // need is a nice hash, that tends to depend on all the bits of the sample, with 490 if (next > current)
604 // very little chance of changes in one place impacting changes in another 491 current = next;
605 // place. 492 else
606 uint32 Histogram::Crc32(uint32 sum, Histogram::Sample range) { 493 ++current; // Just do a narrow bucket, and keep trying.
607 const bool kUseRealCrc = true; // TODO(jar): Switch to false and watch stats. 494 ranges->set_range(bucket_index, current);
608 if (kUseRealCrc) {
609 union {
610 Histogram::Sample range;
611 unsigned char bytes[sizeof(Histogram::Sample)];
612 } converter;
613 converter.range = range;
614 for (size_t i = 0; i < sizeof(converter); ++i)
615 sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8);
616 } else {
617 // Use hash techniques provided in ReallyFastHash, except we don't care
618 // about "avalanching" (which would worsten the hash, and add collisions),
619 // and we don't care about edge cases since we have an even number of bytes.
620 union {
621 Histogram::Sample range;
622 uint16 ints[sizeof(Histogram::Sample) / 2];
623 } converter;
624 DCHECK_EQ(sizeof(Histogram::Sample), sizeof(converter));
625 converter.range = range;
626 sum += converter.ints[0];
627 sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11);
628 sum += sum >> 11;
629 } 495 }
630 return sum; 496 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX);
497 ranges->ResetChecksum();
631 } 498 }
632 499
633 //------------------------------------------------------------------------------ 500 //------------------------------------------------------------------------------
634 // Private methods 501 // Private methods
635 502
636 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { 503 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const {
637 double max = 0; 504 double max = 0;
638 for (size_t i = 0; i < bucket_count() ; ++i) { 505 for (size_t i = 0; i < bucket_count() ; ++i) {
639 double current_size = GetBucketSize(snapshot.counts(i), i); 506 double current_size = GetBucketSize(snapshot.counts(i), i);
640 if (current_size > max) 507 if (current_size > max)
641 max = current_size; 508 max = current_size;
642 } 509 }
643 return max; 510 return max;
644 } 511 }
645 512
646 void Histogram::WriteAsciiHeader(const SampleSet& snapshot, 513 void Histogram::WriteAsciiHeader(const SampleSet& snapshot,
647 Count sample_count, 514 Count sample_count,
648 std::string* output) const { 515 string* output) const {
649 StringAppendF(output, 516 StringAppendF(output,
650 "Histogram: %s recorded %d samples", 517 "Histogram: %s recorded %d samples",
651 histogram_name().c_str(), 518 histogram_name().c_str(),
652 sample_count); 519 sample_count);
653 if (0 == sample_count) { 520 if (0 == sample_count) {
654 DCHECK_EQ(snapshot.sum(), 0); 521 DCHECK_EQ(snapshot.sum(), 0);
655 } else { 522 } else {
656 double average = static_cast<float>(snapshot.sum()) / sample_count; 523 double average = static_cast<float>(snapshot.sum()) / sample_count;
657 524
658 StringAppendF(output, ", average = %.1f", average); 525 StringAppendF(output, ", average = %.1f", average);
659 } 526 }
660 if (flags_ & ~kHexRangePrintingFlag) 527 if (flags_ & ~kHexRangePrintingFlag)
661 StringAppendF(output, " (flags = 0x%x)", flags_ & ~kHexRangePrintingFlag); 528 StringAppendF(output, " (flags = 0x%x)", flags_ & ~kHexRangePrintingFlag);
662 } 529 }
663 530
664 void Histogram::WriteAsciiBucketContext(const int64 past, 531 void Histogram::WriteAsciiBucketContext(const int64 past,
665 const Count current, 532 const Count current,
666 const int64 remaining, 533 const int64 remaining,
667 const size_t i, 534 const size_t i,
668 std::string* output) const { 535 string* output) const {
669 double scaled_sum = (past + current + remaining) / 100.0; 536 double scaled_sum = (past + current + remaining) / 100.0;
670 WriteAsciiBucketValue(current, scaled_sum, output); 537 WriteAsciiBucketValue(current, scaled_sum, output);
671 if (0 < i) { 538 if (0 < i) {
672 double percentage = past / scaled_sum; 539 double percentage = past / scaled_sum;
673 StringAppendF(output, " {%3.1f%%}", percentage); 540 StringAppendF(output, " {%3.1f%%}", percentage);
674 } 541 }
675 } 542 }
676 543
677 void Histogram::WriteAsciiBucketValue(Count current, double scaled_sum, 544 void Histogram::WriteAsciiBucketValue(Count current,
678 std::string* output) const { 545 double scaled_sum,
546 string* output) const {
679 StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum); 547 StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
680 } 548 }
681 549
682 void Histogram::WriteAsciiBucketGraph(double current_size, double max_size, 550 void Histogram::WriteAsciiBucketGraph(double current_size, double max_size,
jar (doing other things) 2012/08/01 00:26:10 nit: style fix here too (push arg to next line)
kaiwang 2012/08/01 04:13:21 Done.
683 std::string* output) const { 551 string* output) const {
684 const int k_line_length = 72; // Maximal horizontal width of graph. 552 const int k_line_length = 72; // Maximal horizontal width of graph.
685 int x_count = static_cast<int>(k_line_length * (current_size / max_size) 553 int x_count = static_cast<int>(k_line_length * (current_size / max_size)
686 + 0.5); 554 + 0.5);
687 int x_remainder = k_line_length - x_count; 555 int x_remainder = k_line_length - x_count;
688 556
689 while (0 < x_count--) 557 while (0 < x_count--)
690 output->append("-"); 558 output->append("-");
691 output->append("O"); 559 output->append("O");
692 while (0 < x_remainder--) 560 while (0 < x_remainder--)
693 output->append(" "); 561 output->append(" ");
694 } 562 }
695 563
696 //------------------------------------------------------------------------------ 564 //------------------------------------------------------------------------------
697 // Methods for the Histogram::SampleSet class 565 // Methods for the Histogram::SampleSet class
698 //------------------------------------------------------------------------------ 566 //------------------------------------------------------------------------------
699 567
568 Histogram::SampleSet::SampleSet(size_t size)
569 : counts_(size, 0),
570 sum_(0),
571 redundant_count_(0) {}
572
700 Histogram::SampleSet::SampleSet() 573 Histogram::SampleSet::SampleSet()
701 : counts_(), 574 : counts_(),
702 sum_(0), 575 sum_(0),
703 redundant_count_(0) { 576 redundant_count_(0) {}
577
578 Histogram::SampleSet::~SampleSet() {}
579
580 void Histogram::SampleSet::Resize(size_t size) {
581 counts_.resize(size, 0);
704 } 582 }
705 583
706 Histogram::SampleSet::~SampleSet() {
707 }
708
709 void Histogram::SampleSet::Resize(const Histogram& histogram) {
710 counts_.resize(histogram.bucket_count(), 0);
711 }
712
713 void Histogram::SampleSet::CheckSize(const Histogram& histogram) const {
714 DCHECK_EQ(histogram.bucket_count(), counts_.size());
715 }
716
717
718 void Histogram::SampleSet::Accumulate(Sample value, Count count, 584 void Histogram::SampleSet::Accumulate(Sample value, Count count,
719 size_t index) { 585 size_t index) {
720 DCHECK(count == 1 || count == -1); 586 DCHECK(count == 1 || count == -1);
721 counts_[index] += count; 587 counts_[index] += count;
722 sum_ += count * value; 588 sum_ += count * value;
723 redundant_count_ += count; 589 redundant_count_ += count;
724 DCHECK_GE(counts_[index], 0); 590 DCHECK_GE(counts_[index], 0);
725 DCHECK_GE(sum_, 0); 591 DCHECK_GE(sum_, 0);
726 DCHECK_GE(redundant_count_, 0); 592 DCHECK_GE(redundant_count_, 0);
727 } 593 }
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 } 661 }
796 DCHECK_EQ(count, redundant_count_); 662 DCHECK_EQ(count, redundant_count_);
797 return count == redundant_count_; 663 return count == redundant_count_;
798 } 664 }
799 665
800 //------------------------------------------------------------------------------ 666 //------------------------------------------------------------------------------
801 // LinearHistogram: This histogram uses a traditional set of evenly spaced 667 // LinearHistogram: This histogram uses a traditional set of evenly spaced
802 // buckets. 668 // buckets.
803 //------------------------------------------------------------------------------ 669 //------------------------------------------------------------------------------
804 670
805 LinearHistogram::~LinearHistogram() { 671 LinearHistogram::~LinearHistogram() {}
806 }
807 672
808 Histogram* LinearHistogram::FactoryGet(const std::string& name, 673 Histogram* LinearHistogram::FactoryGet(const string& name,
809 Sample minimum, 674 Sample minimum,
810 Sample maximum, 675 Sample maximum,
811 size_t bucket_count, 676 size_t bucket_count,
812 Flags flags) { 677 Flags flags) {
813 if (minimum < 1) 678 CHECK(Histogram::InspectConstructionArguments(name, &minimum, &maximum,
814 minimum = 1; 679 &bucket_count));
815 if (maximum > kSampleType_MAX - 1)
816 maximum = kSampleType_MAX - 1;
817
818 DCHECK_GT(maximum, minimum);
819 DCHECK_GT((Sample) bucket_count, 2);
820 DCHECK_LE((Sample) bucket_count, maximum - minimum + 2);
821 680
822 Histogram* histogram = StatisticsRecorder::FindHistogram(name); 681 Histogram* histogram = StatisticsRecorder::FindHistogram(name);
823 if (!histogram) { 682 if (!histogram) {
824 // To avoid racy destruction at shutdown, the following will be leaked. 683 // To avoid racy destruction at shutdown, the following will be leaked.
684 BucketRanges* ranges = new BucketRanges(bucket_count + 1);
685 InitializeBucketRanges(minimum, maximum, bucket_count, ranges);
686 const BucketRanges* registered_ranges =
687 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
688
825 LinearHistogram* tentative_histogram = 689 LinearHistogram* tentative_histogram =
826 new LinearHistogram(name, minimum, maximum, bucket_count); 690 new LinearHistogram(name, minimum, maximum, bucket_count,
827 tentative_histogram->InitializeBucketRange(); 691 registered_ranges);
828 tentative_histogram->SetFlags(flags); 692 tentative_histogram->SetFlags(flags);
829 histogram = 693 histogram =
830 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); 694 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
831 } 695 }
832 696
833 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type()); 697 CHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type());
834 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); 698 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count));
835 return histogram; 699 return histogram;
836 } 700 }
837 701
838 Histogram* LinearHistogram::FactoryTimeGet(const std::string& name, 702 Histogram* LinearHistogram::FactoryTimeGet(const string& name,
839 TimeDelta minimum, 703 TimeDelta minimum,
840 TimeDelta maximum, 704 TimeDelta maximum,
841 size_t bucket_count, 705 size_t bucket_count,
842 Flags flags) { 706 Flags flags) {
843 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), 707 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
844 bucket_count, flags); 708 bucket_count, flags);
845 } 709 }
846 710
847 Histogram::ClassType LinearHistogram::histogram_type() const { 711 Histogram::ClassType LinearHistogram::histogram_type() const {
848 return LINEAR_HISTOGRAM; 712 return LINEAR_HISTOGRAM;
849 } 713 }
850 714
851 void LinearHistogram::SetRangeDescriptions( 715 void LinearHistogram::SetRangeDescriptions(
852 const DescriptionPair descriptions[]) { 716 const DescriptionPair descriptions[]) {
853 for (int i =0; descriptions[i].description; ++i) { 717 for (int i =0; descriptions[i].description; ++i) {
854 bucket_description_[descriptions[i].sample] = descriptions[i].description; 718 bucket_description_[descriptions[i].sample] = descriptions[i].description;
855 } 719 }
856 } 720 }
857 721
858 LinearHistogram::LinearHistogram(const std::string& name, 722 LinearHistogram::LinearHistogram(const string& name,
859 Sample minimum, 723 Sample minimum,
860 Sample maximum, 724 Sample maximum,
861 size_t bucket_count) 725 size_t bucket_count,
862 : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) { 726 const BucketRanges* ranges)
863 } 727 : Histogram(name, minimum, maximum, bucket_count, ranges) {
864
865 LinearHistogram::LinearHistogram(const std::string& name,
866 TimeDelta minimum,
867 TimeDelta maximum,
868 size_t bucket_count)
869 : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ?
870 minimum : TimeDelta::FromMilliseconds(1),
871 maximum, bucket_count) {
872 }
873
874 void LinearHistogram::InitializeBucketRange() {
875 DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here.
876 double min = declared_min();
877 double max = declared_max();
878 size_t i;
879 for (i = 1; i < bucket_count(); ++i) {
880 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) /
881 (bucket_count() - 2);
882 SetBucketRange(i, static_cast<int> (linear_range + 0.5));
883 }
884 ResetRangeChecksum();
885 } 728 }
886 729
887 double LinearHistogram::GetBucketSize(Count current, size_t i) const { 730 double LinearHistogram::GetBucketSize(Count current, size_t i) const {
888 DCHECK_GT(ranges(i + 1), ranges(i)); 731 DCHECK_GT(ranges(i + 1), ranges(i));
889 // Adjacent buckets with different widths would have "surprisingly" many (few) 732 // Adjacent buckets with different widths would have "surprisingly" many (few)
890 // samples in a histogram if we didn't normalize this way. 733 // samples in a histogram if we didn't normalize this way.
891 double denominator = ranges(i + 1) - ranges(i); 734 double denominator = ranges(i + 1) - ranges(i);
892 return current/denominator; 735 return current/denominator;
893 } 736 }
894 737
895 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { 738 const string LinearHistogram::GetAsciiBucketRange(size_t i) const {
896 int range = ranges(i); 739 int range = ranges(i);
897 BucketDescriptionMap::const_iterator it = bucket_description_.find(range); 740 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
898 if (it == bucket_description_.end()) 741 if (it == bucket_description_.end())
899 return Histogram::GetAsciiBucketRange(i); 742 return Histogram::GetAsciiBucketRange(i);
900 return it->second; 743 return it->second;
901 } 744 }
902 745
903 bool LinearHistogram::PrintEmptyBucket(size_t index) const { 746 bool LinearHistogram::PrintEmptyBucket(size_t index) const {
904 return bucket_description_.find(ranges(index)) == bucket_description_.end(); 747 return bucket_description_.find(ranges(index)) == bucket_description_.end();
905 } 748 }
906 749
750 // static
751 void LinearHistogram::InitializeBucketRanges(Sample minimum,
752 Sample maximum,
753 size_t bucket_count,
754 BucketRanges* ranges) {
755 DCHECK_EQ(ranges->size(), bucket_count + 1);
756 double min = minimum;
757 double max = maximum;
758 size_t i;
759 for (i = 1; i < bucket_count; ++i) {
760 double linear_range = (min * (bucket_count -1 - i) + max * (i - 1)) /
761 (bucket_count - 2);
jar (doing other things) 2012/08/01 00:26:10 nit: indent only 4 (even though old code did it th
kaiwang 2012/08/01 04:13:21 merged into second line
762 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5));
763 }
764 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX);
765 ranges->ResetChecksum();
766 }
907 767
908 //------------------------------------------------------------------------------ 768 //------------------------------------------------------------------------------
909 // This section provides implementation for BooleanHistogram. 769 // This section provides implementation for BooleanHistogram.
910 //------------------------------------------------------------------------------ 770 //------------------------------------------------------------------------------
911 771
912 Histogram* BooleanHistogram::FactoryGet(const std::string& name, Flags flags) { 772 Histogram* BooleanHistogram::FactoryGet(const string& name, Flags flags) {
913 Histogram* histogram = StatisticsRecorder::FindHistogram(name); 773 Histogram* histogram = StatisticsRecorder::FindHistogram(name);
914 if (!histogram) { 774 if (!histogram) {
915 // To avoid racy destruction at shutdown, the following will be leaked. 775 // To avoid racy destruction at shutdown, the following will be leaked.
916 BooleanHistogram* tentative_histogram = new BooleanHistogram(name); 776 BucketRanges* ranges = new BucketRanges(4);
917 tentative_histogram->InitializeBucketRange(); 777 LinearHistogram::InitializeBucketRanges(1, 2, 3, ranges);
778 const BucketRanges* registered_ranges =
779 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
780
781 BooleanHistogram* tentative_histogram =
782 new BooleanHistogram(name, registered_ranges);
918 tentative_histogram->SetFlags(flags); 783 tentative_histogram->SetFlags(flags);
919 histogram = 784 histogram =
920 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); 785 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
921 } 786 }
922 787
923 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type()); 788 CHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type());
924 return histogram; 789 return histogram;
925 } 790 }
926 791
927 Histogram::ClassType BooleanHistogram::histogram_type() const { 792 Histogram::ClassType BooleanHistogram::histogram_type() const {
928 return BOOLEAN_HISTOGRAM; 793 return BOOLEAN_HISTOGRAM;
929 } 794 }
930 795
931 void BooleanHistogram::AddBoolean(bool value) { 796 void BooleanHistogram::AddBoolean(bool value) {
932 Add(value ? 1 : 0); 797 Add(value ? 1 : 0);
933 } 798 }
934 799
935 BooleanHistogram::BooleanHistogram(const std::string& name) 800 BooleanHistogram::BooleanHistogram(const string& name,
936 : LinearHistogram(name, 1, 2, 3) { 801 const BucketRanges* ranges)
937 } 802 : LinearHistogram(name, 1, 2, 3, ranges) {}
938 803
939 //------------------------------------------------------------------------------ 804 //------------------------------------------------------------------------------
940 // CustomHistogram: 805 // CustomHistogram:
941 //------------------------------------------------------------------------------ 806 //------------------------------------------------------------------------------
942 807
943 Histogram* CustomHistogram::FactoryGet(const std::string& name, 808 Histogram* CustomHistogram::FactoryGet(const string& name,
944 const std::vector<Sample>& custom_ranges, 809 const vector<Sample>& custom_ranges,
945 Flags flags) { 810 Flags flags) {
946 // Remove the duplicates in the custom ranges array. 811 CHECK(ValidateCustomRanges(custom_ranges));
947 std::vector<int> ranges = custom_ranges;
948 ranges.push_back(0); // Ensure we have a zero value.
949 std::sort(ranges.begin(), ranges.end());
950 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
951 if (ranges.size() <= 1) {
952 DCHECK(false);
953 // Note that we pushed a 0 in above, so for defensive code....
954 ranges.push_back(1); // Put in some data so we can index to [1].
955 }
956
957 DCHECK_LT(ranges.back(), kSampleType_MAX);
958 812
959 Histogram* histogram = StatisticsRecorder::FindHistogram(name); 813 Histogram* histogram = StatisticsRecorder::FindHistogram(name);
960 if (!histogram) { 814 if (!histogram) {
815 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges);
816 const BucketRanges* registered_ranges =
817 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
818
961 // To avoid racy destruction at shutdown, the following will be leaked. 819 // To avoid racy destruction at shutdown, the following will be leaked.
962 CustomHistogram* tentative_histogram = new CustomHistogram(name, ranges); 820 CustomHistogram* tentative_histogram =
963 tentative_histogram->InitializedCustomBucketRange(ranges); 821 new CustomHistogram(name, registered_ranges);
964 tentative_histogram->SetFlags(flags); 822 tentative_histogram->SetFlags(flags);
823
965 histogram = 824 histogram =
966 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); 825 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
967 } 826 }
968 827
969 DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM); 828 CHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM);
970 DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(),
971 ranges.size()));
972 return histogram; 829 return histogram;
973 } 830 }
974 831
975 Histogram::ClassType CustomHistogram::histogram_type() const { 832 Histogram::ClassType CustomHistogram::histogram_type() const {
976 return CUSTOM_HISTOGRAM; 833 return CUSTOM_HISTOGRAM;
977 } 834 }
978 835
979 // static 836 // static
980 std::vector<Histogram::Sample> CustomHistogram::ArrayToCustomRanges( 837 vector<Sample> CustomHistogram::ArrayToCustomRanges(
981 const Sample* values, size_t num_values) { 838 const Sample* values, size_t num_values) {
982 std::vector<Sample> all_values; 839 vector<Sample> all_values;
983 for (size_t i = 0; i < num_values; ++i) { 840 for (size_t i = 0; i < num_values; ++i) {
984 Sample value = values[i]; 841 Sample value = values[i];
985 all_values.push_back(value); 842 all_values.push_back(value);
986 843
987 // Ensure that a guard bucket is added. If we end up with duplicate 844 // Ensure that a guard bucket is added. If we end up with duplicate
988 // values, FactoryGet will take care of removing them. 845 // values, FactoryGet will take care of removing them.
989 all_values.push_back(value + 1); 846 all_values.push_back(value + 1);
990 } 847 }
991 return all_values; 848 return all_values;
992 } 849 }
993 850
994 CustomHistogram::CustomHistogram(const std::string& name, 851 CustomHistogram::CustomHistogram(const string& name,
995 const std::vector<Sample>& custom_ranges) 852 const BucketRanges* ranges)
996 : Histogram(name, custom_ranges[1], custom_ranges.back(), 853 : Histogram(name,
997 custom_ranges.size()) { 854 ranges->range(1),
998 DCHECK_GT(custom_ranges.size(), 1u); 855 ranges->range(ranges->size() - 2),
999 DCHECK_EQ(custom_ranges[0], 0); 856 ranges->size() - 1,
1000 } 857 ranges) {}
1001 858
1002 bool CustomHistogram::SerializeRanges(Pickle* pickle) const { 859 bool CustomHistogram::SerializeRanges(Pickle* pickle) const {
1003 for (size_t i = 0; i < bucket_ranges()->size(); ++i) { 860 for (size_t i = 0; i < bucket_ranges()->size(); ++i) {
1004 if (!pickle->WriteInt(bucket_ranges()->range(i))) 861 if (!pickle->WriteInt(bucket_ranges()->range(i)))
1005 return false; 862 return false;
1006 } 863 }
1007 return true; 864 return true;
1008 } 865 }
1009 866
1010 // static 867 // static
1011 bool CustomHistogram::DeserializeRanges( 868 bool CustomHistogram::DeserializeRanges(
1012 PickleIterator* iter, std::vector<Histogram::Sample>* ranges) { 869 PickleIterator* iter, vector<Sample>* ranges) {
1013 for (size_t i = 0; i < ranges->size(); ++i) { 870 for (size_t i = 0; i < ranges->size(); ++i) {
1014 if (!iter->ReadInt(&(*ranges)[i])) 871 if (!iter->ReadInt(&(*ranges)[i]))
1015 return false; 872 return false;
1016 } 873 }
1017 return true; 874 return true;
1018 } 875 }
1019 876
1020 void CustomHistogram::InitializedCustomBucketRange(
1021 const std::vector<Sample>& custom_ranges) {
1022 DCHECK_GT(custom_ranges.size(), 1u);
1023 DCHECK_EQ(custom_ranges[0], 0);
1024 DCHECK_LE(custom_ranges.size(), bucket_count());
1025 for (size_t index = 0; index < custom_ranges.size(); ++index)
1026 SetBucketRange(index, custom_ranges[index]);
1027 ResetRangeChecksum();
1028 }
1029
1030 double CustomHistogram::GetBucketSize(Count current, size_t i) const { 877 double CustomHistogram::GetBucketSize(Count current, size_t i) const {
1031 return 1; 878 return 1;
1032 } 879 }
1033 880
881 // static
882 bool CustomHistogram::ValidateCustomRanges(
883 const vector<Sample>& custom_ranges) {
884 if (custom_ranges.size() < 1)
885 return false;
886 for (size_t i = 0; i < custom_ranges.size(); i++) {
887 Sample s = custom_ranges[i];
888 if (s < 0 || s > HistogramBase::kSampleType_MAX - 1)
889 return false;
890 }
891 return true;
892 }
893
894 // static
895 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges(
896 const vector<Sample>& custom_ranges) {
897 // Remove the duplicates in the custom ranges array.
898 vector<int> ranges = custom_ranges;
899 ranges.push_back(0); // Ensure we have a zero value.
900 ranges.push_back(HistogramBase::kSampleType_MAX);
901 std::sort(ranges.begin(), ranges.end());
902 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
903
904 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
905 for (size_t i = 0; i < ranges.size(); i++) {
906 bucket_ranges->set_range(i, ranges[i]);
907 }
908 bucket_ranges->ResetChecksum();
909 return bucket_ranges;
910 }
911
1034 } // namespace base 912 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698