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 PersistentMemoryAllocator::Reference counts_ref; | 243 subtle::Atomic32 counts_ref; // PersistentMemoryAllocator::Reference |
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); | |
380 | 378 |
381 // Only continue here if all allocations were successful. If they weren't, | 379 // Only continue here if all allocations were successful. If they weren't, |
382 // there is no way to free the space but that's not really a problem since | 380 // there is no way to free the space but that's not really a problem since |
383 // the allocations only fail because the space is full or corrupt and so | 381 // the allocations only fail because the space is full or corrupt and so |
384 // any future attempts will also fail. | 382 // any future attempts will also fail. |
385 if (counts_ref && ranges_ref && histogram_data) { | 383 if (ranges_ref && histogram_data) { |
386 histogram_data->minimum = minimum; | 384 histogram_data->minimum = minimum; |
387 histogram_data->maximum = maximum; | 385 histogram_data->maximum = maximum; |
388 // |bucket_count| must fit within 32-bits or the allocation of the counts | 386 // |bucket_count| must fit within 32-bits or the allocation of the counts |
389 // array would have failed for being too large; the allocator supports | 387 // array would have failed for being too large; the allocator supports |
390 // less than 4GB total size. | 388 // less than 4GB total size. |
391 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count); | 389 histogram_data->bucket_count = static_cast<uint32_t>(bucket_count); |
392 histogram_data->ranges_ref = ranges_ref; | 390 histogram_data->ranges_ref = ranges_ref; |
393 histogram_data->ranges_checksum = bucket_ranges->checksum(); | 391 histogram_data->ranges_checksum = bucket_ranges->checksum(); |
394 histogram_data->counts_ref = counts_ref; | |
395 } else { | 392 } else { |
396 histogram_data = nullptr; // Clear this for proper handling below. | 393 histogram_data = nullptr; // Clear this for proper handling below. |
397 } | 394 } |
398 } | 395 } |
399 | 396 |
400 if (histogram_data) { | 397 if (histogram_data) { |
401 // Create the histogram using resources in persistent memory. This ends up | 398 // Create the histogram using resources in persistent memory. This ends up |
402 // resolving the "ref" values stored in histogram_data instad of just | 399 // resolving the "ref" values stored in histogram_data instad of just |
403 // using what is already known above but avoids duplicating the switch | 400 // using what is already known above but avoids duplicating the switch |
404 // statement here and serves as a double-check that everything is | 401 // statement here and serves as a double-check that everything is |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 histogram_data.bucket_count + 1); | 596 histogram_data.bucket_count + 1); |
600 if (!created_ranges) { | 597 if (!created_ranges) { |
601 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); | 598 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); |
602 NOTREACHED(); | 599 NOTREACHED(); |
603 return nullptr; | 600 return nullptr; |
604 } | 601 } |
605 const BucketRanges* ranges = | 602 const BucketRanges* ranges = |
606 StatisticsRecorder::RegisterOrDeleteDuplicateRanges( | 603 StatisticsRecorder::RegisterOrDeleteDuplicateRanges( |
607 created_ranges.release()); | 604 created_ranges.release()); |
608 | 605 |
609 HistogramBase::AtomicCount* counts_data = | |
610 memory_allocator_->GetAsArray<HistogramBase::AtomicCount>( | |
611 histogram_data.counts_ref, kTypeIdCountsArray, | |
612 PersistentMemoryAllocator::kSizeAny); | |
613 size_t counts_bytes = | 606 size_t counts_bytes = |
614 CalculateRequiredCountsBytes(histogram_data.bucket_count); | 607 CalculateRequiredCountsBytes(histogram_data.bucket_count); |
615 if (!counts_data || counts_bytes == 0 || | 608 PersistentMemoryAllocator::Reference counts_ref = |
616 memory_allocator_->GetAllocSize(histogram_data.counts_ref) < | 609 subtle::NoBarrier_Load(&histogram_data.counts_ref); |
617 counts_bytes) { | 610 if (counts_bytes == 0 || |
| 611 (counts_ref != 0 && |
| 612 memory_allocator_->GetAllocSize(counts_ref) < counts_bytes)) { |
618 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); | 613 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); |
619 NOTREACHED(); | 614 NOTREACHED(); |
620 return nullptr; | 615 return nullptr; |
621 } | 616 } |
622 | 617 |
623 // After the main "counts" array is a second array using for storing what | 618 // The "counts" data (including both samples and logged samples) is a delayed |
624 // was previously logged. This is used to calculate the "delta" during | 619 // persistent allocation meaning that though its size and storage for a |
625 // snapshot operations. | 620 // reference is defined, no space is reserved until actually needed. When |
626 HistogramBase::AtomicCount* logged_data = | 621 // it is needed, memory will be allocated from the persistent segment and |
627 counts_data + histogram_data.bucket_count; | 622 // a reference to it stored at the passed address. Other threads can then |
| 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); |
628 | 627 |
| 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. |
629 std::string name(histogram_data_ptr->name); | 638 std::string name(histogram_data_ptr->name); |
630 std::unique_ptr<HistogramBase> histogram; | 639 std::unique_ptr<HistogramBase> histogram; |
631 switch (histogram_data.histogram_type) { | 640 switch (histogram_data.histogram_type) { |
632 case HISTOGRAM: | 641 case HISTOGRAM: |
633 histogram = Histogram::PersistentCreate( | 642 histogram = Histogram::PersistentCreate( |
634 name, histogram_data.minimum, histogram_data.maximum, ranges, | 643 name, histogram_data.minimum, histogram_data.maximum, ranges, |
635 counts_data, logged_data, histogram_data.bucket_count, | 644 counts_data, logged_data, &histogram_data_ptr->samples_metadata, |
636 &histogram_data_ptr->samples_metadata, | |
637 &histogram_data_ptr->logged_metadata); | 645 &histogram_data_ptr->logged_metadata); |
638 DCHECK(histogram); | 646 DCHECK(histogram); |
639 break; | 647 break; |
640 case LINEAR_HISTOGRAM: | 648 case LINEAR_HISTOGRAM: |
641 histogram = LinearHistogram::PersistentCreate( | 649 histogram = LinearHistogram::PersistentCreate( |
642 name, histogram_data.minimum, histogram_data.maximum, ranges, | 650 name, histogram_data.minimum, histogram_data.maximum, ranges, |
643 counts_data, logged_data, histogram_data.bucket_count, | 651 counts_data, logged_data, &histogram_data_ptr->samples_metadata, |
644 &histogram_data_ptr->samples_metadata, | |
645 &histogram_data_ptr->logged_metadata); | 652 &histogram_data_ptr->logged_metadata); |
646 DCHECK(histogram); | 653 DCHECK(histogram); |
647 break; | 654 break; |
648 case BOOLEAN_HISTOGRAM: | 655 case BOOLEAN_HISTOGRAM: |
649 histogram = BooleanHistogram::PersistentCreate( | 656 histogram = BooleanHistogram::PersistentCreate( |
650 name, ranges, counts_data, logged_data, | 657 name, ranges, counts_data, logged_data, |
651 &histogram_data_ptr->samples_metadata, | 658 &histogram_data_ptr->samples_metadata, |
652 &histogram_data_ptr->logged_metadata); | 659 &histogram_data_ptr->logged_metadata); |
653 DCHECK(histogram); | 660 DCHECK(histogram); |
654 break; | 661 break; |
655 case CUSTOM_HISTOGRAM: | 662 case CUSTOM_HISTOGRAM: |
656 histogram = CustomHistogram::PersistentCreate( | 663 histogram = CustomHistogram::PersistentCreate( |
657 name, ranges, counts_data, logged_data, histogram_data.bucket_count, | 664 name, ranges, counts_data, logged_data, |
658 &histogram_data_ptr->samples_metadata, | 665 &histogram_data_ptr->samples_metadata, |
659 &histogram_data_ptr->logged_metadata); | 666 &histogram_data_ptr->logged_metadata); |
660 DCHECK(histogram); | 667 DCHECK(histogram); |
661 break; | 668 break; |
662 default: | 669 default: |
663 NOTREACHED(); | 670 NOTREACHED(); |
664 } | 671 } |
665 | 672 |
666 if (histogram) { | 673 if (histogram) { |
667 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); | 674 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
953 while (true) { | 960 while (true) { |
954 std::unique_ptr<HistogramBase> histogram = | 961 std::unique_ptr<HistogramBase> histogram = |
955 import_iterator_.GetNextWithIgnore(record_to_ignore); | 962 import_iterator_.GetNextWithIgnore(record_to_ignore); |
956 if (!histogram) | 963 if (!histogram) |
957 break; | 964 break; |
958 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 965 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
959 } | 966 } |
960 } | 967 } |
961 | 968 |
962 } // namespace base | 969 } // namespace base |
OLD | NEW |