123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- // 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.
- #ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_
- #define BASE_METRICS_HISTOGRAM_SAMPLES_H_
- #include <stddef.h>
- #include <stdint.h>
- #include <limits>
- #include <memory>
- #include "base/atomicops.h"
- #include "base/metrics/histogram_base.h"
- namespace base {
- class Pickle;
- class PickleIterator;
- class SampleCountIterator;
- // HistogramSamples is a container storing all samples of a histogram. All
- // 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 BASE_EXPORT 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;
- // Initialized when the sample-set is first created with a value provided
- // by the caller. It is generally used to identify the sample-set across
- // threads and processes, though not necessarily uniquely as it is possible
- // to have multiple sample-sets representing subsets of the data.
- uint64_t id;
- // The sum of all the entries, effectivly the sum(sample * count) for
- // all samples. Despite being atomic, no guarantees are made on the
- // accuracy of this value; there may be races during histogram
- // accumulation and snapshotting that we choose to accept. It should
- // be treated as approximate.
- #ifdef ARCH_CPU_64_BITS
- subtle::Atomic64 sum;
- #else
- // 32-bit systems don't have atomic 64-bit operations. Use a basic type
- // and don't worry about "shearing".
- int64_t sum;
- #endif
- // A "redundant" count helps identify memory corruption. It redundantly
- // stores the total number of samples accumulated in the histogram. We
- // can compare this count to the sum of the counts (TotalCount() function),
- // and detect problems. Note, depending on the implementation of different
- // histogram types, there might be races during histogram accumulation
- // and snapshotting that we choose to accept. In this case, the tallies
- // might mismatch even when no memory corruption has happened.
- HistogramBase::AtomicCount redundant_count;
- // 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 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 BASE_EXPORT LocalMetadata : Metadata {
- LocalMetadata();
- };
- HistogramSamples(uint64_t id, Metadata* meta);
- HistogramSamples(const HistogramSamples&) = delete;
- HistogramSamples& operator=(const HistogramSamples&) = delete;
- virtual ~HistogramSamples();
- virtual void Accumulate(HistogramBase::Sample value,
- HistogramBase::Count count) = 0;
- virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
- virtual HistogramBase::Count TotalCount() const = 0;
- virtual void Add(const HistogramSamples& other);
- // Add from serialized samples.
- virtual bool AddFromPickle(PickleIterator* iter);
- virtual void Subtract(const HistogramSamples& other);
- virtual std::unique_ptr<SampleCountIterator> Iterator() const = 0;
- virtual void Serialize(Pickle* pickle) const;
- // Accessor fuctions.
- uint64_t id() const { return meta_->id; }
- int64_t sum() const {
- #ifdef ARCH_CPU_64_BITS
- return subtle::NoBarrier_Load(&meta_->sum);
- #else
- return meta_->sum;
- #endif
- }
- HistogramBase::Count redundant_count() const {
- return subtle::NoBarrier_Load(&meta_->redundant_count);
- }
- protected:
- enum NegativeSampleReason {
- SAMPLES_HAVE_LOGGED_BUT_NOT_SAMPLE,
- SAMPLES_SAMPLE_LESS_THAN_LOGGED,
- SAMPLES_ADDED_NEGATIVE_COUNT,
- SAMPLES_ADD_WENT_NEGATIVE,
- SAMPLES_ADD_OVERFLOW,
- SAMPLES_ACCUMULATE_NEGATIVE_COUNT,
- SAMPLES_ACCUMULATE_WENT_NEGATIVE,
- DEPRECATED_SAMPLES_ACCUMULATE_OVERFLOW,
- SAMPLES_ACCUMULATE_OVERFLOW,
- MAX_NEGATIVE_SAMPLE_REASONS
- };
- // Based on |op| type, add or subtract sample counts data from the iterator.
- enum Operator { ADD, SUBTRACT };
- virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
- // 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);
- // Record a negative-sample observation and the reason why.
- void RecordNegativeSample(NegativeSampleReason reason,
- HistogramBase::Count increment);
- AtomicSingleSample& single_sample() { return meta_->single_sample; }
- const AtomicSingleSample& single_sample() const {
- return meta_->single_sample;
- }
- Metadata* meta() { return meta_; }
- private:
- // Depending on derived class meta values can come from local stoarge or
- // external storage in which case HistogramSamples class cannot take ownership
- // of Metadata*.
- Metadata* meta_;
- };
- class BASE_EXPORT SampleCountIterator {
- public:
- virtual ~SampleCountIterator();
- virtual bool Done() const = 0;
- virtual void Next() = 0;
- // Get the sample and count at current position.
- // |min| |max| and |count| can be NULL if the value is not of interest.
- // Note: |max| is int64_t because histograms support logged values in the
- // full int32_t range and bucket max is exclusive, so it needs to support
- // values up to MAXINT32+1.
- // Requires: !Done();
- virtual void Get(HistogramBase::Sample* min,
- int64_t* max,
- HistogramBase::Count* count) const = 0;
- static_assert(std::numeric_limits<HistogramBase::Sample>::max() <
- std::numeric_limits<int64_t>::max(),
- "Get() |max| must be able to hold Histogram::Sample max + 1");
- // Get the index of current histogram bucket.
- // For histograms that don't use predefined buckets, it returns false.
- // Requires: !Done();
- virtual bool GetBucketIndex(size_t* index) const;
- };
- class BASE_EXPORT SingleSampleIterator : public SampleCountIterator {
- public:
- SingleSampleIterator(HistogramBase::Sample min,
- int64_t max,
- HistogramBase::Count count);
- SingleSampleIterator(HistogramBase::Sample min,
- int64_t max,
- HistogramBase::Count count,
- size_t bucket_index);
- ~SingleSampleIterator() override;
- // SampleCountIterator:
- bool Done() const override;
- void Next() override;
- void Get(HistogramBase::Sample* min,
- int64_t* 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 int64_t max_;
- const size_t bucket_index_;
- HistogramBase::Count count_;
- };
- } // namespace base
- #endif // BASE_METRICS_HISTOGRAM_SAMPLES_H_
|