1 // 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 #include "base/metrics/histogram_samples.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/pickle.h"
9
10 namespace base {
11
12 namespace {
13
14 class SampleCountPickleIterator : public SampleCountIterator {
15 public:
16 explicit SampleCountPickleIterator(PickleIterator* iter);
17
18 bool Done() const override;
19 void Next() override;
20 void Get(HistogramBase::Sample* min,
21 HistogramBase::Sample* max,
22 HistogramBase::Count* count) const override;
23
24 private:
25 PickleIterator* const iter_;
26
27 HistogramBase::Sample min_;
28 HistogramBase::Sample max_;
29 HistogramBase::Count count_;
30 bool is_done_;
31 };
32
SampleCountPickleIterator(PickleIterator * iter)33 SampleCountPickleIterator::SampleCountPickleIterator(PickleIterator* iter)
34 : iter_(iter),
35 is_done_(false) {
36 Next();
37 }
38
Done() const39 bool SampleCountPickleIterator::Done() const {
40 return is_done_;
41 }
42
Next()43 void SampleCountPickleIterator::Next() {
44 DCHECK(!Done());
45 if (!iter_->ReadInt(&min_) ||
46 !iter_->ReadInt(&max_) ||
47 !iter_->ReadInt(&count_))
48 is_done_ = true;
49 }
50
Get(HistogramBase::Sample * min,HistogramBase::Sample * max,HistogramBase::Count * count) const51 void SampleCountPickleIterator::Get(HistogramBase::Sample* min,
52 HistogramBase::Sample* max,
53 HistogramBase::Count* count) const {
54 DCHECK(!Done());
55 *min = min_;
56 *max = max_;
57 *count = count_;
58 }
59
60 } // namespace
61
62 // Don't try to delegate behavior to the constructor below that accepts a
63 // Matadata pointer by passing &local_meta_. Such cannot be reliably passed
64 // because it has not yet been constructed -- no member variables have; the
65 // class itself is in the middle of being constructed. Using it to
66 // initialize meta_ is okay because the object now exists and local_meta_
67 // is before meta_ in the construction order.
HistogramSamples(uint64_t id)68 HistogramSamples::HistogramSamples(uint64_t id)
69 : meta_(&local_meta_) {
70 meta_->id = id;
71 }
72
HistogramSamples(uint64_t id,Metadata * meta)73 HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta)
74 : meta_(meta) {
75 DCHECK(meta_->id == 0 || meta_->id == id);
76
77 // It's possible that |meta| is contained in initialized, read-only memory
78 // so it's essential that no write be done in that case.
79 if (!meta_->id)
80 meta_->id = id;
81 }
82
~HistogramSamples()83 HistogramSamples::~HistogramSamples() {}
84
Add(const HistogramSamples & other)85 void HistogramSamples::Add(const HistogramSamples& other) {
86 IncreaseSum(other.sum());
87 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
88 other.redundant_count());
89 bool success = AddSubtractImpl(other.Iterator().get(), ADD);
90 DCHECK(success);
91 }
92
AddFromPickle(PickleIterator * iter)93 bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
94 int64_t sum;
95 HistogramBase::Count redundant_count;
96
97 if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
98 return false;
99
100 IncreaseSum(sum);
101 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
102 redundant_count);
103
104 SampleCountPickleIterator pickle_iter(iter);
105 return AddSubtractImpl(&pickle_iter, ADD);
106 }
107
Subtract(const HistogramSamples & other)108 void HistogramSamples::Subtract(const HistogramSamples& other) {
109 IncreaseSum(-other.sum());
110 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
111 -other.redundant_count());
112 bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
113 DCHECK(success);
114 }
115
Serialize(Pickle * pickle) const116 bool HistogramSamples::Serialize(Pickle* pickle) const {
117 if (!pickle->WriteInt64(sum()))
118 return false;
119 if (!pickle->WriteInt(redundant_count()))
120 return false;
121
122 HistogramBase::Sample min;
123 HistogramBase::Sample max;
124 HistogramBase::Count count;
125 for (std::unique_ptr<SampleCountIterator> it = Iterator(); !it->Done();
126 it->Next()) {
127 it->Get(&min, &max, &count);
128 if (!pickle->WriteInt(min) ||
129 !pickle->WriteInt(max) ||
130 !pickle->WriteInt(count))
131 return false;
132 }
133 return true;
134 }
135
IncreaseSum(int64_t diff)136 void HistogramSamples::IncreaseSum(int64_t diff) {
137 #ifdef ARCH_CPU_64_BITS
138 subtle::NoBarrier_AtomicIncrement(&meta_->sum, diff);
139 #else
140 meta_->sum += diff;
141 #endif
142 }
143
IncreaseRedundantCount(HistogramBase::Count diff)144 void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
145 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count, diff);
146 }
147
~SampleCountIterator()148 SampleCountIterator::~SampleCountIterator() {}
149
GetBucketIndex(size_t *) const150 bool SampleCountIterator::GetBucketIndex(size_t* /*index*/) const {
151 DCHECK(!Done());
152 return false;
153 }
154
155 } // namespace base
156