15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram_snapshot_manager.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram_flattener.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram_samples.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/statistics_recorder.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::map; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistogramSnapshotManager::HistogramSnapshotManager( 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramFlattener* histogram_flattener) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : histogram_flattener_(histogram_flattener) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(histogram_flattener_); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistogramSnapshotManager::~HistogramSnapshotManager() { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) STLDeleteValues(&logged_samples_); 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HistogramSnapshotManager::PrepareDeltas( 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HistogramBase::Flags flag_to_set, 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HistogramBase::Flags required_flags) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatisticsRecorder::Histograms histograms; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatisticsRecorder::GetHistograms(&histograms); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin(); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histograms.end() != it; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*it)->SetFlags(flag_to_set); 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (((*it)->flags() & required_flags) == required_flags) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PrepareDelta(**it); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(histogram_flattener_); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get up-to-date snapshot of sample stats. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples()); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& histogram_name = histogram.histogram_name(); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int corruption = histogram.FindCorruption(*snapshot); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Crash if we detect that our histograms have been overwritten. This may be 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a fair distance from the memory smasher, but we hope to correlate these 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // crashes with other events, such as plugins, or usage patterns, etc. 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (HistogramBase::BUCKET_ORDER_ERROR & corruption) { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The checksum should have caught this, so crash separately if it didn't. 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(false); // Crash for the bucket order corruption. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Checksum corruption might not have caused order corruption. 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note, at this point corruption can only be COUNT_HIGH_ERROR or 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // COUNT_LOW_ERROR and they never arise together, so we don't need to extract 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bits from corruption. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (corruption) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Histogram: " << histogram_name 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " has data corruption: " << corruption; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_flattener_->InconsistencyDetected( 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<HistogramBase::Inconsistency>(corruption)); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't record corrupt data to metrics services. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_corruption = inconsistencies_[histogram_name]; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_corruption == (corruption | old_corruption)) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // We've already seen this corruption for this histogram. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inconsistencies_[histogram_name] |= corruption; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_flattener_->UniqueInconsistencyDetected( 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<HistogramBase::Inconsistency>(corruption)); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramSamples* to_log; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map<string, HistogramSamples*>::iterator it = 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logged_samples_.find(histogram_name); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == logged_samples_.end()) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_log = snapshot.release(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This histogram has not been logged before, add a new entry. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logged_samples_[histogram_name] = to_log; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramSamples* already_logged = it->second; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InspectLoggedSamplesInconsistency(*snapshot, already_logged); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) snapshot->Subtract(*already_logged); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) already_logged->Add(*snapshot); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to_log = snapshot.get(); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (to_log->TotalCount() > 0) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_flattener_->RecordDelta(histogram, *to_log); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HistogramSnapshotManager::InspectLoggedSamplesInconsistency( 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HistogramSamples& new_snapshot, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramSamples* logged_samples) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistogramBase::Count discrepancy = 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logged_samples->TotalCount() - logged_samples->redundant_count(); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!discrepancy) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fix logged_samples. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logged_samples->Subtract(*logged_samples); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logged_samples->Add(new_snapshot); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 117