Index: base/metrics/histogram_samples.h |
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h |
index 93f6d21c8aabd34eed61dd9c20d2e030cabada8f..0e24c4f160e7a2a29f83eefc554efbf2dffc80f4 100644 |
--- a/base/metrics/histogram_samples.h |
+++ b/base/metrics/histogram_samples.h |
@@ -24,8 +24,64 @@ class SampleCountIterator; |
// elements must be of a fixed width to ensure 32/64-bit interoperability. |
// If this structure changes, bump the version number for kTypeIdHistogram |
// in persistent_histogram_allocator.cc. |
+// |
+// Note that though these samples are individually consistent (through the use |
+// of atomic operations on the counts), there is only "eventual consistency" |
+// overall when multiple threads are accessing this data. That means that the |
+// sum, redundant-count, etc. could be momentarily out-of-sync with the stored |
+// counts but will settle to a consistent "steady state" once all threads have |
+// exited this code. |
class BASE_EXPORT HistogramSamples { |
public: |
+ // A single bucket and count. To fit within a single atomic on 32-bit build |
+ // architectures, both |bucket| and |count| are limited in size to 16 bits. |
+ // This limits the functionality somewhat but if an entry can't fit then |
+ // the full array of samples can be allocated and used. |
+ struct SingleSample { |
+ uint16_t bucket; |
+ uint16_t count; |
+ }; |
+ |
+ // A structure for managing an atomic single sample. Because this is generally |
+ // used in association with other atomic values, the defined methods use |
+ // acquire/release operations to guarantee ordering with outside values. |
+ union AtomicSingleSample { |
+ AtomicSingleSample() : as_atomic(0) {} |
+ AtomicSingleSample(subtle::Atomic32 rhs) : as_atomic(rhs) {} |
+ |
+ // Returns the single sample in an atomic manner. This in an "acquire" |
+ // load. The returned sample isn't shared and thus its fields can be safely |
+ // accessed. |
+ SingleSample Load() const; |
+ |
+ // Extracts the single sample in an atomic manner. If |disable| is true |
+ // then this object will be set so it will never accumulate another value. |
+ // This is "no barrier" so doesn't enforce ordering with other atomic ops. |
+ SingleSample Extract(bool disable); |
+ |
+ // Adds a given count to the held bucket. If not possible, it returns false |
+ // and leaves the parts unchanged. Once extracted/disabled, this always |
+ // returns false. This in an "acquire/release" operation. |
+ bool Accumulate(size_t bucket, HistogramBase::Count count); |
+ |
+ // Returns if the sample has been "disabled" (via Extract) and thus not |
+ // allowed to accept further accumulation. |
+ bool IsDisabled() const; |
+ |
+ private: |
+ // union field: The actual sample bucket and count. |
+ SingleSample as_parts; |
+ |
+ // union field: The sample as an atomic value. Atomic64 would provide |
+ // more flexibility but isn't available on all builds. This can hold a |
+ // special, internal "disabled" value indicating that it must not accept |
+ // further accumulation. |
+ subtle::Atomic32 as_atomic; |
+ }; |
+ |
+ // A structure of information about the data, common to all sample containers. |
+ // Because of how this is used in persistent memory, it must be a POD object |
+ // that makes sense when initialized to all zeros. |
struct Metadata { |
// Expected size for 32/64-bit check. |
static constexpr size_t kExpectedInstanceSize = 24; |
@@ -58,21 +114,17 @@ class BASE_EXPORT HistogramSamples { |
// might mismatch even when no memory corruption has happened. |
HistogramBase::AtomicCount redundant_count; |
- // 4 bytes of padding to explicitly extend this structure to a multiple of |
- // 64-bits. This is required to ensure the structure is the same size on |
- // both 32-bit and 64-bit builds. |
- char padding[4]; |
+ // A single histogram value and associated count. This allows histograms |
+ // that typically report only a single value to not require full storage |
+ // to be allocated. |
+ AtomicSingleSample single_sample; // 32 bits |
}; |
- // Because sturctures held in persistent memory must be POD, there can be no |
+ // Because structures held in persistent memory must be POD, there can be no |
// default constructor to clear the fields. This derived class exists just |
// to clear them when being allocated on the heap. |
- struct LocalMetadata : Metadata { |
- LocalMetadata() { |
- id = 0; |
- sum = 0; |
- redundant_count = 0; |
- } |
+ struct BASE_EXPORT LocalMetadata : Metadata { |
+ LocalMetadata(); |
}; |
explicit HistogramSamples(uint64_t id); |
@@ -112,8 +164,20 @@ class BASE_EXPORT HistogramSamples { |
enum Operator { ADD, SUBTRACT }; |
virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0; |
- void IncreaseSum(int64_t diff); |
- void IncreaseRedundantCount(HistogramBase::Count diff); |
+ // Accumulates to the embedded single-sample field if possible. Returns true |
+ // on success, false otherwise. Sum and redundant-count are also updated in |
+ // the success case. |
+ bool AccumulateSingleSample(HistogramBase::Sample value, |
+ HistogramBase::Count count, |
+ size_t bucket); |
+ |
+ // Atomically adjust the sum and redundant-count. |
+ void IncreaseSumAndCount(int64_t sum, HistogramBase::Count count); |
+ |
+ AtomicSingleSample& single_sample() { return meta_->single_sample; } |
+ const AtomicSingleSample& single_sample() const { |
+ return meta_->single_sample; |
+ } |
private: |
// In order to support histograms shared through an external memory segment, |
@@ -145,6 +209,35 @@ class BASE_EXPORT SampleCountIterator { |
virtual bool GetBucketIndex(size_t* index) const; |
}; |
+class BASE_EXPORT SingleSampleIterator : public SampleCountIterator { |
+ public: |
+ SingleSampleIterator(HistogramBase::Sample min, |
+ HistogramBase::Sample max, |
+ HistogramBase::Count count); |
+ SingleSampleIterator(HistogramBase::Sample min, |
+ HistogramBase::Sample max, |
+ HistogramBase::Count count, |
+ size_t bucket_index); |
+ ~SingleSampleIterator() override; |
+ |
+ // SampleCountIterator: |
+ bool Done() const override; |
+ void Next() override; |
+ void Get(HistogramBase::Sample* min, |
+ HistogramBase::Sample* max, |
+ HistogramBase::Count* count) const override; |
+ |
+ // SampleVector uses predefined buckets so iterator can return bucket index. |
+ bool GetBucketIndex(size_t* index) const override; |
+ |
+ private: |
+ // Information about the single value to return. |
+ const HistogramBase::Sample min_; |
+ const HistogramBase::Sample max_; |
+ const size_t bucket_index_; |
+ HistogramBase::Count count_; |
+}; |
+ |
} // namespace base |
#endif // BASE_METRICS_HISTOGRAM_SAMPLES_H_ |