OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/persistent_histogram_allocator.h" | 5 #include "base/metrics/persistent_histogram_allocator.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/atomicops.h" | 9 #include "base/atomicops.h" |
10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 static constexpr size_t kExpectedInstanceSize = | 233 static constexpr size_t kExpectedInstanceSize = |
234 40 + 2 * HistogramSamples::Metadata::kExpectedInstanceSize; | 234 40 + 2 * HistogramSamples::Metadata::kExpectedInstanceSize; |
235 | 235 |
236 int32_t histogram_type; | 236 int32_t histogram_type; |
237 int32_t flags; | 237 int32_t flags; |
238 int32_t minimum; | 238 int32_t minimum; |
239 int32_t maximum; | 239 int32_t maximum; |
240 uint32_t bucket_count; | 240 uint32_t bucket_count; |
241 PersistentMemoryAllocator::Reference ranges_ref; | 241 PersistentMemoryAllocator::Reference ranges_ref; |
242 uint32_t ranges_checksum; | 242 uint32_t ranges_checksum; |
243 subtle::Atomic32 counts_ref; // PersistentMemoryAllocator::Reference | 243 PersistentMemoryAllocator::Reference counts_ref; |
244 HistogramSamples::Metadata samples_metadata; | 244 HistogramSamples::Metadata samples_metadata; |
245 HistogramSamples::Metadata logged_metadata; | 245 HistogramSamples::Metadata logged_metadata; |
246 | 246 |
247 // Space for the histogram name will be added during the actual allocation | 247 // Space for the histogram name will be added during the actual allocation |
248 // request. This must be the last field of the structure. A zero-size array | 248 // request. This must be the last field of the structure. A zero-size array |
249 // or a "flexible" array would be preferred but is not (yet) valid C++. | 249 // or a "flexible" array would be preferred but is not (yet) valid C++. |
250 char name[sizeof(uint64_t)]; // Force 64-bit alignment on 32-bit builds. | 250 char name[sizeof(uint64_t)]; // Force 64-bit alignment on 32-bit builds. |
251 }; | 251 }; |
252 | 252 |
253 PersistentHistogramAllocator::Iterator::Iterator( | 253 PersistentHistogramAllocator::Iterator::Iterator( |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 } else { | 368 } else { |
369 // This should never happen but be tolerant if it does. | 369 // This should never happen but be tolerant if it does. |
370 NOTREACHED(); | 370 NOTREACHED(); |
371 ranges_ref = PersistentMemoryAllocator::kReferenceNull; | 371 ranges_ref = PersistentMemoryAllocator::kReferenceNull; |
372 } | 372 } |
373 } | 373 } |
374 } else { | 374 } else { |
375 DCHECK_EQ(kTypeIdRangesArray, memory_allocator_->GetType(ranges_ref)); | 375 DCHECK_EQ(kTypeIdRangesArray, memory_allocator_->GetType(ranges_ref)); |
376 } | 376 } |
377 | 377 |
| 378 PersistentMemoryAllocator::Reference counts_ref = |
| 379 memory_allocator_->Allocate(counts_bytes, kTypeIdCountsArray); |
378 | 380 |
379 // Only continue here if all allocations were successful. If they weren't, | 381 // Only continue here if all allocations were successful. If they weren't, |
380 // there is no way to free the space but that's not really a problem since | 382 // there is no way to free the space but that's not really a problem since |
381 // the allocations only fail because the space is full or corrupt and so | 383 // the allocations only fail because the space is full or corrupt and so |
382 // any future attempts will also fail. | 384 // any future attempts will also fail. |
383 if (ranges_ref && histogram_data) { | 385 if (counts_ref && ranges_ref && histogram_data) { |
384 histogram_data->minimum = minimum; | 386 histogram_data->minimum = minimum; |
385 histogram_data->maximum = maximum; | 387 histogram_data->maximum = maximum; |
386 // |bucket_count| must fit within 32-bits or the allocation of the counts | 388 // |bucket_count| must fit within 32-bits or the allocation of the counts |
387 // array would have failed for being too large; the allocator supports | 389 // array would have failed for being too large; the allocator supports |
388 // less than 4GB total size. | 390 // less than 4GB total size. |
389 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count); | 391 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count); |
390 histogram_data->ranges_ref = ranges_ref; | 392 histogram_data->ranges_ref = ranges_ref; |
391 histogram_data->ranges_checksum = bucket_ranges->checksum(); | 393 histogram_data->ranges_checksum = bucket_ranges->checksum(); |
| 394 histogram_data->counts_ref = counts_ref; |
392 } else { | 395 } else { |
393 histogram_data = nullptr; // Clear this for proper handling below. | 396 histogram_data = nullptr; // Clear this for proper handling below. |
394 } | 397 } |
395 } | 398 } |
396 | 399 |
397 if (histogram_data) { | 400 if (histogram_data) { |
398 // Create the histogram using resources in persistent memory. This ends up | 401 // Create the histogram using resources in persistent memory. This ends up |
399 // resolving the "ref" values stored in histogram_data instad of just | 402 // resolving the "ref" values stored in histogram_data instad of just |
400 // using what is already known above but avoids duplicating the switch | 403 // using what is already known above but avoids duplicating the switch |
401 // statement here and serves as a double-check that everything is | 404 // statement here and serves as a double-check that everything is |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 histogram_data.bucket_count + 1); | 599 histogram_data.bucket_count + 1); |
597 if (!created_ranges) { | 600 if (!created_ranges) { |
598 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); | 601 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); |
599 NOTREACHED(); | 602 NOTREACHED(); |
600 return nullptr; | 603 return nullptr; |
601 } | 604 } |
602 const BucketRanges* ranges = | 605 const BucketRanges* ranges = |
603 StatisticsRecorder::RegisterOrDeleteDuplicateRanges( | 606 StatisticsRecorder::RegisterOrDeleteDuplicateRanges( |
604 created_ranges.release()); | 607 created_ranges.release()); |
605 | 608 |
| 609 HistogramBase::AtomicCount* counts_data = |
| 610 memory_allocator_->GetAsArray<HistogramBase::AtomicCount>( |
| 611 histogram_data.counts_ref, kTypeIdCountsArray, |
| 612 PersistentMemoryAllocator::kSizeAny); |
606 size_t counts_bytes = | 613 size_t counts_bytes = |
607 CalculateRequiredCountsBytes(histogram_data.bucket_count); | 614 CalculateRequiredCountsBytes(histogram_data.bucket_count); |
608 PersistentMemoryAllocator::Reference counts_ref = | 615 if (!counts_data || counts_bytes == 0 || |
609 subtle::NoBarrier_Load(&histogram_data.counts_ref); | 616 memory_allocator_->GetAllocSize(histogram_data.counts_ref) < |
610 if (counts_bytes == 0 || | 617 counts_bytes) { |
611 (counts_ref != 0 && | |
612 memory_allocator_->GetAllocSize(counts_ref) < counts_bytes)) { | |
613 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); | 618 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); |
614 NOTREACHED(); | 619 NOTREACHED(); |
615 return nullptr; | 620 return nullptr; |
616 } | 621 } |
617 | 622 |
618 // The "counts" data (including both samples and logged samples) is a delayed | 623 // After the main "counts" array is a second array using for storing what |
619 // persistent allocation meaning that though its size and storage for a | 624 // was previously logged. This is used to calculate the "delta" during |
620 // reference is defined, no space is reserved until actually needed. When | 625 // snapshot operations. |
621 // it is needed, memory will be allocated from the persistent segment and | 626 HistogramBase::AtomicCount* logged_data = |
622 // a reference to it stored at the passed address. Other threads can then | 627 counts_data + histogram_data.bucket_count; |
623 // notice the valid reference and access the same data. | |
624 DelayedPersistentAllocation counts_data(memory_allocator_.get(), | |
625 &histogram_data_ptr->counts_ref, | |
626 kTypeIdCountsArray, counts_bytes, 0); | |
627 | 628 |
628 // A second delayed allocations is defined using the same reference storage | |
629 // location as the first so the allocation of one will automatically be found | |
630 // by the other. Within the block, the first half of the space is for "counts" | |
631 // and the second half is for "logged counts". | |
632 DelayedPersistentAllocation logged_data( | |
633 memory_allocator_.get(), &histogram_data_ptr->counts_ref, | |
634 kTypeIdCountsArray, counts_bytes, counts_bytes / 2, | |
635 /*make_iterable=*/false); | |
636 | |
637 // Create the right type of histogram. | |
638 std::string name(histogram_data_ptr->name); | 629 std::string name(histogram_data_ptr->name); |
639 std::unique_ptr<HistogramBase> histogram; | 630 std::unique_ptr<HistogramBase> histogram; |
640 switch (histogram_data.histogram_type) { | 631 switch (histogram_data.histogram_type) { |
641 case HISTOGRAM: | 632 case HISTOGRAM: |
642 histogram = Histogram::PersistentCreate( | 633 histogram = Histogram::PersistentCreate( |
643 name, histogram_data.minimum, histogram_data.maximum, ranges, | 634 name, histogram_data.minimum, histogram_data.maximum, ranges, |
644 counts_data, logged_data, &histogram_data_ptr->samples_metadata, | 635 counts_data, logged_data, histogram_data.bucket_count, |
| 636 &histogram_data_ptr->samples_metadata, |
645 &histogram_data_ptr->logged_metadata); | 637 &histogram_data_ptr->logged_metadata); |
646 DCHECK(histogram); | 638 DCHECK(histogram); |
647 break; | 639 break; |
648 case LINEAR_HISTOGRAM: | 640 case LINEAR_HISTOGRAM: |
649 histogram = LinearHistogram::PersistentCreate( | 641 histogram = LinearHistogram::PersistentCreate( |
650 name, histogram_data.minimum, histogram_data.maximum, ranges, | 642 name, histogram_data.minimum, histogram_data.maximum, ranges, |
651 counts_data, logged_data, &histogram_data_ptr->samples_metadata, | 643 counts_data, logged_data, histogram_data.bucket_count, |
| 644 &histogram_data_ptr->samples_metadata, |
652 &histogram_data_ptr->logged_metadata); | 645 &histogram_data_ptr->logged_metadata); |
653 DCHECK(histogram); | 646 DCHECK(histogram); |
654 break; | 647 break; |
655 case BOOLEAN_HISTOGRAM: | 648 case BOOLEAN_HISTOGRAM: |
656 histogram = BooleanHistogram::PersistentCreate( | 649 histogram = BooleanHistogram::PersistentCreate( |
657 name, ranges, counts_data, logged_data, | 650 name, ranges, counts_data, logged_data, |
658 &histogram_data_ptr->samples_metadata, | 651 &histogram_data_ptr->samples_metadata, |
659 &histogram_data_ptr->logged_metadata); | 652 &histogram_data_ptr->logged_metadata); |
660 DCHECK(histogram); | 653 DCHECK(histogram); |
661 break; | 654 break; |
662 case CUSTOM_HISTOGRAM: | 655 case CUSTOM_HISTOGRAM: |
663 histogram = CustomHistogram::PersistentCreate( | 656 histogram = CustomHistogram::PersistentCreate( |
664 name, ranges, counts_data, logged_data, | 657 name, ranges, counts_data, logged_data, histogram_data.bucket_count, |
665 &histogram_data_ptr->samples_metadata, | 658 &histogram_data_ptr->samples_metadata, |
666 &histogram_data_ptr->logged_metadata); | 659 &histogram_data_ptr->logged_metadata); |
667 DCHECK(histogram); | 660 DCHECK(histogram); |
668 break; | 661 break; |
669 default: | 662 default: |
670 NOTREACHED(); | 663 NOTREACHED(); |
671 } | 664 } |
672 | 665 |
673 if (histogram) { | 666 if (histogram) { |
674 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); | 667 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
960 while (true) { | 953 while (true) { |
961 std::unique_ptr<HistogramBase> histogram = | 954 std::unique_ptr<HistogramBase> histogram = |
962 import_iterator_.GetNextWithIgnore(record_to_ignore); | 955 import_iterator_.GetNextWithIgnore(record_to_ignore); |
963 if (!histogram) | 956 if (!histogram) |
964 break; | 957 break; |
965 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 958 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
966 } | 959 } |
967 } | 960 } |
968 | 961 |
969 } // namespace base | 962 } // namespace base |
OLD | NEW |