• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   meta_->id = id;
77 }
78 
~HistogramSamples()79 HistogramSamples::~HistogramSamples() {}
80 
81 // Despite using atomic operations, the increment/add actions below are *not*
82 // atomic! Race conditions may cause loss of samples or even completely corrupt
83 // the 64-bit sum on 32-bit machines. This is done intentionally to reduce the
84 // cost of these operations that could be executed in performance-significant
85 //  points of the code.
86 //
87 // TODO(bcwhite): Gather quantitative information as to the cost of using
88 // proper atomic increments and improve either globally or for those histograms
89 // that really need it.
90 
Add(const HistogramSamples & other)91 void HistogramSamples::Add(const HistogramSamples& other) {
92   meta_->sum += other.sum();
93 
94   HistogramBase::Count old_redundant_count =
95       subtle::NoBarrier_Load(&meta_->redundant_count);
96   subtle::NoBarrier_Store(&meta_->redundant_count,
97       old_redundant_count + other.redundant_count());
98   bool success = AddSubtractImpl(other.Iterator().get(), ADD);
99   DCHECK(success);
100 }
101 
AddFromPickle(PickleIterator * iter)102 bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
103   int64_t sum;
104   HistogramBase::Count redundant_count;
105 
106   if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
107     return false;
108 
109   meta_->sum += sum;
110 
111   HistogramBase::Count old_redundant_count =
112       subtle::NoBarrier_Load(&meta_->redundant_count);
113   subtle::NoBarrier_Store(&meta_->redundant_count,
114                           old_redundant_count + redundant_count);
115 
116   SampleCountPickleIterator pickle_iter(iter);
117   return AddSubtractImpl(&pickle_iter, ADD);
118 }
119 
Subtract(const HistogramSamples & other)120 void HistogramSamples::Subtract(const HistogramSamples& other) {
121   meta_->sum -= other.sum();
122 
123   HistogramBase::Count old_redundant_count =
124       subtle::NoBarrier_Load(&meta_->redundant_count);
125   subtle::NoBarrier_Store(&meta_->redundant_count,
126                           old_redundant_count - other.redundant_count());
127   bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
128   DCHECK(success);
129 }
130 
Serialize(Pickle * pickle) const131 bool HistogramSamples::Serialize(Pickle* pickle) const {
132   if (!pickle->WriteInt64(meta_->sum))
133     return false;
134   if (!pickle->WriteInt(subtle::NoBarrier_Load(&meta_->redundant_count)))
135     return false;
136 
137   HistogramBase::Sample min;
138   HistogramBase::Sample max;
139   HistogramBase::Count count;
140   for (scoped_ptr<SampleCountIterator> it = Iterator();
141        !it->Done();
142        it->Next()) {
143     it->Get(&min, &max, &count);
144     if (!pickle->WriteInt(min) ||
145         !pickle->WriteInt(max) ||
146         !pickle->WriteInt(count))
147       return false;
148   }
149   return true;
150 }
151 
IncreaseSum(int64_t diff)152 void HistogramSamples::IncreaseSum(int64_t diff) {
153   meta_->sum += diff;
154 }
155 
IncreaseRedundantCount(HistogramBase::Count diff)156 void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
157   subtle::NoBarrier_Store(&meta_->redundant_count,
158       subtle::NoBarrier_Load(&meta_->redundant_count) + diff);
159 }
160 
~SampleCountIterator()161 SampleCountIterator::~SampleCountIterator() {}
162 
GetBucketIndex(size_t *) const163 bool SampleCountIterator::GetBucketIndex(size_t* /* index */) const {
164   DCHECK(!Done());
165   return false;
166 }
167 
168 }  // namespace base
169