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/sample_vector.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/metrics/bucket_ranges.h"
      9 
     10 namespace base {
     11 
     12 typedef HistogramBase::Count Count;
     13 typedef HistogramBase::Sample Sample;
     14 
     15 SampleVector::SampleVector(const BucketRanges* bucket_ranges)
     16     : SampleVector(0, bucket_ranges) {}
     17 
     18 SampleVector::SampleVector(uint64_t id, const BucketRanges* bucket_ranges)
     19     : HistogramSamples(id),
     20       local_counts_(bucket_ranges->bucket_count()),
     21       counts_(&local_counts_[0]),
     22       counts_size_(local_counts_.size()),
     23       bucket_ranges_(bucket_ranges) {
     24   CHECK_GE(bucket_ranges_->bucket_count(), 1u);
     25 }
     26 
     27 SampleVector::SampleVector(uint64_t id,
     28                            HistogramBase::AtomicCount* counts,
     29                            size_t counts_size,
     30                            Metadata* meta,
     31                            const BucketRanges* bucket_ranges)
     32     : HistogramSamples(id, meta),
     33       counts_(counts),
     34       counts_size_(bucket_ranges->bucket_count()),
     35       bucket_ranges_(bucket_ranges) {
     36   CHECK_LE(bucket_ranges_->bucket_count(), counts_size_);
     37   CHECK_GE(bucket_ranges_->bucket_count(), 1u);
     38 }
     39 
     40 SampleVector::~SampleVector() {}
     41 
     42 void SampleVector::Accumulate(Sample value, Count count) {
     43   size_t bucket_index = GetBucketIndex(value);
     44   subtle::NoBarrier_AtomicIncrement(&counts_[bucket_index], count);
     45   IncreaseSum(static_cast<int64_t>(count) * value);
     46   IncreaseRedundantCount(count);
     47 }
     48 
     49 Count SampleVector::GetCount(Sample value) const {
     50   size_t bucket_index = GetBucketIndex(value);
     51   return subtle::NoBarrier_Load(&counts_[bucket_index]);
     52 }
     53 
     54 Count SampleVector::TotalCount() const {
     55   Count count = 0;
     56   for (size_t i = 0; i < counts_size_; i++) {
     57     count += subtle::NoBarrier_Load(&counts_[i]);
     58   }
     59   return count;
     60 }
     61 
     62 Count SampleVector::GetCountAtIndex(size_t bucket_index) const {
     63   DCHECK(bucket_index < counts_size_);
     64   return subtle::NoBarrier_Load(&counts_[bucket_index]);
     65 }
     66 
     67 std::unique_ptr<SampleCountIterator> SampleVector::Iterator() const {
     68   return std::unique_ptr<SampleCountIterator>(
     69       new SampleVectorIterator(counts_, counts_size_, bucket_ranges_));
     70 }
     71 
     72 bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
     73                                    HistogramSamples::Operator op) {
     74   HistogramBase::Sample min;
     75   HistogramBase::Sample max;
     76   HistogramBase::Count count;
     77 
     78   // Go through the iterator and add the counts into correct bucket.
     79   size_t index = 0;
     80   while (index < counts_size_ && !iter->Done()) {
     81     iter->Get(&min, &max, &count);
     82     if (min == bucket_ranges_->range(index) &&
     83         max == bucket_ranges_->range(index + 1)) {
     84       // Sample matches this bucket!
     85       subtle::NoBarrier_AtomicIncrement(
     86           &counts_[index], op == HistogramSamples::ADD ? count : -count);
     87       iter->Next();
     88     } else if (min > bucket_ranges_->range(index)) {
     89       // Sample is larger than current bucket range. Try next.
     90       index++;
     91     } else {
     92       // Sample is smaller than current bucket range. We scan buckets from
     93       // smallest to largest, so the sample value must be invalid.
     94       return false;
     95     }
     96   }
     97 
     98   return iter->Done();
     99 }
    100 
    101 // Use simple binary search.  This is very general, but there are better
    102 // approaches if we knew that the buckets were linearly distributed.
    103 size_t SampleVector::GetBucketIndex(Sample value) const {
    104   size_t bucket_count = bucket_ranges_->bucket_count();
    105   CHECK_GE(bucket_count, 1u);
    106   CHECK_GE(value, bucket_ranges_->range(0));
    107   CHECK_LT(value, bucket_ranges_->range(bucket_count));
    108 
    109   size_t under = 0;
    110   size_t over = bucket_count;
    111   size_t mid;
    112   do {
    113     DCHECK_GE(over, under);
    114     mid = under + (over - under)/2;
    115     if (mid == under)
    116       break;
    117     if (bucket_ranges_->range(mid) <= value)
    118       under = mid;
    119     else
    120       over = mid;
    121   } while (true);
    122 
    123   DCHECK_LE(bucket_ranges_->range(mid), value);
    124   CHECK_GT(bucket_ranges_->range(mid + 1), value);
    125   return mid;
    126 }
    127 
    128 SampleVectorIterator::SampleVectorIterator(
    129     const std::vector<HistogramBase::AtomicCount>* counts,
    130     const BucketRanges* bucket_ranges)
    131     : counts_(&(*counts)[0]),
    132       counts_size_(counts->size()),
    133       bucket_ranges_(bucket_ranges),
    134       index_(0) {
    135   CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
    136   SkipEmptyBuckets();
    137 }
    138 
    139 SampleVectorIterator::SampleVectorIterator(
    140     const HistogramBase::AtomicCount* counts,
    141     size_t counts_size,
    142     const BucketRanges* bucket_ranges)
    143     : counts_(counts),
    144       counts_size_(counts_size),
    145       bucket_ranges_(bucket_ranges),
    146       index_(0) {
    147   CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
    148   SkipEmptyBuckets();
    149 }
    150 
    151 SampleVectorIterator::~SampleVectorIterator() {}
    152 
    153 bool SampleVectorIterator::Done() const {
    154   return index_ >= counts_size_;
    155 }
    156 
    157 void SampleVectorIterator::Next() {
    158   DCHECK(!Done());
    159   index_++;
    160   SkipEmptyBuckets();
    161 }
    162 
    163 void SampleVectorIterator::Get(HistogramBase::Sample* min,
    164                                HistogramBase::Sample* max,
    165                                HistogramBase::Count* count) const {
    166   DCHECK(!Done());
    167   if (min != NULL)
    168     *min = bucket_ranges_->range(index_);
    169   if (max != NULL)
    170     *max = bucket_ranges_->range(index_ + 1);
    171   if (count != NULL)
    172     *count = subtle::NoBarrier_Load(&counts_[index_]);
    173 }
    174 
    175 bool SampleVectorIterator::GetBucketIndex(size_t* index) const {
    176   DCHECK(!Done());
    177   if (index != NULL)
    178     *index = index_;
    179   return true;
    180 }
    181 
    182 void SampleVectorIterator::SkipEmptyBuckets() {
    183   if (Done())
    184     return;
    185 
    186   while (index_ < counts_size_) {
    187     if (subtle::NoBarrier_Load(&counts_[index_]) != 0)
    188       return;
    189     index_++;
    190   }
    191 }
    192 
    193 }  // namespace base
    194