| 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 |