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

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

Issue 1485763002: Merge multiple histogram snapshots into single one for reporting. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@shared-histograms
Patch Set: Change 'inconsistencies' from int to unsigned. Created 4 years, 10 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 (c) 2015 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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 "base/metrics/histogram_persistence.h" 5 #include "base/metrics/histogram_persistence.h"
6 6
7 #include "base/lazy_instance.h" 7 #include "base/lazy_instance.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 struct PersistentHistogramData { 66 struct PersistentHistogramData {
67 int histogram_type; 67 int histogram_type;
68 int flags; 68 int flags;
69 int minimum; 69 int minimum;
70 int maximum; 70 int maximum;
71 uint32_t bucket_count; 71 uint32_t bucket_count;
72 PersistentMemoryAllocator::Reference ranges_ref; 72 PersistentMemoryAllocator::Reference ranges_ref;
73 uint32_t ranges_checksum; 73 uint32_t ranges_checksum;
74 PersistentMemoryAllocator::Reference counts_ref; 74 PersistentMemoryAllocator::Reference counts_ref;
75 HistogramSamples::Metadata samples_metadata; 75 HistogramSamples::Metadata samples_metadata;
76 HistogramSamples::Metadata logged_metadata;
76 77
77 // Space for the histogram name will be added during the actual allocation 78 // Space for the histogram name will be added during the actual allocation
78 // request. This must be the last field of the structure. A zero-size array 79 // request. This must be the last field of the structure. A zero-size array
79 // or a "flexible" array would be preferred but is not (yet) valid C++. 80 // or a "flexible" array would be preferred but is not (yet) valid C++.
80 char name[1]; 81 char name[1];
81 }; 82 };
82 83
83 // The object held here will obviously not be destructed at process exit 84 // The object held here will obviously not be destructed at process exit
84 // but that's okay since PersistentMemoryAllocator objects are explicitly 85 // but that's okay since PersistentMemoryAllocator objects are explicitly
85 // forbidden from doing anything essential at exit anyway due to the fact 86 // forbidden from doing anything essential at exit anyway due to the fact
(...skipping 15 matching lines...) Expand all
101 ranges->set_range(i, ranges_data[i]); 102 ranges->set_range(i, ranges_data[i]);
102 } 103 }
103 104
104 ranges->ResetChecksum(); 105 ranges->ResetChecksum();
105 if (ranges->checksum() != ranges_checksum) 106 if (ranges->checksum() != ranges_checksum)
106 return nullptr; 107 return nullptr;
107 108
108 return ranges.release(); 109 return ranges.release();
109 } 110 }
110 111
112 // Calculate the number of bytes required to store all of a histogram's
113 // "counts".
Alexei Svitkine (slow) 2016/02/17 16:21:12 Add a sentence about why this returns 0. Maybe jus
bcwhite 2016/02/17 17:58:20 Done.
114 uint32_t RequiredCountsBytes(size_t bucket_count) {
Alexei Svitkine (slow) 2016/02/17 16:21:12 Nit: Get* or Calculate*
bcwhite 2016/02/17 17:58:20 Done.
115 // 2 because each "sample count" also requires a backup "logged count"
116 // used for calculating the delta during snapshot operations.
117 const unsigned kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount);
118
119 // If the |bucket_count| is such that it would overflow the return type,
120 // perhaps as the result of a milicious actor, then return zero to
Alexei Svitkine (slow) 2016/02/17 16:21:12 Nit: malicious
bcwhite 2016/02/17 17:58:20 Done.
121 // indicate the problem to the caller.
122 if (bucket_count > std::numeric_limits<uint32_t>::max() / kBytesPerBucket)
123 return 0;
124
125 return static_cast<uint32_t>(bucket_count * kBytesPerBucket);
126 }
127
111 } // namespace 128 } // namespace
112 129
113 const Feature kPersistentHistogramsFeature{ 130 const Feature kPersistentHistogramsFeature{
114 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT 131 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
115 }; 132 };
116 133
117 // Get the histogram in which create results are stored. This is copied almost 134 // Get the histogram in which create results are stored. This is copied almost
118 // exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with added code 135 // exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with added code
119 // to prevent recursion (a likely occurance because the creation of a new 136 // to prevent recursion (a likely occurance because the creation of a new
120 // histogram can end up calling this.) 137 // histogram can end up calling this.)
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 if (!ranges) { 230 if (!ranges) {
214 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); 231 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
215 NOTREACHED(); 232 NOTREACHED();
216 return nullptr; 233 return nullptr;
217 } 234 }
218 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); 235 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
219 236
220 HistogramBase::AtomicCount* counts_data = 237 HistogramBase::AtomicCount* counts_data =
221 allocator->GetAsObject<HistogramBase::AtomicCount>( 238 allocator->GetAsObject<HistogramBase::AtomicCount>(
222 histogram_data.counts_ref, kTypeIdCountsArray); 239 histogram_data.counts_ref, kTypeIdCountsArray);
223 if (!counts_data || 240 size_t counts_bytes = RequiredCountsBytes(histogram_data.bucket_count);
224 allocator->GetAllocSize(histogram_data.counts_ref) < 241 if (!counts_data || !counts_bytes ||
225 histogram_data.bucket_count * sizeof(HistogramBase::AtomicCount)) { 242 allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) {
226 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); 243 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY);
227 NOTREACHED(); 244 NOTREACHED();
228 return nullptr; 245 return nullptr;
229 } 246 }
230 247
248 // After the main "counts" array is a second array using for storing what
249 // was previously logged. This is used to calculate the "delta" during
250 // snapshot operations.
251 HistogramBase::AtomicCount* logged_data =
252 counts_data + histogram_data.bucket_count;
253
231 std::string name(histogram_data_ptr->name); 254 std::string name(histogram_data_ptr->name);
232 HistogramBase* histogram = nullptr; 255 HistogramBase* histogram = nullptr;
233 switch (histogram_data.histogram_type) { 256 switch (histogram_data.histogram_type) {
234 case HISTOGRAM: 257 case HISTOGRAM:
235 histogram = Histogram::PersistentGet( 258 histogram = Histogram::PersistentGet(
236 name, 259 name,
237 histogram_data.minimum, 260 histogram_data.minimum,
238 histogram_data.maximum, 261 histogram_data.maximum,
239 ranges, 262 ranges,
240 counts_data, 263 counts_data,
264 logged_data,
241 histogram_data.bucket_count, 265 histogram_data.bucket_count,
242 &histogram_data_ptr->samples_metadata); 266 &histogram_data_ptr->samples_metadata,
267 &histogram_data_ptr->logged_metadata);
243 DCHECK(histogram); 268 DCHECK(histogram);
244 break; 269 break;
245 case LINEAR_HISTOGRAM: 270 case LINEAR_HISTOGRAM:
246 histogram = LinearHistogram::PersistentGet( 271 histogram = LinearHistogram::PersistentGet(
247 name, 272 name,
248 histogram_data.minimum, 273 histogram_data.minimum,
249 histogram_data.maximum, 274 histogram_data.maximum,
250 ranges, 275 ranges,
251 counts_data, 276 counts_data,
277 logged_data,
252 histogram_data.bucket_count, 278 histogram_data.bucket_count,
253 &histogram_data_ptr->samples_metadata); 279 &histogram_data_ptr->samples_metadata,
280 &histogram_data_ptr->logged_metadata);
254 DCHECK(histogram); 281 DCHECK(histogram);
255 break; 282 break;
256 case BOOLEAN_HISTOGRAM: 283 case BOOLEAN_HISTOGRAM:
257 histogram = BooleanHistogram::PersistentGet( 284 histogram = BooleanHistogram::PersistentGet(
258 name, 285 name,
259 ranges, 286 ranges,
260 counts_data, 287 counts_data,
261 &histogram_data_ptr->samples_metadata); 288 logged_data,
289 &histogram_data_ptr->samples_metadata,
290 &histogram_data_ptr->logged_metadata);
262 DCHECK(histogram); 291 DCHECK(histogram);
263 break; 292 break;
264 case CUSTOM_HISTOGRAM: 293 case CUSTOM_HISTOGRAM:
265 histogram = CustomHistogram::PersistentGet( 294 histogram = CustomHistogram::PersistentGet(
266 name, 295 name,
267 ranges, 296 ranges,
268 counts_data, 297 counts_data,
298 logged_data,
269 histogram_data.bucket_count, 299 histogram_data.bucket_count,
270 &histogram_data_ptr->samples_metadata); 300 &histogram_data_ptr->samples_metadata,
301 &histogram_data_ptr->logged_metadata);
271 DCHECK(histogram); 302 DCHECK(histogram);
272 break; 303 break;
273 default: 304 default:
274 NOTREACHED(); 305 NOTREACHED();
275 } 306 }
276 307
277 if (histogram) { 308 if (histogram) {
278 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); 309 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType());
279 histogram->SetFlags(histogram_data.flags); 310 histogram->SetFlags(histogram_data.flags);
280 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); 311 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 HistogramType histogram_type, 366 HistogramType histogram_type,
336 const std::string& name, 367 const std::string& name,
337 int minimum, 368 int minimum,
338 int maximum, 369 int maximum,
339 const BucketRanges* bucket_ranges, 370 const BucketRanges* bucket_ranges,
340 int32_t flags, 371 int32_t flags,
341 PersistentMemoryAllocator::Reference* ref_ptr) { 372 PersistentMemoryAllocator::Reference* ref_ptr) {
342 if (!allocator) 373 if (!allocator)
343 return nullptr; 374 return nullptr;
344 375
376 // If RequiredCountsBytes() returns zero then the bucket_count was not valid.
345 size_t bucket_count = bucket_ranges->bucket_count(); 377 size_t bucket_count = bucket_ranges->bucket_count();
346 // An overflow such as this, perhaps as the result of a milicious actor, 378 size_t counts_bytes = RequiredCountsBytes(bucket_count);
Alexei Svitkine (slow) 2016/02/17 16:21:12 Make the function return size_t instead of uint32_
bcwhite 2016/02/17 17:58:20 Done.
347 // could lead to writing beyond the allocation boundary and into other 379 if (!counts_bytes) {
348 // memory. Just fail the allocation and let the caller deal with it.
349 if (bucket_count > std::numeric_limits<int32_t>::max() /
350 sizeof(HistogramBase::AtomicCount)) {
351 NOTREACHED(); 380 NOTREACHED();
352 return nullptr; 381 return nullptr;
353 } 382 }
354 size_t counts_bytes = bucket_count * sizeof(HistogramBase::AtomicCount); 383
355 size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample); 384 size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample);
356 PersistentMemoryAllocator::Reference ranges_ref = 385 PersistentMemoryAllocator::Reference ranges_ref =
357 allocator->Allocate(ranges_bytes, kTypeIdRangesArray); 386 allocator->Allocate(ranges_bytes, kTypeIdRangesArray);
358 PersistentMemoryAllocator::Reference counts_ref = 387 PersistentMemoryAllocator::Reference counts_ref =
359 allocator->Allocate(counts_bytes, kTypeIdCountsArray); 388 allocator->Allocate(counts_bytes, kTypeIdCountsArray);
360 PersistentMemoryAllocator::Reference histogram_ref = 389 PersistentMemoryAllocator::Reference histogram_ref =
361 allocator->Allocate(offsetof(PersistentHistogramData, name) + 390 allocator->Allocate(offsetof(PersistentHistogramData, name) +
362 name.length() + 1, kTypeIdHistogram); 391 name.length() + 1, kTypeIdHistogram);
363 HistogramBase::Sample* ranges_data = 392 HistogramBase::Sample* ranges_data =
364 allocator->GetAsObject<HistogramBase::Sample>(ranges_ref, 393 allocator->GetAsObject<HistogramBase::Sample>(ranges_ref,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 for (;;) { 459 for (;;) {
431 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); 460 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter);
432 if (!histogram) 461 if (!histogram)
433 break; 462 break;
434 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); 463 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram);
435 } 464 }
436 } 465 }
437 } 466 }
438 467
439 } // namespace base 468 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698