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 33 SampleCountPickleIterator::SampleCountPickleIterator(PickleIterator* iter) 34 : iter_(iter), 35 is_done_(false) { 36 Next(); 37 } 38 39 bool SampleCountPickleIterator::Done() const { 40 return is_done_; 41 } 42 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 51 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. 68 HistogramSamples::HistogramSamples(uint64_t id) 69 : meta_(&local_meta_) { 70 meta_->id = id; 71 } 72 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 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 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 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 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 131 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 152 void HistogramSamples::IncreaseSum(int64_t diff) { 153 meta_->sum += diff; 154 } 155 156 void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) { 157 subtle::NoBarrier_Store(&meta_->redundant_count, 158 subtle::NoBarrier_Load(&meta_->redundant_count) + diff); 159 } 160 161 SampleCountIterator::~SampleCountIterator() {} 162 163 bool SampleCountIterator::GetBucketIndex(size_t* /* index */) const { 164 DCHECK(!Done()); 165 return false; 166 } 167 168 } // namespace base 169