rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/metrics/histogram_snapshot_manager.h" |
| 6 | |
dcheng | cc8e4d8 | 2016-04-05 06:25:51 +0900 | [diff] [blame] | 7 | #include <memory> |
| 8 | |
bcwhite | cb532bf | 2016-04-06 04:41:53 +0900 | [diff] [blame] | 9 | #include "base/debug/alias.h" |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 10 | #include "base/metrics/histogram_flattener.h" |
| 11 | #include "base/metrics/histogram_samples.h" |
kaiwang@chromium.org | 3c57dc6 | 2012-07-14 06:48:29 +0900 | [diff] [blame] | 12 | #include "base/metrics/statistics_recorder.h" |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 13 | #include "base/stl_util.h" |
kaiwang@chromium.org | 3c57dc6 | 2012-07-14 06:48:29 +0900 | [diff] [blame] | 14 | |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 15 | namespace base { |
| 16 | |
bcwhite | bc44d70 | 2017-05-09 13:01:17 +0900 | [diff] [blame] | 17 | namespace { |
| 18 | |
| 19 | // A simple object to set an "active" flag and clear it upon destruction. It is |
| 20 | // an error if the flag is already set. |
| 21 | class MakeActive { |
| 22 | public: |
| 23 | MakeActive(std::atomic<bool>* is_active) : is_active_(is_active) { |
| 24 | bool was_active = is_active_->exchange(true, std::memory_order_relaxed); |
| 25 | CHECK(!was_active); |
| 26 | } |
| 27 | ~MakeActive() { is_active_->store(false, std::memory_order_relaxed); } |
| 28 | |
| 29 | private: |
| 30 | std::atomic<bool>* is_active_; |
| 31 | |
| 32 | DISALLOW_COPY_AND_ASSIGN(MakeActive); |
| 33 | }; |
| 34 | |
| 35 | } // namespace |
| 36 | |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 37 | HistogramSnapshotManager::HistogramSnapshotManager( |
| 38 | HistogramFlattener* histogram_flattener) |
bcwhite | 271dcde | 2016-07-13 11:49:11 +0900 | [diff] [blame] | 39 | : histogram_flattener_(histogram_flattener) { |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 40 | DCHECK(histogram_flattener_); |
bcwhite | bc44d70 | 2017-05-09 13:01:17 +0900 | [diff] [blame] | 41 | is_active_.store(false, std::memory_order_relaxed); |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 42 | } |
| 43 | |
Chris Watkins | d155d9f | 2017-11-29 16:16:38 +0900 | [diff] [blame^] | 44 | HistogramSnapshotManager::~HistogramSnapshotManager() = default; |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 45 | |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 46 | void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) { |
Brian White | 385ec10 | 2017-08-11 15:26:26 +0900 | [diff] [blame] | 47 | if (!histogram->ValidateHistogramContents(true, 0)) |
| 48 | return; |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 49 | PrepareSamples(histogram, histogram->SnapshotDelta()); |
| 50 | } |
| 51 | |
bcwhite | 271dcde | 2016-07-13 11:49:11 +0900 | [diff] [blame] | 52 | void HistogramSnapshotManager::PrepareFinalDelta( |
| 53 | const HistogramBase* histogram) { |
Brian White | 385ec10 | 2017-08-11 15:26:26 +0900 | [diff] [blame] | 54 | if (!histogram->ValidateHistogramContents(true, 0)) |
| 55 | return; |
bcwhite | 271dcde | 2016-07-13 11:49:11 +0900 | [diff] [blame] | 56 | PrepareSamples(histogram, histogram->SnapshotFinalDelta()); |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 57 | } |
| 58 | |
| 59 | void HistogramSnapshotManager::PrepareSamples( |
| 60 | const HistogramBase* histogram, |
dcheng | cc8e4d8 | 2016-04-05 06:25:51 +0900 | [diff] [blame] | 61 | std::unique_ptr<HistogramSamples> samples) { |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 62 | DCHECK(histogram_flattener_); |
| 63 | |
bcwhite | bc44d70 | 2017-05-09 13:01:17 +0900 | [diff] [blame] | 64 | // Ensure that there is no concurrent access going on while accessing the |
| 65 | // set of known histograms. The flag will be reset when this object goes |
| 66 | // out of scope. |
| 67 | MakeActive make_active(&is_active_); |
| 68 | |
bcwhite | 271dcde | 2016-07-13 11:49:11 +0900 | [diff] [blame] | 69 | // Get information known about this histogram. If it did not previously |
| 70 | // exist, one will be created and initialized. |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 71 | SampleInfo* sample_info = &known_histograms_[histogram->name_hash()]; |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 72 | |
| 73 | // Crash if we detect that our histograms have been overwritten. This may be |
| 74 | // a fair distance from the memory smasher, but we hope to correlate these |
| 75 | // crashes with other events, such as plugins, or usage patterns, etc. |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 76 | uint32_t corruption = histogram->FindCorruption(*samples); |
kaiwang@chromium.org | 7881e42 | 2013-03-01 12:53:25 +0900 | [diff] [blame] | 77 | if (HistogramBase::BUCKET_ORDER_ERROR & corruption) { |
bcwhite | 60a5d37 | 2016-07-13 12:58:09 +0900 | [diff] [blame] | 78 | // Extract fields useful during debug. |
| 79 | const BucketRanges* ranges = |
| 80 | static_cast<const Histogram*>(histogram)->bucket_ranges(); |
bcwhite | b47b11e | 2016-09-23 23:02:04 +0900 | [diff] [blame] | 81 | uint32_t ranges_checksum = ranges->checksum(); |
| 82 | uint32_t ranges_calc_checksum = ranges->CalculateChecksum(); |
bcwhite | 60a5d37 | 2016-07-13 12:58:09 +0900 | [diff] [blame] | 83 | int32_t flags = histogram->flags(); |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 84 | // The checksum should have caught this, so crash separately if it didn't. |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 85 | CHECK_NE(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 86 | CHECK(false); // Crash for the bucket order corruption. |
bcwhite | cb532bf | 2016-04-06 04:41:53 +0900 | [diff] [blame] | 87 | // Ensure that compiler keeps around pointers to |histogram| and its |
| 88 | // internal |bucket_ranges_| for any minidumps. |
bcwhite | b47b11e | 2016-09-23 23:02:04 +0900 | [diff] [blame] | 89 | base::debug::Alias(&ranges_checksum); |
| 90 | base::debug::Alias(&ranges_calc_checksum); |
bcwhite | 60a5d37 | 2016-07-13 12:58:09 +0900 | [diff] [blame] | 91 | base::debug::Alias(&flags); |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 92 | } |
| 93 | // Checksum corruption might not have caused order corruption. |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 94 | CHECK_EQ(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 95 | |
kaiwang@chromium.org | c239f5a | 2012-08-21 08:53:15 +0900 | [diff] [blame] | 96 | // Note, at this point corruption can only be COUNT_HIGH_ERROR or |
| 97 | // COUNT_LOW_ERROR and they never arise together, so we don't need to extract |
| 98 | // bits from corruption. |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 99 | if (corruption) { |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 100 | DLOG(ERROR) << "Histogram: \"" << histogram->histogram_name() |
| 101 | << "\" has data corruption: " << corruption; |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 102 | // Don't record corrupt data to metrics services. |
bcwhite | b73fa82 | 2016-02-19 06:22:14 +0900 | [diff] [blame] | 103 | const uint32_t old_corruption = sample_info->inconsistencies; |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 104 | if (old_corruption == (corruption | old_corruption)) |
| 105 | return; // We've already seen this corruption for this histogram. |
bcwhite | 271dcde | 2016-07-13 11:49:11 +0900 | [diff] [blame] | 106 | sample_info->inconsistencies |= corruption; |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 107 | return; |
| 108 | } |
| 109 | |
bcwhite | 271dcde | 2016-07-13 11:49:11 +0900 | [diff] [blame] | 110 | if (samples->TotalCount() > 0) |
| 111 | histogram_flattener_->RecordDelta(*histogram, *samples); |
kaiwang@chromium.org | 0ce37b1 | 2012-09-22 12:42:12 +0900 | [diff] [blame] | 112 | } |
| 113 | |
rtenneti@google.com | 1c05d34 | 2012-07-13 03:19:45 +0900 | [diff] [blame] | 114 | } // namespace base |