1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/metrics/sample_map.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <type_traits>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker namespace base {
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker typedef HistogramBase::Count Count;
15*6777b538SAndroid Build Coastguard Worker typedef HistogramBase::Sample Sample;
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker namespace {
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker // An iterator for going through a SampleMap. The logic here is identical
20*6777b538SAndroid Build Coastguard Worker // to that of the iterator for PersistentSampleMap but with different data
21*6777b538SAndroid Build Coastguard Worker // structures. Changes here likely need to be duplicated there.
22*6777b538SAndroid Build Coastguard Worker template <typename T, typename I>
23*6777b538SAndroid Build Coastguard Worker class IteratorTemplate : public SampleCountIterator {
24*6777b538SAndroid Build Coastguard Worker public:
IteratorTemplate(T & sample_counts)25*6777b538SAndroid Build Coastguard Worker explicit IteratorTemplate(T& sample_counts)
26*6777b538SAndroid Build Coastguard Worker : iter_(sample_counts.begin()), end_(sample_counts.end()) {
27*6777b538SAndroid Build Coastguard Worker SkipEmptyBuckets();
28*6777b538SAndroid Build Coastguard Worker }
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker ~IteratorTemplate() override;
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker // SampleCountIterator:
Done() const33*6777b538SAndroid Build Coastguard Worker bool Done() const override { return iter_ == end_; }
Next()34*6777b538SAndroid Build Coastguard Worker void Next() override {
35*6777b538SAndroid Build Coastguard Worker DCHECK(!Done());
36*6777b538SAndroid Build Coastguard Worker ++iter_;
37*6777b538SAndroid Build Coastguard Worker SkipEmptyBuckets();
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker void Get(HistogramBase::Sample* min,
40*6777b538SAndroid Build Coastguard Worker int64_t* max,
41*6777b538SAndroid Build Coastguard Worker HistogramBase::Count* count) override;
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker private:
SkipEmptyBuckets()44*6777b538SAndroid Build Coastguard Worker void SkipEmptyBuckets() {
45*6777b538SAndroid Build Coastguard Worker while (!Done() && iter_->second == 0) {
46*6777b538SAndroid Build Coastguard Worker ++iter_;
47*6777b538SAndroid Build Coastguard Worker }
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker I iter_;
51*6777b538SAndroid Build Coastguard Worker const I end_;
52*6777b538SAndroid Build Coastguard Worker };
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker typedef std::map<HistogramBase::Sample, HistogramBase::Count> SampleToCountMap;
55*6777b538SAndroid Build Coastguard Worker typedef IteratorTemplate<const SampleToCountMap,
56*6777b538SAndroid Build Coastguard Worker SampleToCountMap::const_iterator>
57*6777b538SAndroid Build Coastguard Worker SampleMapIterator;
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker template <>
60*6777b538SAndroid Build Coastguard Worker SampleMapIterator::~IteratorTemplate() = default;
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker // Get() for an iterator of a SampleMap.
63*6777b538SAndroid Build Coastguard Worker template <>
Get(Sample * min,int64_t * max,Count * count)64*6777b538SAndroid Build Coastguard Worker void SampleMapIterator::Get(Sample* min, int64_t* max, Count* count) {
65*6777b538SAndroid Build Coastguard Worker DCHECK(!Done());
66*6777b538SAndroid Build Coastguard Worker *min = iter_->first;
67*6777b538SAndroid Build Coastguard Worker *max = strict_cast<int64_t>(iter_->first) + 1;
68*6777b538SAndroid Build Coastguard Worker // We do not have to do the following atomically -- if the caller needs thread
69*6777b538SAndroid Build Coastguard Worker // safety, they should use a lock. And since this is in local memory, if a
70*6777b538SAndroid Build Coastguard Worker // lock is used, we know the value would not be concurrently modified by a
71*6777b538SAndroid Build Coastguard Worker // different process (in contrast to PersistentSampleMap, where the value in
72*6777b538SAndroid Build Coastguard Worker // shared memory may be modified concurrently by a subprocess).
73*6777b538SAndroid Build Coastguard Worker *count = iter_->second;
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker typedef IteratorTemplate<SampleToCountMap, SampleToCountMap::iterator>
77*6777b538SAndroid Build Coastguard Worker ExtractingSampleMapIterator;
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker template <>
~IteratorTemplate()80*6777b538SAndroid Build Coastguard Worker ExtractingSampleMapIterator::~IteratorTemplate() {
81*6777b538SAndroid Build Coastguard Worker // Ensure that the user has consumed all the samples in order to ensure no
82*6777b538SAndroid Build Coastguard Worker // samples are lost.
83*6777b538SAndroid Build Coastguard Worker DCHECK(Done());
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard Worker // Get() for an extracting iterator of a SampleMap.
87*6777b538SAndroid Build Coastguard Worker template <>
Get(Sample * min,int64_t * max,Count * count)88*6777b538SAndroid Build Coastguard Worker void ExtractingSampleMapIterator::Get(Sample* min, int64_t* max, Count* count) {
89*6777b538SAndroid Build Coastguard Worker DCHECK(!Done());
90*6777b538SAndroid Build Coastguard Worker *min = iter_->first;
91*6777b538SAndroid Build Coastguard Worker *max = strict_cast<int64_t>(iter_->first) + 1;
92*6777b538SAndroid Build Coastguard Worker // We do not have to do the following atomically -- if the caller needs thread
93*6777b538SAndroid Build Coastguard Worker // safety, they should use a lock. And since this is in local memory, if a
94*6777b538SAndroid Build Coastguard Worker // lock is used, we know the value would not be concurrently modified by a
95*6777b538SAndroid Build Coastguard Worker // different process (in contrast to PersistentSampleMap, where the value in
96*6777b538SAndroid Build Coastguard Worker // shared memory may be modified concurrently by a subprocess).
97*6777b538SAndroid Build Coastguard Worker *count = iter_->second;
98*6777b538SAndroid Build Coastguard Worker iter_->second = 0;
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker } // namespace
102*6777b538SAndroid Build Coastguard Worker
SampleMap()103*6777b538SAndroid Build Coastguard Worker SampleMap::SampleMap() : SampleMap(0) {}
104*6777b538SAndroid Build Coastguard Worker
SampleMap(uint64_t id)105*6777b538SAndroid Build Coastguard Worker SampleMap::SampleMap(uint64_t id)
106*6777b538SAndroid Build Coastguard Worker : HistogramSamples(id, std::make_unique<LocalMetadata>()) {}
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker SampleMap::~SampleMap() = default;
109*6777b538SAndroid Build Coastguard Worker
Accumulate(Sample value,Count count)110*6777b538SAndroid Build Coastguard Worker void SampleMap::Accumulate(Sample value, Count count) {
111*6777b538SAndroid Build Coastguard Worker // We do not have to do the following atomically -- if the caller needs
112*6777b538SAndroid Build Coastguard Worker // thread safety, they should use a lock. And since this is in local memory,
113*6777b538SAndroid Build Coastguard Worker // if a lock is used, we know the value would not be concurrently modified
114*6777b538SAndroid Build Coastguard Worker // by a different process (in contrast to PersistentSampleMap, where the
115*6777b538SAndroid Build Coastguard Worker // value in shared memory may be modified concurrently by a subprocess).
116*6777b538SAndroid Build Coastguard Worker sample_counts_[value] += count;
117*6777b538SAndroid Build Coastguard Worker IncreaseSumAndCount(strict_cast<int64_t>(count) * value, count);
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker
GetCount(Sample value) const120*6777b538SAndroid Build Coastguard Worker Count SampleMap::GetCount(Sample value) const {
121*6777b538SAndroid Build Coastguard Worker auto it = sample_counts_.find(value);
122*6777b538SAndroid Build Coastguard Worker if (it == sample_counts_.end())
123*6777b538SAndroid Build Coastguard Worker return 0;
124*6777b538SAndroid Build Coastguard Worker return it->second;
125*6777b538SAndroid Build Coastguard Worker }
126*6777b538SAndroid Build Coastguard Worker
TotalCount() const127*6777b538SAndroid Build Coastguard Worker Count SampleMap::TotalCount() const {
128*6777b538SAndroid Build Coastguard Worker Count count = 0;
129*6777b538SAndroid Build Coastguard Worker for (const auto& entry : sample_counts_) {
130*6777b538SAndroid Build Coastguard Worker count += entry.second;
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker return count;
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
Iterator() const135*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> SampleMap::Iterator() const {
136*6777b538SAndroid Build Coastguard Worker return std::make_unique<SampleMapIterator>(sample_counts_);
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker
ExtractingIterator()139*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> SampleMap::ExtractingIterator() {
140*6777b538SAndroid Build Coastguard Worker return std::make_unique<ExtractingSampleMapIterator>(sample_counts_);
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker
IsDefinitelyEmpty() const143*6777b538SAndroid Build Coastguard Worker bool SampleMap::IsDefinitelyEmpty() const {
144*6777b538SAndroid Build Coastguard Worker // If |sample_counts_| is empty (no entry was ever inserted), then return
145*6777b538SAndroid Build Coastguard Worker // true. If it does contain some entries, then it may or may not have samples
146*6777b538SAndroid Build Coastguard Worker // (e.g. it's possible all entries have a bucket count of 0). Just return
147*6777b538SAndroid Build Coastguard Worker // false in this case. If we are wrong, this will just make the caller perform
148*6777b538SAndroid Build Coastguard Worker // some extra work thinking that |this| is non-empty.
149*6777b538SAndroid Build Coastguard Worker return HistogramSamples::IsDefinitelyEmpty() && sample_counts_.empty();
150*6777b538SAndroid Build Coastguard Worker }
151*6777b538SAndroid Build Coastguard Worker
AddSubtractImpl(SampleCountIterator * iter,Operator op)152*6777b538SAndroid Build Coastguard Worker bool SampleMap::AddSubtractImpl(SampleCountIterator* iter, Operator op) {
153*6777b538SAndroid Build Coastguard Worker Sample min;
154*6777b538SAndroid Build Coastguard Worker int64_t max;
155*6777b538SAndroid Build Coastguard Worker Count count;
156*6777b538SAndroid Build Coastguard Worker for (; !iter->Done(); iter->Next()) {
157*6777b538SAndroid Build Coastguard Worker iter->Get(&min, &max, &count);
158*6777b538SAndroid Build Coastguard Worker if (strict_cast<int64_t>(min) + 1 != max) {
159*6777b538SAndroid Build Coastguard Worker return false; // SparseHistogram only supports bucket with size 1.
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker // Note that we do not need to check that count != 0, since Next() above
163*6777b538SAndroid Build Coastguard Worker // will skip empty buckets.
164*6777b538SAndroid Build Coastguard Worker
165*6777b538SAndroid Build Coastguard Worker // We do not have to do the following atomically -- if the caller needs
166*6777b538SAndroid Build Coastguard Worker // thread safety, they should use a lock. And since this is in local memory,
167*6777b538SAndroid Build Coastguard Worker // if a lock is used, we know the value would not be concurrently modified
168*6777b538SAndroid Build Coastguard Worker // by a different process (in contrast to PersistentSampleMap, where the
169*6777b538SAndroid Build Coastguard Worker // value in shared memory may be modified concurrently by a subprocess).
170*6777b538SAndroid Build Coastguard Worker Count& sample_ref = sample_counts_[min];
171*6777b538SAndroid Build Coastguard Worker if (op == HistogramSamples::ADD) {
172*6777b538SAndroid Build Coastguard Worker sample_ref = base::WrappingAdd(sample_ref, count);
173*6777b538SAndroid Build Coastguard Worker } else {
174*6777b538SAndroid Build Coastguard Worker sample_ref = base::WrappingSub(sample_ref, count);
175*6777b538SAndroid Build Coastguard Worker }
176*6777b538SAndroid Build Coastguard Worker }
177*6777b538SAndroid Build Coastguard Worker return true;
178*6777b538SAndroid Build Coastguard Worker }
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker } // namespace base
181