Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Side by Side Diff: base/metrics/histogram_samples.cc

Issue 2811713003: Embed a single sample in histogram metadata. (Closed)
Patch Set: fixed build problems Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/metrics/histogram_samples.h" 5 #include "base/metrics/histogram_samples.h"
6 6
7 #include <limits>
8
7 #include "base/compiler_specific.h" 9 #include "base/compiler_specific.h"
8 #include "base/pickle.h" 10 #include "base/pickle.h"
9 11
10 namespace base { 12 namespace base {
11 13
12 namespace { 14 namespace {
13 15
16 const size_t kSizeMax = std::numeric_limits<size_t>::max();
17
18 const int32_t kDisabledSingleSample = -1;
Alexei Svitkine (slow) 2017/04/12 17:38:06 These need comments.
bcwhite 2017/04/13 00:06:01 Done.
19
14 class SampleCountPickleIterator : public SampleCountIterator { 20 class SampleCountPickleIterator : public SampleCountIterator {
15 public: 21 public:
16 explicit SampleCountPickleIterator(PickleIterator* iter); 22 explicit SampleCountPickleIterator(PickleIterator* iter);
17 23
18 bool Done() const override; 24 bool Done() const override;
19 void Next() override; 25 void Next() override;
20 void Get(HistogramBase::Sample* min, 26 void Get(HistogramBase::Sample* min,
21 HistogramBase::Sample* max, 27 HistogramBase::Sample* max,
22 HistogramBase::Count* count) const override; 28 HistogramBase::Count* count) const override;
23 29
(...skipping 28 matching lines...) Expand all
52 HistogramBase::Sample* max, 58 HistogramBase::Sample* max,
53 HistogramBase::Count* count) const { 59 HistogramBase::Count* count) const {
54 DCHECK(!Done()); 60 DCHECK(!Done());
55 *min = min_; 61 *min = min_;
56 *max = max_; 62 *max = max_;
57 *count = count_; 63 *count = count_;
58 } 64 }
59 65
60 } // namespace 66 } // namespace
61 67
68 static_assert(sizeof(HistogramSamples::AtomicSingleSample) ==
69 sizeof(subtle::Atomic32),
70 "AtomicSingleSample isn't 32 bits");
71
72 HistogramSamples::SingleSample HistogramSamples::AtomicSingleSample::Load()
73 const {
74 AtomicSingleSample single_sample = subtle::Acquire_Load(&as_atomic);
75 if (single_sample.as_atomic == kDisabledSingleSample)
76 single_sample.as_atomic = 0;
77 return single_sample.as_parts;
78 }
79
80 HistogramSamples::SingleSample HistogramSamples::AtomicSingleSample::Extract(
81 bool disable) {
82 AtomicSingleSample single_sample = subtle::NoBarrier_AtomicExchange(
83 &as_atomic, disable ? kDisabledSingleSample : 0);
84 if (single_sample.as_atomic == kDisabledSingleSample)
85 single_sample.as_atomic = 0;
86 return single_sample.as_parts;
87 }
88
89 bool HistogramSamples::AtomicSingleSample::Accumulate(
90 HistogramBase::Sample value,
91 HistogramBase::Count count) {
92 if (count == 0)
93 return true;
94
95 // Convert the parameters to 16-bit variables because it's all 16-bit below.
96 if (value < std::numeric_limits<int16_t>::min() ||
97 value > std::numeric_limits<int16_t>::max() ||
98 count < std::numeric_limits<int16_t>::min() ||
99 count > std::numeric_limits<int16_t>::max()) {
100 return false;
101 }
102 int16_t value16 = static_cast<int16_t>(value);
103 int16_t count16 = static_cast<int16_t>(count);
104
105 // A local, unshared copy of the single-sample is necessary so the parts
106 // can be manipulated without worrying about atomicity.
107 AtomicSingleSample single_sample;
108
109 subtle::Atomic32 existing, found;
110 do {
111 existing = subtle::Acquire_Load(&as_atomic);
112 // This has to be checked again in case it has changed.
113 if (existing == kDisabledSingleSample)
114 return false;
115 single_sample.as_atomic = existing;
116 if (single_sample.as_atomic != 0) {
117 if (single_sample.as_parts.value != value16)
118 return false;
119 // Make sure counts don't overflow.
120 if (count16 < 0) {
121 if (single_sample.as_parts.count <
122 std::numeric_limits<int16_t>::min() - count16) {
123 return false;
124 }
125 } else {
126 if (single_sample.as_parts.count >
127 std::numeric_limits<int16_t>::max() - count16) {
128 return false;
129 }
130 }
131 } else {
132 single_sample.as_parts.value = value16;
133 }
134
135 single_sample.as_parts.count += count16;
136 if (single_sample.as_parts.count == 0)
137 single_sample.as_atomic = 0;
138 else if (single_sample.as_atomic == kDisabledSingleSample)
139 return false;
140 found = subtle::Release_CompareAndSwap(&as_atomic, existing,
141 single_sample.as_atomic);
142 } while (found != existing);
143
144 return true;
145 }
146
147 HistogramSamples::LocalMetadata::LocalMetadata() {
148 // This is the same way it's done for persistent metadata since no ctor
149 // is called for the data members in that case.
150 memset(this, 0, sizeof(*this));
151 }
152
62 // Don't try to delegate behavior to the constructor below that accepts a 153 // 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 154 // Matadata pointer by passing &local_meta_. Such cannot be reliably passed
64 // because it has not yet been constructed -- no member variables have; the 155 // 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 156 // 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_ 157 // initialize meta_ is okay because the object now exists and local_meta_
67 // is before meta_ in the construction order. 158 // is before meta_ in the construction order.
68 HistogramSamples::HistogramSamples(uint64_t id) 159 HistogramSamples::HistogramSamples(uint64_t id)
69 : meta_(&local_meta_) { 160 : meta_(&local_meta_) {
70 meta_->id = id; 161 meta_->id = id;
71 } 162 }
72 163
73 HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta) 164 HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta)
74 : meta_(meta) { 165 : meta_(meta) {
75 DCHECK(meta_->id == 0 || meta_->id == id); 166 DCHECK(meta_->id == 0 || meta_->id == id);
76 167
77 // It's possible that |meta| is contained in initialized, read-only memory 168 // 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. 169 // so it's essential that no write be done in that case.
79 if (!meta_->id) 170 if (!meta_->id)
80 meta_->id = id; 171 meta_->id = id;
81 } 172 }
82 173
83 HistogramSamples::~HistogramSamples() {} 174 HistogramSamples::~HistogramSamples() {}
84 175
85 void HistogramSamples::Add(const HistogramSamples& other) { 176 void HistogramSamples::Add(const HistogramSamples& other) {
86 IncreaseSum(other.sum()); 177 IncreaseSumAndCount(other.sum(), other.redundant_count());
87 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
88 other.redundant_count());
89 bool success = AddSubtractImpl(other.Iterator().get(), ADD); 178 bool success = AddSubtractImpl(other.Iterator().get(), ADD);
90 DCHECK(success); 179 DCHECK(success);
91 } 180 }
92 181
93 bool HistogramSamples::AddFromPickle(PickleIterator* iter) { 182 bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
94 int64_t sum; 183 int64_t sum;
95 HistogramBase::Count redundant_count; 184 HistogramBase::Count redundant_count;
96 185
97 if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count)) 186 if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
98 return false; 187 return false;
99 188
100 IncreaseSum(sum); 189 IncreaseSumAndCount(sum, redundant_count);
101 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
102 redundant_count);
103 190
104 SampleCountPickleIterator pickle_iter(iter); 191 SampleCountPickleIterator pickle_iter(iter);
105 return AddSubtractImpl(&pickle_iter, ADD); 192 return AddSubtractImpl(&pickle_iter, ADD);
106 } 193 }
107 194
108 void HistogramSamples::Subtract(const HistogramSamples& other) { 195 void HistogramSamples::Subtract(const HistogramSamples& other) {
109 IncreaseSum(-other.sum()); 196 IncreaseSumAndCount(-other.sum(), -other.redundant_count());
110 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
111 -other.redundant_count());
112 bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT); 197 bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
113 DCHECK(success); 198 DCHECK(success);
114 } 199 }
115 200
116 bool HistogramSamples::Serialize(Pickle* pickle) const { 201 bool HistogramSamples::Serialize(Pickle* pickle) const {
117 if (!pickle->WriteInt64(sum())) 202 if (!pickle->WriteInt64(sum()))
118 return false; 203 return false;
119 if (!pickle->WriteInt(redundant_count())) 204 if (!pickle->WriteInt(redundant_count()))
120 return false; 205 return false;
121 206
122 HistogramBase::Sample min; 207 HistogramBase::Sample min;
123 HistogramBase::Sample max; 208 HistogramBase::Sample max;
124 HistogramBase::Count count; 209 HistogramBase::Count count;
125 for (std::unique_ptr<SampleCountIterator> it = Iterator(); !it->Done(); 210 for (std::unique_ptr<SampleCountIterator> it = Iterator(); !it->Done();
126 it->Next()) { 211 it->Next()) {
127 it->Get(&min, &max, &count); 212 it->Get(&min, &max, &count);
128 if (!pickle->WriteInt(min) || 213 if (!pickle->WriteInt(min) ||
129 !pickle->WriteInt(max) || 214 !pickle->WriteInt(max) ||
130 !pickle->WriteInt(count)) 215 !pickle->WriteInt(count))
131 return false; 216 return false;
132 } 217 }
133 return true; 218 return true;
134 } 219 }
135 220
136 void HistogramSamples::IncreaseSum(int64_t diff) { 221 bool HistogramSamples::AccumulateSingleSample(HistogramBase::Sample value,
137 #ifdef ARCH_CPU_64_BITS 222 HistogramBase::Count count) {
138 subtle::NoBarrier_AtomicIncrement(&meta_->sum, diff); 223 if (single_sample().Accumulate(value, count)) {
139 #else 224 // Success. Update the (separate) sum and redundant-count.
140 meta_->sum += diff; 225 IncreaseSumAndCount(static_cast<int64_t>(value) * count, count);
141 #endif 226 return true;
227 }
228 return false;
142 } 229 }
143 230
144 void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) { 231 void HistogramSamples::IncreaseSumAndCount(int64_t sum,
145 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count, diff); 232 HistogramBase::Count count) {
233 #ifdef ARCH_CPU_64_BITS
234 subtle::NoBarrier_AtomicIncrement(&meta_->sum, sum);
235 #else
236 meta_->sum += sum;
237 #endif
238 subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count, count);
146 } 239 }
147 240
148 SampleCountIterator::~SampleCountIterator() {} 241 SampleCountIterator::~SampleCountIterator() {}
149 242
150 bool SampleCountIterator::GetBucketIndex(size_t* index) const { 243 bool SampleCountIterator::GetBucketIndex(size_t* index) const {
151 DCHECK(!Done()); 244 DCHECK(!Done());
152 return false; 245 return false;
153 } 246 }
154 247
248 SingleSampleIterator::SingleSampleIterator(HistogramBase::Sample min,
249 HistogramBase::Sample max,
250 HistogramBase::Count count)
251 : SingleSampleIterator(min, max, count, kSizeMax) {}
Alexei Svitkine (slow) 2017/04/12 17:38:07 Nit: Add an empty line between ctors and methods -
bcwhite 2017/04/13 00:06:01 Done.
252 SingleSampleIterator::SingleSampleIterator(HistogramBase::Sample min,
253 HistogramBase::Sample max,
254 HistogramBase::Count count,
255 size_t bucket_index)
256 : min_(min), max_(max), bucket_index_(bucket_index), count_(count) {}
257
258 SingleSampleIterator::~SingleSampleIterator() {}
259
260 bool SingleSampleIterator::Done() const {
261 return count_ == 0;
262 }
263 void SingleSampleIterator::Next() {
264 DCHECK(!Done());
265 count_ = 0;
266 }
267 void SingleSampleIterator::Get(HistogramBase::Sample* min,
268 HistogramBase::Sample* max,
269 HistogramBase::Count* count) const {
270 DCHECK(!Done());
271 if (min != nullptr)
272 *min = min_;
273 if (max != nullptr)
274 *max = max_;
275 if (count != nullptr)
276 *count = count_;
277 }
278
279 bool SingleSampleIterator::GetBucketIndex(size_t* index) const {
280 DCHECK(!Done());
281 if (bucket_index_ == kSizeMax)
282 return false;
283 *index = bucket_index_;
284 return true;
285 }
286
155 } // namespace base 287 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698