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

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: addressed remaining review comments by Alexei 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
« no previous file with comments | « base/metrics/histogram_base.cc ('k') | base/metrics/histogram_snapshot_manager.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 struct PersistentHistogramData { 69 struct PersistentHistogramData {
70 int histogram_type; 70 int histogram_type;
71 int flags; 71 int flags;
72 int minimum; 72 int minimum;
73 int maximum; 73 int maximum;
74 uint32_t bucket_count; 74 uint32_t bucket_count;
75 PersistentMemoryAllocator::Reference ranges_ref; 75 PersistentMemoryAllocator::Reference ranges_ref;
76 uint32_t ranges_checksum; 76 uint32_t ranges_checksum;
77 PersistentMemoryAllocator::Reference counts_ref; 77 PersistentMemoryAllocator::Reference counts_ref;
78 HistogramSamples::Metadata samples_metadata; 78 HistogramSamples::Metadata samples_metadata;
79 HistogramSamples::Metadata logged_metadata;
79 80
80 // Space for the histogram name will be added during the actual allocation 81 // Space for the histogram name will be added during the actual allocation
81 // request. This must be the last field of the structure. A zero-size array 82 // request. This must be the last field of the structure. A zero-size array
82 // or a "flexible" array would be preferred but is not (yet) valid C++. 83 // or a "flexible" array would be preferred but is not (yet) valid C++.
83 char name[1]; 84 char name[1];
84 }; 85 };
85 86
86 // The object held here will obviously not be destructed at process exit 87 // The object held here will obviously not be destructed at process exit
87 // but that's okay since PersistentMemoryAllocator objects are explicitly 88 // but that's okay since PersistentMemoryAllocator objects are explicitly
88 // forbidden from doing anything essential at exit anyway due to the fact 89 // forbidden from doing anything essential at exit anyway due to the fact
(...skipping 15 matching lines...) Expand all
104 ranges->set_range(i, ranges_data[i]); 105 ranges->set_range(i, ranges_data[i]);
105 } 106 }
106 107
107 ranges->ResetChecksum(); 108 ranges->ResetChecksum();
108 if (ranges->checksum() != ranges_checksum) 109 if (ranges->checksum() != ranges_checksum)
109 return nullptr; 110 return nullptr;
110 111
111 return ranges.release(); 112 return ranges.release();
112 } 113 }
113 114
115 // Calculate the number of bytes required to store all of a histogram's
116 // "counts". This will return zero (0) if |bucket_count| is not valid.
117 size_t CalculateRequiredCountsBytes(size_t bucket_count) {
118 // 2 because each "sample count" also requires a backup "logged count"
119 // used for calculating the delta during snapshot operations.
120 const unsigned kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount);
121
122 // If the |bucket_count| is such that it would overflow the return type,
123 // perhaps as the result of a malicious actor, then return zero to
124 // indicate the problem to the caller.
125 if (bucket_count > std::numeric_limits<uint32_t>::max() / kBytesPerBucket)
126 return 0;
127
128 return bucket_count * kBytesPerBucket;
129 }
130
114 } // namespace 131 } // namespace
115 132
116 const Feature kPersistentHistogramsFeature{ 133 const Feature kPersistentHistogramsFeature{
117 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT 134 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
118 }; 135 };
119 136
120 // Get the histogram in which create results are stored. This is copied almost 137 // Get the histogram in which create results are stored. This is copied almost
121 // exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with added code 138 // exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with added code
122 // to prevent recursion (a likely occurance because the creation of a new 139 // to prevent recursion (a likely occurance because the creation of a new
123 // histogram can end up calling this.) 140 // histogram can end up calling this.)
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 if (!ranges) { 254 if (!ranges) {
238 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); 255 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
239 NOTREACHED(); 256 NOTREACHED();
240 return nullptr; 257 return nullptr;
241 } 258 }
242 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); 259 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
243 260
244 HistogramBase::AtomicCount* counts_data = 261 HistogramBase::AtomicCount* counts_data =
245 allocator->GetAsObject<HistogramBase::AtomicCount>( 262 allocator->GetAsObject<HistogramBase::AtomicCount>(
246 histogram_data.counts_ref, kTypeIdCountsArray); 263 histogram_data.counts_ref, kTypeIdCountsArray);
247 if (!counts_data || 264 size_t counts_bytes =
248 allocator->GetAllocSize(histogram_data.counts_ref) < 265 CalculateRequiredCountsBytes(histogram_data.bucket_count);
249 histogram_data.bucket_count * sizeof(HistogramBase::AtomicCount)) { 266 if (!counts_data || !counts_bytes ||
267 allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) {
250 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); 268 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY);
251 NOTREACHED(); 269 NOTREACHED();
252 return nullptr; 270 return nullptr;
253 } 271 }
254 272
273 // After the main "counts" array is a second array using for storing what
274 // was previously logged. This is used to calculate the "delta" during
275 // snapshot operations.
276 HistogramBase::AtomicCount* logged_data =
277 counts_data + histogram_data.bucket_count;
278
255 std::string name(histogram_data_ptr->name); 279 std::string name(histogram_data_ptr->name);
256 HistogramBase* histogram = nullptr; 280 HistogramBase* histogram = nullptr;
257 switch (histogram_data.histogram_type) { 281 switch (histogram_data.histogram_type) {
258 case HISTOGRAM: 282 case HISTOGRAM:
259 histogram = Histogram::PersistentGet( 283 histogram = Histogram::PersistentGet(
260 name, 284 name,
261 histogram_data.minimum, 285 histogram_data.minimum,
262 histogram_data.maximum, 286 histogram_data.maximum,
263 ranges, 287 ranges,
264 counts_data, 288 counts_data,
289 logged_data,
265 histogram_data.bucket_count, 290 histogram_data.bucket_count,
266 &histogram_data_ptr->samples_metadata); 291 &histogram_data_ptr->samples_metadata,
292 &histogram_data_ptr->logged_metadata);
267 DCHECK(histogram); 293 DCHECK(histogram);
268 break; 294 break;
269 case LINEAR_HISTOGRAM: 295 case LINEAR_HISTOGRAM:
270 histogram = LinearHistogram::PersistentGet( 296 histogram = LinearHistogram::PersistentGet(
271 name, 297 name,
272 histogram_data.minimum, 298 histogram_data.minimum,
273 histogram_data.maximum, 299 histogram_data.maximum,
274 ranges, 300 ranges,
275 counts_data, 301 counts_data,
302 logged_data,
276 histogram_data.bucket_count, 303 histogram_data.bucket_count,
277 &histogram_data_ptr->samples_metadata); 304 &histogram_data_ptr->samples_metadata,
305 &histogram_data_ptr->logged_metadata);
278 DCHECK(histogram); 306 DCHECK(histogram);
279 break; 307 break;
280 case BOOLEAN_HISTOGRAM: 308 case BOOLEAN_HISTOGRAM:
281 histogram = BooleanHistogram::PersistentGet( 309 histogram = BooleanHistogram::PersistentGet(
282 name, 310 name,
283 ranges, 311 ranges,
284 counts_data, 312 counts_data,
285 &histogram_data_ptr->samples_metadata); 313 logged_data,
314 &histogram_data_ptr->samples_metadata,
315 &histogram_data_ptr->logged_metadata);
286 DCHECK(histogram); 316 DCHECK(histogram);
287 break; 317 break;
288 case CUSTOM_HISTOGRAM: 318 case CUSTOM_HISTOGRAM:
289 histogram = CustomHistogram::PersistentGet( 319 histogram = CustomHistogram::PersistentGet(
290 name, 320 name,
291 ranges, 321 ranges,
292 counts_data, 322 counts_data,
323 logged_data,
293 histogram_data.bucket_count, 324 histogram_data.bucket_count,
294 &histogram_data_ptr->samples_metadata); 325 &histogram_data_ptr->samples_metadata,
326 &histogram_data_ptr->logged_metadata);
295 DCHECK(histogram); 327 DCHECK(histogram);
296 break; 328 break;
297 default: 329 default:
298 NOTREACHED(); 330 NOTREACHED();
299 } 331 }
300 332
301 if (histogram) { 333 if (histogram) {
302 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); 334 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType());
303 histogram->SetFlags(histogram_data.flags); 335 histogram->SetFlags(histogram_data.flags);
304 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); 336 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS);
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 400
369 // If the allocator is corrupt, don't waste time trying anything else. 401 // If the allocator is corrupt, don't waste time trying anything else.
370 // This also allows differentiating on the dashboard between allocations 402 // This also allows differentiating on the dashboard between allocations
371 // failed due to a corrupt allocator and the number of process instances 403 // failed due to a corrupt allocator and the number of process instances
372 // with one, the latter being idicated by "newly corrupt", below. 404 // with one, the latter being idicated by "newly corrupt", below.
373 if (allocator->IsCorrupt()) { 405 if (allocator->IsCorrupt()) {
374 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT); 406 RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT);
375 return nullptr; 407 return nullptr;
376 } 408 }
377 409
410 // If CalculateRequiredCountsBytes() returns zero then the bucket_count
411 // was not valid.
378 size_t bucket_count = bucket_ranges->bucket_count(); 412 size_t bucket_count = bucket_ranges->bucket_count();
379 // An overflow such as this, perhaps as the result of a milicious actor, 413 size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count);
380 // could lead to writing beyond the allocation boundary and into other 414 if (!counts_bytes) {
381 // memory. Just fail the allocation and let the caller deal with it.
382 if (bucket_count > std::numeric_limits<int32_t>::max() /
383 sizeof(HistogramBase::AtomicCount)) {
384 NOTREACHED(); 415 NOTREACHED();
385 return nullptr; 416 return nullptr;
386 } 417 }
387 size_t counts_bytes = bucket_count * sizeof(HistogramBase::AtomicCount); 418
388 size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample); 419 size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample);
389 PersistentMemoryAllocator::Reference ranges_ref = 420 PersistentMemoryAllocator::Reference ranges_ref =
390 allocator->Allocate(ranges_bytes, kTypeIdRangesArray); 421 allocator->Allocate(ranges_bytes, kTypeIdRangesArray);
391 PersistentMemoryAllocator::Reference counts_ref = 422 PersistentMemoryAllocator::Reference counts_ref =
392 allocator->Allocate(counts_bytes, kTypeIdCountsArray); 423 allocator->Allocate(counts_bytes, kTypeIdCountsArray);
393 PersistentMemoryAllocator::Reference histogram_ref = 424 PersistentMemoryAllocator::Reference histogram_ref =
394 allocator->Allocate(offsetof(PersistentHistogramData, name) + 425 allocator->Allocate(offsetof(PersistentHistogramData, name) +
395 name.length() + 1, kTypeIdHistogram); 426 name.length() + 1, kTypeIdHistogram);
396 HistogramBase::Sample* ranges_data = 427 HistogramBase::Sample* ranges_data =
397 allocator->GetAsObject<HistogramBase::Sample>(ranges_ref, 428 allocator->GetAsObject<HistogramBase::Sample>(ranges_ref,
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 for (;;) { 495 for (;;) {
465 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); 496 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter);
466 if (!histogram) 497 if (!histogram)
467 break; 498 break;
468 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); 499 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram);
469 } 500 }
470 } 501 }
471 } 502 }
472 503
473 } // namespace base 504 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/histogram_base.cc ('k') | base/metrics/histogram_snapshot_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698