Index: base/metrics/histogram.cc |
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc |
index c35f76ce5548d8f0264f26fbeefab9c5d62aea82..09f0bbb67131e84417f8493971f52aa6603b06af 100644 |
--- a/base/metrics/histogram.cc |
+++ b/base/metrics/histogram.cc |
@@ -414,7 +414,7 @@ bool Histogram::InspectConstructionArguments(const std::string& name, |
} |
uint64_t Histogram::name_hash() const { |
- return samples_->id(); |
+ return unlogged_samples_->id(); |
} |
HistogramType Histogram::GetHistogramType() const { |
@@ -445,29 +445,33 @@ void Histogram::AddCount(int value, int count) { |
NOTREACHED(); |
return; |
} |
- samples_->Accumulate(value, count); |
+ unlogged_samples_->Accumulate(value, count); |
FindAndRunCallback(value); |
} |
std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const { |
- return SnapshotSampleVector(); |
+ return SnapshotAllSamples(); |
} |
std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() { |
DCHECK(!final_delta_created_); |
- |
- std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector(); |
- if (!logged_samples_) { |
- // If nothing has been previously logged, save this one as |
- // |logged_samples_| and gather another snapshot to return. |
- logged_samples_.swap(snapshot); |
- return SnapshotSampleVector(); |
- } |
- |
- // Subtract what was previously logged and update that information. |
- snapshot->Subtract(*logged_samples_); |
+ // The code below has subtle thread-safety guarantees! All changes to |
+ // the underlying SampleVectors use atomic integer operations, which guarantee |
+ // eventual consistency, but do not guarantee full synchronization between |
+ // different entries in the SampleVector. In particular, this means that |
+ // concurrent updates to the histogram might result in the reported sum not |
+ // matching the individual bucket counts; or there being some buckets that are |
+ // logically updated "together", but end up being only partially updated when |
+ // a snapshot is captured. Note that this is why it's important to subtract |
+ // exactly the snapshotted unlogged samples, rather than simply resetting the |
+ // vector: this way, the next snapshot will include any concurrent updates |
+ // missed by the current snapshot. |
+ |
+ std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples(); |
+ unlogged_samples_->Subtract(*snapshot); |
logged_samples_->Add(*snapshot); |
+ |
return snapshot; |
} |
@@ -475,20 +479,15 @@ std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { |
DCHECK(!final_delta_created_); |
final_delta_created_ = true; |
- std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector(); |
- |
- // Subtract what was previously logged and then return. |
- if (logged_samples_) |
- snapshot->Subtract(*logged_samples_); |
- return snapshot; |
+ return SnapshotUnloggedSamples(); |
} |
void Histogram::AddSamples(const HistogramSamples& samples) { |
- samples_->Add(samples); |
+ unlogged_samples_->Add(samples); |
} |
bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { |
- return samples_->AddFromPickle(iter); |
+ return unlogged_samples_->AddFromPickle(iter); |
} |
// The following methods provide a graphical histogram display. |
@@ -521,8 +520,10 @@ Histogram::Histogram(const std::string& name, |
bucket_ranges_(ranges), |
declared_min_(minimum), |
declared_max_(maximum) { |
- if (ranges) |
- samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
+ if (ranges) { |
+ unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
+ logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges)); |
+ } |
} |
Histogram::Histogram(const std::string& name, |
@@ -538,10 +539,10 @@ Histogram::Histogram(const std::string& name, |
declared_min_(minimum), |
declared_max_(maximum) { |
if (ranges) { |
- samples_.reset( |
+ unlogged_samples_.reset( |
new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); |
logged_samples_.reset(new PersistentSampleVector( |
- samples_->id(), ranges, logged_meta, logged_counts)); |
+ unlogged_samples_->id(), ranges, logged_meta, logged_counts)); |
} |
} |
@@ -598,10 +599,16 @@ HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) { |
return histogram; |
} |
-std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const { |
+std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const { |
+ std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamples(); |
+ samples->Add(*logged_samples_); |
+ return samples; |
+} |
+ |
+std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const { |
std::unique_ptr<SampleVector> samples( |
- new SampleVector(samples_->id(), bucket_ranges())); |
- samples->Add(*samples_); |
+ new SampleVector(unlogged_samples_->id(), bucket_ranges())); |
+ samples->Add(*unlogged_samples_); |
return samples; |
} |
@@ -610,7 +617,7 @@ void Histogram::WriteAsciiImpl(bool graph_it, |
std::string* output) const { |
// Get local (stack) copies of all effectively volatile class data so that we |
// are consistent across our output activities. |
- std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); |
+ std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples(); |
Count sample_count = snapshot->TotalCount(); |
WriteAsciiHeader(*snapshot, sample_count, output); |
@@ -722,7 +729,7 @@ void Histogram::GetParameters(DictionaryValue* params) const { |
void Histogram::GetCountAndBucketData(Count* count, |
int64_t* sum, |
ListValue* buckets) const { |
- std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); |
+ std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples(); |
*count = snapshot->TotalCount(); |
*sum = snapshot->sum(); |
uint32_t index = 0; |