| Index: base/metrics/histogram_snapshot_manager.cc
|
| diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc
|
| index 3d1c0d666a245050953d6899b9eb1423922f77ef..e03213fc72104774fc9568601e6f537952693847 100644
|
| --- a/base/metrics/histogram_snapshot_manager.cc
|
| +++ b/base/metrics/histogram_snapshot_manager.cc
|
| @@ -14,68 +14,124 @@ namespace base {
|
|
|
| HistogramSnapshotManager::HistogramSnapshotManager(
|
| HistogramFlattener* histogram_flattener)
|
| - : histogram_flattener_(histogram_flattener) {
|
| + : preparing_deltas_(false),
|
| + histogram_flattener_(histogram_flattener) {
|
| DCHECK(histogram_flattener_);
|
| }
|
|
|
| HistogramSnapshotManager::~HistogramSnapshotManager() {
|
| - STLDeleteValues(&logged_samples_);
|
| }
|
|
|
| -void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) {
|
| +void HistogramSnapshotManager::StartDeltas() {
|
| + // Ensure that start/finish calls do not get nested.
|
| + DCHECK(!preparing_deltas_);
|
| + preparing_deltas_ = true;
|
| +
|
| +#ifdef DEBUG
|
| + for (const auto& iter : known_histograms) {
|
| + CHECK(!iter->second.histogram);
|
| + CHECK(!iter->second.accumulated_samples);
|
| + CHECK(!(iter->second.inconsistencies &
|
| + HistogramBase::NEW_INCONSISTENCY_FOUND));
|
| + }
|
| +#endif
|
| +}
|
| +
|
| +void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) {
|
| + PrepareSamples(histogram, histogram->SnapshotDelta());
|
| +}
|
| +
|
| +void HistogramSnapshotManager::PrepareAbsolute(const HistogramBase* histogram) {
|
| + PrepareSamples(histogram, histogram->SnapshotSamples());
|
| +}
|
| +
|
| +void HistogramSnapshotManager::FinishDeltas() {
|
| + DCHECK(preparing_deltas_);
|
| +
|
| + // Iterate over all known histograms to see what should be recorded.
|
| + for (auto& iter : known_histograms_) {
|
| + SampleInfo* sample_info = &iter.second;
|
| +
|
| + // First, record any histograms in which corruption was detected.
|
| + if (sample_info->inconsistencies & HistogramBase::NEW_INCONSISTENCY_FOUND) {
|
| + sample_info->inconsistencies &= ~HistogramBase::NEW_INCONSISTENCY_FOUND;
|
| + histogram_flattener_->UniqueInconsistencyDetected(
|
| + static_cast<HistogramBase::Inconsistency>(
|
| + sample_info->inconsistencies));
|
| + }
|
| +
|
| + // Second, record actual accumulated deltas.
|
| + if (sample_info->accumulated_samples) {
|
| + // TODO(bcwhite): Investigate using redundant_count() below to avoid
|
| + // additional pass through all the samples to calculate real total.
|
| + if (sample_info->accumulated_samples->TotalCount() > 0) {
|
| + histogram_flattener_->RecordDelta(*sample_info->histogram,
|
| + *sample_info->accumulated_samples);
|
| + }
|
| + delete sample_info->accumulated_samples;
|
| + sample_info->accumulated_samples = nullptr;
|
| + }
|
| +
|
| + // The Histogram pointer must be cleared at this point because the owner
|
| + // is only required to keep it alive until FinishDeltas() completes.
|
| + sample_info->histogram = nullptr;
|
| + }
|
| +
|
| + preparing_deltas_ = false;
|
| +}
|
| +
|
| +void HistogramSnapshotManager::PrepareSamples(
|
| + const HistogramBase* histogram,
|
| + scoped_ptr<HistogramSamples> samples) {
|
| DCHECK(histogram_flattener_);
|
|
|
| - // Get up-to-date snapshot of sample stats.
|
| - scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples());
|
| + // Get information known about this histogram.
|
| + SampleInfo* sample_info = &known_histograms_[histogram->name_hash()];
|
| + if (sample_info->histogram) {
|
| + DCHECK_EQ(sample_info->histogram->histogram_name(),
|
| + histogram->histogram_name()) << "hash collision";
|
| + } else {
|
| + // First time this histogram has been seen; datafill.
|
| + sample_info->histogram = histogram;
|
| + }
|
|
|
| // 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.
|
| - int corruption = histogram.FindCorruption(*snapshot);
|
| + uint32_t corruption = histogram->FindCorruption(*samples);
|
| if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
|
| // The checksum should have caught this, so crash separately if it didn't.
|
| - CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
|
| + CHECK_NE(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
|
| CHECK(false); // Crash for the bucket order corruption.
|
| }
|
| // Checksum corruption might not have caused order corruption.
|
| - CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & 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.
|
| - const uint64_t histogram_hash = histogram.name_hash();
|
| if (corruption) {
|
| - DLOG(ERROR) << "Histogram: " << histogram.histogram_name()
|
| - << " has data corruption: " << corruption;
|
| + DLOG(ERROR) << "Histogram: \"" << histogram->histogram_name()
|
| + << "\" has data corruption: " << corruption;
|
| histogram_flattener_->InconsistencyDetected(
|
| static_cast<HistogramBase::Inconsistency>(corruption));
|
| // Don't record corrupt data to metrics services.
|
| - int old_corruption = inconsistencies_[histogram_hash];
|
| + const uint32_t old_corruption = sample_info->inconsistencies;
|
| if (old_corruption == (corruption | old_corruption))
|
| return; // We've already seen this corruption for this histogram.
|
| - inconsistencies_[histogram_hash] |= corruption;
|
| - histogram_flattener_->UniqueInconsistencyDetected(
|
| - static_cast<HistogramBase::Inconsistency>(corruption));
|
| + sample_info->inconsistencies |=
|
| + corruption | HistogramBase::NEW_INCONSISTENCY_FOUND;
|
| + // TODO(bcwhite): Can we clear the inconsistency for future collection?
|
| return;
|
| }
|
|
|
| - HistogramSamples* to_log;
|
| - auto it = logged_samples_.find(histogram_hash);
|
| - if (it == logged_samples_.end()) {
|
| - to_log = snapshot.release();
|
| -
|
| - // This histogram has not been logged before, add a new entry.
|
| - logged_samples_[histogram_hash] = to_log;
|
| + if (!sample_info->accumulated_samples) {
|
| + // This histogram has not been seen before; add it as a new entry.
|
| + sample_info->accumulated_samples = samples.release();
|
| } else {
|
| - HistogramSamples* already_logged = it->second;
|
| - InspectLoggedSamplesInconsistency(*snapshot, already_logged);
|
| - snapshot->Subtract(*already_logged);
|
| - already_logged->Add(*snapshot);
|
| - to_log = snapshot.get();
|
| + // There are previous values from this histogram; add them together.
|
| + sample_info->accumulated_samples->Add(*samples);
|
| }
|
| -
|
| - if (to_log->TotalCount() > 0)
|
| - histogram_flattener_->RecordDelta(histogram, *to_log);
|
| }
|
|
|
| void HistogramSnapshotManager::InspectLoggedSamplesInconsistency(
|
|
|