blob: cc551dc2c3f8603e2ef1a8686dd65dbca51f1eaf [file] [log] [blame]
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:121// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// SampleVector implements HistogramSamples interface. It is used by all
6// Histogram based classes to store samples.
7
8#ifndef BASE_METRICS_SAMPLE_VECTOR_H_
9#define BASE_METRICS_SAMPLE_VECTOR_H_
10
avi9b6f42932015-12-26 22:15:1411#include <stddef.h>
bcwhiteb036e4322015-12-10 18:36:3412#include <stdint.h>
avi9b6f42932015-12-26 22:15:1413
Benoit Lize8ff573d2021-04-14 11:37:0514#include <atomic>
dcheng093de9b2016-04-04 21:25:5115#include <memory>
Sumaid Syed22f60eeb2021-08-26 05:16:2616#include <string>
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1217#include <vector>
18
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1219#include "base/compiler_specific.h"
20#include "base/gtest_prod_util.h"
bcwhitefa8485b2017-05-01 16:43:2521#include "base/metrics/bucket_ranges.h"
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1222#include "base/metrics/histogram_base.h"
23#include "base/metrics/histogram_samples.h"
bcwhitefa8485b2017-05-01 16:43:2524#include "base/metrics/persistent_memory_allocator.h"
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1225
26namespace base {
27
28class BucketRanges;
29
bcwhitefa8485b2017-05-01 16:43:2530class BASE_EXPORT SampleVectorBase : public HistogramSamples {
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1231 public:
bcwhitefa8485b2017-05-01 16:43:2532 SampleVectorBase(uint64_t id,
33 Metadata* meta,
34 const BucketRanges* bucket_ranges);
David Bienvenuf1f524482020-09-16 19:37:3735 SampleVectorBase(const SampleVectorBase&) = delete;
36 SampleVectorBase& operator=(const SampleVectorBase&) = delete;
bcwhitefa8485b2017-05-01 16:43:2537 ~SampleVectorBase() override;
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1238
bcwhitefa8485b2017-05-01 16:43:2539 // HistogramSamples:
dcheng56488182014-10-21 10:54:5140 void Accumulate(HistogramBase::Sample value,
41 HistogramBase::Count count) override;
42 HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
43 HistogramBase::Count TotalCount() const override;
dcheng093de9b2016-04-04 21:25:5144 std::unique_ptr<SampleCountIterator> Iterator() const override;
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1245
46 // Get count of a specific bucket.
47 HistogramBase::Count GetCountAtIndex(size_t bucket_index) const;
48
Brian White32052d5b2017-08-07 16:46:5749 // Access the bucket ranges held externally.
50 const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
51
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1252 protected:
dcheng56488182014-10-21 10:54:5153 bool AddSubtractImpl(
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1254 SampleCountIterator* iter,
mostynb9e096de2014-10-07 17:59:1155 HistogramSamples::Operator op) override; // |op| is ADD or SUBTRACT.
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1256
57 virtual size_t GetBucketIndex(HistogramBase::Sample value) const;
58
bcwhitefa8485b2017-05-01 16:43:2559 // Moves the single-sample value to a mounted "counts" array.
Gabriel Charettea2bb40e2021-09-29 17:44:1760 // TODO(crbug.com/1254354): Remove NOINLINE after diagnosis.
61 void NOINLINE MoveSingleSampleToCounts();
bcwhitefa8485b2017-05-01 16:43:2562
63 // Mounts (creating if necessary) an array of "counts" for multi-value
64 // storage.
Gabriel Charettea2bb40e2021-09-29 17:44:1765 // TODO(crbug.com/1254354): Remove NOINLINE after diagnosis.
66 void NOINLINE MountCountsStorageAndMoveSingleSample();
bcwhitefa8485b2017-05-01 16:43:2567
68 // Mounts "counts" storage that already exists. This does not attempt to move
69 // any single-sample information to that storage as that would violate the
70 // "const" restriction that is often used to indicate read-only memory.
71 virtual bool MountExistingCountsStorage() const = 0;
72
73 // Creates "counts" storage and returns a pointer to it. Ownership of the
74 // array remains with the called method but will never change. This must be
75 // called while some sort of lock is held to prevent reentry.
76 virtual HistogramBase::Count* CreateCountsStorageWhileLocked() = 0;
77
78 HistogramBase::AtomicCount* counts() {
Benoit Lize8ff573d2021-04-14 11:37:0579 return counts_.load(std::memory_order_acquire);
bcwhitefa8485b2017-05-01 16:43:2580 }
81
82 const HistogramBase::AtomicCount* counts() const {
Benoit Lize8ff573d2021-04-14 11:37:0583 return counts_.load(std::memory_order_acquire);
bcwhitefa8485b2017-05-01 16:43:2584 }
85
Benoit Lize8ff573d2021-04-14 11:37:0586 void set_counts(HistogramBase::AtomicCount* counts) const {
87 counts_.store(counts, std::memory_order_release);
bcwhitefa8485b2017-05-01 16:43:2588 }
89
90 size_t counts_size() const { return bucket_ranges_->bucket_count(); }
91
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1292 private:
bcwhitefa8485b2017-05-01 16:43:2593 friend class SampleVectorTest;
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1294 FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
bcwhite5cb99eb2016-02-01 21:07:5695 FRIEND_TEST_ALL_PREFIXES(SharedHistogramTest, CorruptSampleCounts);
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:1296
bcwhitefa8485b2017-05-01 16:43:2597 // |counts_| is actually a pointer to a HistogramBase::AtomicCount array but
Benoit Lize8ff573d2021-04-14 11:37:0598 // is held as an atomic pointer for concurrency reasons. When combined with
99 // the single_sample held in the metadata, there are four possible states:
bcwhitefa8485b2017-05-01 16:43:25100 // 1) single_sample == zero, counts_ == null
101 // 2) single_sample != zero, counts_ == null
102 // 3) single_sample != zero, counts_ != null BUT IS EMPTY
103 // 4) single_sample == zero, counts_ != null and may have data
104 // Once |counts_| is set, it can never revert and any existing single-sample
105 // must be moved to this storage. It is mutable because changing it doesn't
106 // change the (const) data but must adapt if a non-const object causes the
107 // storage to be allocated and updated.
Benoit Lize8ff573d2021-04-14 11:37:05108 mutable std::atomic<HistogramBase::AtomicCount*> counts_{nullptr};
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:12109
110 // Shares the same BucketRanges with Histogram object.
111 const BucketRanges* const bucket_ranges_;
bcwhitefa8485b2017-05-01 16:43:25112};
113
114// A sample vector that uses local memory for the counts array.
115class BASE_EXPORT SampleVector : public SampleVectorBase {
116 public:
117 explicit SampleVector(const BucketRanges* bucket_ranges);
118 SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
David Bienvenuf1f524482020-09-16 19:37:37119 SampleVector(const SampleVector&) = delete;
120 SampleVector& operator=(const SampleVector&) = delete;
bcwhitefa8485b2017-05-01 16:43:25121 ~SampleVector() override;
122
123 private:
Quang Minh Tuan Nguyen39b1fed2021-03-16 00:49:38124 FRIEND_TEST_ALL_PREFIXES(SampleVectorTest, GetPeakBucketSize);
125
126 // HistogramSamples:
127 std::string GetAsciiBody() const override;
128 std::string GetAsciiHeader(StringPiece histogram_name,
129 int32_t flags) const override;
130
bcwhitefa8485b2017-05-01 16:43:25131 // SampleVectorBase:
132 bool MountExistingCountsStorage() const override;
133 HistogramBase::Count* CreateCountsStorageWhileLocked() override;
134
Quang Minh Tuan Nguyen39b1fed2021-03-16 00:49:38135 // Writes cumulative percentage information based on the number
136 // of past, current, and remaining bucket samples.
137 void WriteAsciiBucketContext(int64_t past,
138 HistogramBase::Count current,
139 int64_t remaining,
140 uint32_t current_bucket_index,
141 std::string* output) const;
142
143 // Finds out how large (graphically) the largest bucket will appear to be.
144 double GetPeakBucketSize() const;
145
146 size_t bucket_count() const { return bucket_ranges()->bucket_count(); }
147
bcwhitefa8485b2017-05-01 16:43:25148 // Simple local storage for counts.
149 mutable std::vector<HistogramBase::AtomicCount> local_counts_;
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:12150};
151
bcwhitefa8485b2017-05-01 16:43:25152// A sample vector that uses persistent memory for the counts array.
153class BASE_EXPORT PersistentSampleVector : public SampleVectorBase {
154 public:
155 PersistentSampleVector(uint64_t id,
156 const BucketRanges* bucket_ranges,
157 Metadata* meta,
158 const DelayedPersistentAllocation& counts);
David Bienvenuf1f524482020-09-16 19:37:37159 PersistentSampleVector(const PersistentSampleVector&) = delete;
160 PersistentSampleVector& operator=(const PersistentSampleVector&) = delete;
bcwhitefa8485b2017-05-01 16:43:25161 ~PersistentSampleVector() override;
162
163 private:
164 // SampleVectorBase:
165 bool MountExistingCountsStorage() const override;
166 HistogramBase::Count* CreateCountsStorageWhileLocked() override;
167
168 // Persistent storage for counts.
169 DelayedPersistentAllocation persistent_counts_;
bcwhitefa8485b2017-05-01 16:43:25170};
171
172// An iterator for sample vectors. This could be defined privately in the .cc
173// file but is here for easy testing.
xhwang3e9ca562015-11-06 18:50:36174class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:12175 public:
glider@chromium.orgd2efe462014-01-21 07:59:28176 SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:12177 const BucketRanges* bucket_ranges);
bcwhiteb036e4322015-12-10 18:36:34178 SampleVectorIterator(const HistogramBase::AtomicCount* counts,
179 size_t counts_size,
180 const BucketRanges* bucket_ranges);
dcheng56488182014-10-21 10:54:51181 ~SampleVectorIterator() override;
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:12182
183 // SampleCountIterator implementation:
dcheng56488182014-10-21 10:54:51184 bool Done() const override;
185 void Next() override;
186 void Get(HistogramBase::Sample* min,
asvitkine3f17b1462017-05-03 21:37:37187 int64_t* max,
dcheng56488182014-10-21 10:54:51188 HistogramBase::Count* count) const override;
kaiwang@chromium.orgb4af2ec2012-10-05 21:29:44189
190 // SampleVector uses predefined buckets, so iterator can return bucket index.
dcheng56488182014-10-21 10:54:51191 bool GetBucketIndex(size_t* index) const override;
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:12192
193 private:
194 void SkipEmptyBuckets();
195
bcwhiteb036e4322015-12-10 18:36:34196 const HistogramBase::AtomicCount* counts_;
197 size_t counts_size_;
kaiwang@chromium.org2f7d9cd2012-09-22 03:42:12198 const BucketRanges* bucket_ranges_;
199
200 size_t index_;
201};
202
203} // namespace base
204
205#endif // BASE_METRICS_SAMPLE_VECTOR_H_