Home | History | Annotate | Download | only in metrics
      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