123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/metrics/histogram_snapshot_manager.h"
- #include <memory>
- #include "base/debug/alias.h"
- #include "base/logging.h"
- #include "base/memory/raw_ptr.h"
- #include "base/metrics/histogram_flattener.h"
- #include "base/metrics/histogram_samples.h"
- #include "base/metrics/statistics_recorder.h"
- namespace base {
- namespace {
- // A simple object to set an "active" flag and clear it upon destruction. It is
- // an error if the flag is already set.
- class MakeActive {
- public:
- explicit MakeActive(std::atomic<bool>* is_active) : is_active_(is_active) {
- bool was_active = is_active_->exchange(true, std::memory_order_relaxed);
- CHECK(!was_active);
- }
- MakeActive(const MakeActive&) = delete;
- MakeActive& operator=(const MakeActive&) = delete;
- ~MakeActive() { is_active_->store(false, std::memory_order_relaxed); }
- private:
- raw_ptr<std::atomic<bool>> is_active_;
- };
- } // namespace
- HistogramSnapshotManager::HistogramSnapshotManager(
- HistogramFlattener* histogram_flattener)
- : histogram_flattener_(histogram_flattener) {
- DCHECK(histogram_flattener_);
- is_active_.store(false, std::memory_order_relaxed);
- }
- HistogramSnapshotManager::~HistogramSnapshotManager() = default;
- void HistogramSnapshotManager::PrepareDeltas(
- const std::vector<HistogramBase*>& histograms,
- HistogramBase::Flags flags_to_set,
- HistogramBase::Flags required_flags) {
- for (HistogramBase* const histogram : histograms) {
- histogram->SetFlags(flags_to_set);
- if ((histogram->flags() & required_flags) == required_flags)
- PrepareDelta(histogram);
- }
- }
- void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) {
- PrepareSamples(histogram, histogram->SnapshotDelta());
- }
- void HistogramSnapshotManager::PrepareFinalDelta(
- const HistogramBase* histogram) {
- PrepareSamples(histogram, histogram->SnapshotFinalDelta());
- }
- void HistogramSnapshotManager::PrepareSamples(
- const HistogramBase* histogram,
- std::unique_ptr<HistogramSamples> samples) {
- DCHECK(histogram_flattener_);
- // Ensure that there is no concurrent access going on while accessing the
- // set of known histograms. The flag will be reset when this object goes
- // out of scope.
- MakeActive make_active(&is_active_);
- // Get information known about this histogram. If it did not previously
- // exist, one will be created and initialized.
- SampleInfo* sample_info = &known_histograms_[histogram->name_hash()];
- // Crash if we detect that our histograms have been overwritten. This may be
- // a fair distance from the memory smasher, but we hope to correlate these
- // crashes with other events, such as plugins, or usage patterns, etc.
- uint32_t corruption = histogram->FindCorruption(*samples);
- if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
- // Extract fields useful during debug.
- const BucketRanges* ranges =
- static_cast<const Histogram*>(histogram)->bucket_ranges();
- uint32_t ranges_checksum = ranges->checksum();
- uint32_t ranges_calc_checksum = ranges->CalculateChecksum();
- int32_t flags = histogram->flags();
- // The checksum should have caught this, so crash separately if it didn't.
- CHECK_NE(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
- CHECK(false); // Crash for the bucket order corruption.
- // Ensure that compiler keeps around pointers to |histogram| and its
- // internal |bucket_ranges_| for any minidumps.
- base::debug::Alias(&ranges_checksum);
- base::debug::Alias(&ranges_calc_checksum);
- base::debug::Alias(&flags);
- }
- // Checksum corruption might not have caused order corruption.
- CHECK_EQ(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
- // Note, at this point corruption can only be COUNT_HIGH_ERROR or
- // COUNT_LOW_ERROR and they never arise together, so we don't need to extract
- // bits from corruption.
- if (corruption) {
- DLOG(ERROR) << "Histogram: \"" << histogram->histogram_name()
- << "\" has data corruption: " << corruption;
- // Don't record corrupt data to metrics services.
- const uint32_t old_corruption = sample_info->inconsistencies;
- if (old_corruption == (corruption | old_corruption))
- return; // We've already seen this corruption for this histogram.
- sample_info->inconsistencies |= corruption;
- return;
- }
- if (samples->TotalCount() > 0)
- histogram_flattener_->RecordDelta(*histogram, *samples);
- }
- } // namespace base
|