1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be
3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file.
4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_
6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#define BASE_METRICS_HISTOGRAM_SAMPLES_H_
7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
80d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stddef.h>
90d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stdint.h>
100d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
1194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include <memory>
1294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
130d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/atomicops.h"
140d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/macros.h"
150d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/metrics/histogram_base.h"
16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass Pickle;
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass PickleIterator;
21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass SampleCountIterator;
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
2345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// HistogramSamples is a container storing all samples of a histogram. All
2445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// elements must be of a fixed width to ensure 32/64-bit interoperability.
2545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// If this structure changes, bump the version number for kTypeIdHistogram
2645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// in persistent_histogram_allocator.cc.
27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass BASE_EXPORT HistogramSamples {
28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public:
290d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  struct Metadata {
303a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    // Expected size for 32/64-bit check.
313a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    static constexpr size_t kExpectedInstanceSize = 24;
323a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli
330d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // Initialized when the sample-set is first created with a value provided
340d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // by the caller. It is generally used to identify the sample-set across
350d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // threads and processes, though not necessarily uniquely as it is possible
360d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // to have multiple sample-sets representing subsets of the data.
370d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    uint64_t id;
380d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
390d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // The sum of all the entries, effectivly the sum(sample * count) for
400d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // all samples. Despite being atomic, no guarantees are made on the
410d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // accuracy of this value; there may be races during histogram
420d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // accumulation and snapshotting that we choose to accept. It should
430d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // be treated as approximate.
4494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#ifdef ARCH_CPU_64_BITS
4594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    subtle::Atomic64 sum;
4694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#else
4794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    // 32-bit systems don't have atomic 64-bit operations. Use a basic type
4894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    // and don't worry about "shearing".
490d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    int64_t sum;
5094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#endif
510d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
520d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // A "redundant" count helps identify memory corruption. It redundantly
530d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // stores the total number of samples accumulated in the histogram. We
540d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // can compare this count to the sum of the counts (TotalCount() function),
550d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // and detect problems. Note, depending on the implementation of different
560d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // histogram types, there might be races during histogram accumulation
570d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // and snapshotting that we choose to accept. In this case, the tallies
580d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    // might mismatch even when no memory corruption has happened.
590d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    HistogramBase::AtomicCount redundant_count;
600d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
613a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    // 4 bytes of padding to explicitly extend this structure to a multiple of
623a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    // 64-bits. This is required to ensure the structure is the same size on
633a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    // both 32-bit and 64-bit builds.
643a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    char padding[4];
653a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli  };
663a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli
673a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli  // Because sturctures held in persistent memory must be POD, there can be no
683a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli  // default constructor to clear the fields. This derived class exists just
693a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli  // to clear them when being allocated on the heap.
703a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli  struct LocalMetadata : Metadata {
713a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    LocalMetadata() {
723a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli      id = 0;
733a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli      sum = 0;
743a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli      redundant_count = 0;
753a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli    }
760d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  };
770d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
780d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  explicit HistogramSamples(uint64_t id);
790d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  HistogramSamples(uint64_t id, Metadata* meta);
80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual ~HistogramSamples();
81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual void Accumulate(HistogramBase::Sample value,
83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                          HistogramBase::Count count) = 0;
84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual HistogramBase::Count TotalCount() const = 0;
86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual void Add(const HistogramSamples& other);
88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Add from serialized samples.
90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual bool AddFromPickle(PickleIterator* iter);
91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual void Subtract(const HistogramSamples& other);
93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
9494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  virtual std::unique_ptr<SampleCountIterator> Iterator() const = 0;
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual bool Serialize(Pickle* pickle) const;
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Accessor fuctions.
980d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  uint64_t id() const { return meta_->id; }
9994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  int64_t sum() const {
10094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#ifdef ARCH_CPU_64_BITS
10194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    return subtle::NoBarrier_Load(&meta_->sum);
10294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#else
10394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    return meta_->sum;
10494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#endif
10594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  }
106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  HistogramBase::Count redundant_count() const {
1070d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return subtle::NoBarrier_Load(&meta_->redundant_count);
108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat protected:
111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Based on |op| type, add or subtract sample counts data from the iterator.
112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  enum Operator { ADD, SUBTRACT };
113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
1150d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  void IncreaseSum(int64_t diff);
116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void IncreaseRedundantCount(HistogramBase::Count diff);
117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private:
1190d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // In order to support histograms shared through an external memory segment,
1200d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // meta values may be the local storage or external storage depending on the
1210d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // wishes of the derived class.
1223a83cddbf6d8fe9c9d70d01e008ff8e86a823cb6Jay Civelli  LocalMetadata local_meta_;
1230d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  Metadata* meta_;
1240d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
1250d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat};
127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass BASE_EXPORT SampleCountIterator {
129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public:
130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual ~SampleCountIterator();
131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual bool Done() const = 0;
133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual void Next() = 0;
134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Get the sample and count at current position.
136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |min| |max| and |count| can be NULL if the value is not of interest.
137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Requires: !Done();
138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual void Get(HistogramBase::Sample* min,
139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                   HistogramBase::Sample* max,
140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                   HistogramBase::Count* count) const = 0;
141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Get the index of current histogram bucket.
143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // For histograms that don't use predefined buckets, it returns false.
144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Requires: !Done();
145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual bool GetBucketIndex(size_t* index) const;
146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat};
147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif  // BASE_METRICS_HISTOGRAM_SAMPLES_H_
151