blob: 7b3cff8b4d8d73ecfdd093122e571a06f7ac85c1 [file] [log] [blame]
rtenneti@google.com1c05d342012-07-13 03:19:45 +09001// 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
dchengcc8e4d82016-04-05 06:25:51 +09007#include <memory>
8
bcwhitecb532bf2016-04-06 04:41:53 +09009#include "base/debug/alias.h"
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090010#include "base/metrics/histogram_flattener.h"
11#include "base/metrics/histogram_samples.h"
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090012#include "base/metrics/statistics_recorder.h"
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +090013#include "base/stl_util.h"
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090014
rtenneti@google.com1c05d342012-07-13 03:19:45 +090015namespace base {
16
bcwhitebc44d702017-05-09 13:01:17 +090017namespace {
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.
21class 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.com1c05d342012-07-13 03:19:45 +090037HistogramSnapshotManager::HistogramSnapshotManager(
38 HistogramFlattener* histogram_flattener)
bcwhite271dcde2016-07-13 11:49:11 +090039 : histogram_flattener_(histogram_flattener) {
rtenneti@google.com1c05d342012-07-13 03:19:45 +090040 DCHECK(histogram_flattener_);
bcwhitebc44d702017-05-09 13:01:17 +090041 is_active_.store(false, std::memory_order_relaxed);
rtenneti@google.com1c05d342012-07-13 03:19:45 +090042}
43
Chris Watkinsd155d9f2017-11-29 16:16:38 +090044HistogramSnapshotManager::~HistogramSnapshotManager() = default;
rtenneti@google.com1c05d342012-07-13 03:19:45 +090045
bcwhiteb73fa822016-02-19 06:22:14 +090046void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) {
Brian White385ec102017-08-11 15:26:26 +090047 if (!histogram->ValidateHistogramContents(true, 0))
48 return;
bcwhiteb73fa822016-02-19 06:22:14 +090049 PrepareSamples(histogram, histogram->SnapshotDelta());
50}
51
bcwhite271dcde2016-07-13 11:49:11 +090052void HistogramSnapshotManager::PrepareFinalDelta(
53 const HistogramBase* histogram) {
Brian White385ec102017-08-11 15:26:26 +090054 if (!histogram->ValidateHistogramContents(true, 0))
55 return;
bcwhite271dcde2016-07-13 11:49:11 +090056 PrepareSamples(histogram, histogram->SnapshotFinalDelta());
bcwhiteb73fa822016-02-19 06:22:14 +090057}
58
59void HistogramSnapshotManager::PrepareSamples(
60 const HistogramBase* histogram,
dchengcc8e4d82016-04-05 06:25:51 +090061 std::unique_ptr<HistogramSamples> samples) {
rtenneti@google.com1c05d342012-07-13 03:19:45 +090062 DCHECK(histogram_flattener_);
63
bcwhitebc44d702017-05-09 13:01:17 +090064 // 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
bcwhite271dcde2016-07-13 11:49:11 +090069 // Get information known about this histogram. If it did not previously
70 // exist, one will be created and initialized.
bcwhiteb73fa822016-02-19 06:22:14 +090071 SampleInfo* sample_info = &known_histograms_[histogram->name_hash()];
rtenneti@google.com1c05d342012-07-13 03:19:45 +090072
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.
bcwhiteb73fa822016-02-19 06:22:14 +090076 uint32_t corruption = histogram->FindCorruption(*samples);
kaiwang@chromium.org7881e422013-03-01 12:53:25 +090077 if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
bcwhite60a5d372016-07-13 12:58:09 +090078 // Extract fields useful during debug.
79 const BucketRanges* ranges =
80 static_cast<const Histogram*>(histogram)->bucket_ranges();
bcwhiteb47b11e2016-09-23 23:02:04 +090081 uint32_t ranges_checksum = ranges->checksum();
82 uint32_t ranges_calc_checksum = ranges->CalculateChecksum();
bcwhite60a5d372016-07-13 12:58:09 +090083 int32_t flags = histogram->flags();
rtenneti@google.com1c05d342012-07-13 03:19:45 +090084 // The checksum should have caught this, so crash separately if it didn't.
bcwhiteb73fa822016-02-19 06:22:14 +090085 CHECK_NE(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
rtenneti@google.com1c05d342012-07-13 03:19:45 +090086 CHECK(false); // Crash for the bucket order corruption.
bcwhitecb532bf2016-04-06 04:41:53 +090087 // Ensure that compiler keeps around pointers to |histogram| and its
88 // internal |bucket_ranges_| for any minidumps.
bcwhiteb47b11e2016-09-23 23:02:04 +090089 base::debug::Alias(&ranges_checksum);
90 base::debug::Alias(&ranges_calc_checksum);
bcwhite60a5d372016-07-13 12:58:09 +090091 base::debug::Alias(&flags);
rtenneti@google.com1c05d342012-07-13 03:19:45 +090092 }
93 // Checksum corruption might not have caused order corruption.
bcwhiteb73fa822016-02-19 06:22:14 +090094 CHECK_EQ(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
rtenneti@google.com1c05d342012-07-13 03:19:45 +090095
kaiwang@chromium.orgc239f5a2012-08-21 08:53:15 +090096 // 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.com1c05d342012-07-13 03:19:45 +090099 if (corruption) {
bcwhiteb73fa822016-02-19 06:22:14 +0900100 DLOG(ERROR) << "Histogram: \"" << histogram->histogram_name()
101 << "\" has data corruption: " << corruption;
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900102 // Don't record corrupt data to metrics services.
bcwhiteb73fa822016-02-19 06:22:14 +0900103 const uint32_t old_corruption = sample_info->inconsistencies;
rtenneti@google.com1c05d342012-07-13 03:19:45 +0900104 if (old_corruption == (corruption | old_corruption))
105 return; // We've already seen this corruption for this histogram.
bcwhite271dcde2016-07-13 11:49:11 +0900106 sample_info->inconsistencies |= corruption;
rtenneti@google.com1c05d342012-07-13 03:19:45 +0900107 return;
108 }
109
bcwhite271dcde2016-07-13 11:49:11 +0900110 if (samples->TotalCount() > 0)
111 histogram_flattener_->RecordDelta(*histogram, *samples);
kaiwang@chromium.org0ce37b12012-09-22 12:42:12 +0900112}
113
rtenneti@google.com1c05d342012-07-13 03:19:45 +0900114} // namespace base