| 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 |
| 636 // Create the right type of histogram. |
| 629 std::string name(histogram_data_ptr->name); | 637 std::string name(histogram_data_ptr->name); |
| 630 std::unique_ptr<HistogramBase> histogram; | 638 std::unique_ptr<HistogramBase> histogram; |
| 631 switch (histogram_data.histogram_type) { | 639 switch (histogram_data.histogram_type) { |
| 632 case HISTOGRAM: | 640 case HISTOGRAM: |
| 633 histogram = Histogram::PersistentCreate( | 641 histogram = Histogram::PersistentCreate( |
| 634 name, histogram_data.minimum, histogram_data.maximum, ranges, | 642 name, histogram_data.minimum, histogram_data.maximum, ranges, |
| 635 counts_data, logged_data, histogram_data.bucket_count, | 643 counts_data, logged_data, &histogram_data_ptr->samples_metadata, |
| 636 &histogram_data_ptr->samples_metadata, | |
| 637 &histogram_data_ptr->logged_metadata); | 644 &histogram_data_ptr->logged_metadata); |
| 638 DCHECK(histogram); | 645 DCHECK(histogram); |
| 639 break; | 646 break; |
| 640 case LINEAR_HISTOGRAM: | 647 case LINEAR_HISTOGRAM: |
| 641 histogram = LinearHistogram::PersistentCreate( | 648 histogram = LinearHistogram::PersistentCreate( |
| 642 name, histogram_data.minimum, histogram_data.maximum, ranges, | 649 name, histogram_data.minimum, histogram_data.maximum, ranges, |
| 643 counts_data, logged_data, histogram_data.bucket_count, | 650 counts_data, logged_data, &histogram_data_ptr->samples_metadata, |
| 644 &histogram_data_ptr->samples_metadata, | |
| 645 &histogram_data_ptr->logged_metadata); | 651 &histogram_data_ptr->logged_metadata); |
| 646 DCHECK(histogram); | 652 DCHECK(histogram); |
| 647 break; | 653 break; |
| 648 case BOOLEAN_HISTOGRAM: | 654 case BOOLEAN_HISTOGRAM: |
| 649 histogram = BooleanHistogram::PersistentCreate( | 655 histogram = BooleanHistogram::PersistentCreate( |
| 650 name, ranges, counts_data, logged_data, | 656 name, ranges, counts_data, logged_data, |
| 651 &histogram_data_ptr->samples_metadata, | 657 &histogram_data_ptr->samples_metadata, |
| 652 &histogram_data_ptr->logged_metadata); | 658 &histogram_data_ptr->logged_metadata); |
| 653 DCHECK(histogram); | 659 DCHECK(histogram); |
| 654 break; | 660 break; |
| 655 case CUSTOM_HISTOGRAM: | 661 case CUSTOM_HISTOGRAM: |
| 656 histogram = CustomHistogram::PersistentCreate( | 662 histogram = CustomHistogram::PersistentCreate( |
| 657 name, ranges, counts_data, logged_data, histogram_data.bucket_count, | 663 name, ranges, counts_data, logged_data, |
| 658 &histogram_data_ptr->samples_metadata, | 664 &histogram_data_ptr->samples_metadata, |
| 659 &histogram_data_ptr->logged_metadata); | 665 &histogram_data_ptr->logged_metadata); |
| 660 DCHECK(histogram); | 666 DCHECK(histogram); |
| 661 break; | 667 break; |
| 662 default: | 668 default: |
| 663 NOTREACHED(); | 669 NOTREACHED(); |
| 664 } | 670 } |
| 665 | 671 |
| 666 if (histogram) { | 672 if (histogram) { |
| 667 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); | 673 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 953 while (true) { | 959 while (true) { |
| 954 std::unique_ptr<HistogramBase> histogram = | 960 std::unique_ptr<HistogramBase> histogram = |
| 955 import_iterator_.GetNextWithIgnore(record_to_ignore); | 961 import_iterator_.GetNextWithIgnore(record_to_ignore); |
| 956 if (!histogram) | 962 if (!histogram) |
| 957 break; | 963 break; |
| 958 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); | 964 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release()); |
| 959 } | 965 } |
| 960 } | 966 } |
| 961 | 967 |
| 962 } // namespace base | 968 } // namespace base |
| OLD | NEW |