blob: 812ed86e40f825654f6836fecc84eab6736e0f30 [file] [log] [blame]
Sameer Abu Asala8439542013-02-14 16:06:42 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_RUNTIME_BASE_HISTOGRAM_INL_H_
18#define ART_RUNTIME_BASE_HISTOGRAM_INL_H_
Sameer Abu Asala8439542013-02-14 16:06:42 -080019
20#include "histogram.h"
21
22#include "utils.h"
23
24#include <algorithm>
25#include <cmath>
26#include <limits>
27#include <ostream>
28
29namespace art {
30
31template <class Value> inline void Histogram<Value>::AddValue(Value value) {
Mathieu Chartiere5426c92013-08-01 13:55:42 -070032 CHECK_GE(value, static_cast<Value>(0));
Sameer Abu Asala8439542013-02-14 16:06:42 -080033 if (value >= max_) {
34 Value new_max = ((value + 1) / bucket_width_ + 1) * bucket_width_;
35 DCHECK_GT(new_max, max_);
36 GrowBuckets(new_max);
37 }
Sameer Abu Asala8439542013-02-14 16:06:42 -080038 BucketiseValue(value);
Sameer Abu Asala8439542013-02-14 16:06:42 -080039}
40
Mathieu Chartier70a596d2014-12-17 14:56:47 -080041template <class Value> inline void Histogram<Value>::AdjustAndAddValue(Value value) {
42 AddValue(value / kAdjust);
43}
44
Mathieu Chartier19b0a912013-11-20 14:07:54 -080045template <class Value> inline Histogram<Value>::Histogram(const char* name)
46 : kAdjust(0),
47 kInitialBucketCount(0),
48 name_(name),
49 max_buckets_(0) {
50}
51
Sameer Abu Asala8439542013-02-14 16:06:42 -080052template <class Value>
Mathieu Chartiere5426c92013-08-01 13:55:42 -070053inline Histogram<Value>::Histogram(const char* name, Value initial_bucket_width,
54 size_t max_buckets)
Sameer Abu Asala8439542013-02-14 16:06:42 -080055 : kAdjust(1000),
Mathieu Chartiere5426c92013-08-01 13:55:42 -070056 kInitialBucketCount(8),
57 name_(name),
58 max_buckets_(max_buckets),
59 bucket_width_(initial_bucket_width) {
Sameer Abu Asala8439542013-02-14 16:06:42 -080060 Reset();
61}
62
63template <class Value>
64inline void Histogram<Value>::GrowBuckets(Value new_max) {
65 while (max_ < new_max) {
Mathieu Chartiere5426c92013-08-01 13:55:42 -070066 // If we have reached the maximum number of buckets, merge buckets together.
67 if (frequency_.size() >= max_buckets_) {
68 CHECK(IsAligned<2>(frequency_.size()));
69 // We double the width of each bucket to reduce the number of buckets by a factor of 2.
70 bucket_width_ *= 2;
71 const size_t limit = frequency_.size() / 2;
72 // Merge the frequencies by adding each adjacent two together.
73 for (size_t i = 0; i < limit; ++i) {
74 frequency_[i] = frequency_[i * 2] + frequency_[i * 2 + 1];
75 }
76 // Remove frequencies in the second half of the array which were added to the first half.
77 while (frequency_.size() > limit) {
78 frequency_.pop_back();
79 }
80 }
Sameer Abu Asala8439542013-02-14 16:06:42 -080081 max_ += bucket_width_;
Sameer Abu Asala8439542013-02-14 16:06:42 -080082 frequency_.push_back(0);
Sameer Abu Asala8439542013-02-14 16:06:42 -080083 }
84}
85
Mathieu Chartiere5426c92013-08-01 13:55:42 -070086template <class Value> inline size_t Histogram<Value>::FindBucket(Value val) const {
Sameer Abu Asala8439542013-02-14 16:06:42 -080087 // Since this is only a linear histogram, bucket index can be found simply with
88 // dividing the value by the bucket width.
89 DCHECK_GE(val, min_);
90 DCHECK_LE(val, max_);
Mathieu Chartiere5426c92013-08-01 13:55:42 -070091 const size_t bucket_idx = static_cast<size_t>((val - min_) / bucket_width_);
Sameer Abu Asala8439542013-02-14 16:06:42 -080092 DCHECK_GE(bucket_idx, 0ul);
Mathieu Chartiere5426c92013-08-01 13:55:42 -070093 DCHECK_LE(bucket_idx, GetBucketCount());
Sameer Abu Asala8439542013-02-14 16:06:42 -080094 return bucket_idx;
95}
96
97template <class Value>
Mathieu Chartiere5426c92013-08-01 13:55:42 -070098inline void Histogram<Value>::BucketiseValue(Value val) {
99 CHECK_LT(val, max_);
100 sum_ += val;
101 sum_of_squares_ += val * val;
102 ++sample_size_;
103 ++frequency_[FindBucket(val)];
104 max_value_added_ = std::max(val, max_value_added_);
105 min_value_added_ = std::min(val, min_value_added_);
Sameer Abu Asala8439542013-02-14 16:06:42 -0800106}
107
108template <class Value> inline void Histogram<Value>::Initialize() {
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700109 for (size_t idx = 0; idx < kInitialBucketCount; idx++) {
Sameer Abu Asala8439542013-02-14 16:06:42 -0800110 frequency_.push_back(0);
111 }
112 // Cumulative frequency and ranges has a length of 1 over frequency.
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700113 max_ = bucket_width_ * GetBucketCount();
114}
115
116template <class Value> inline size_t Histogram<Value>::GetBucketCount() const {
117 return frequency_.size();
Sameer Abu Asala8439542013-02-14 16:06:42 -0800118}
119
120template <class Value> inline void Histogram<Value>::Reset() {
Sameer Abu Asala8439542013-02-14 16:06:42 -0800121 sum_of_squares_ = 0;
122 sample_size_ = 0;
123 min_ = 0;
124 sum_ = 0;
125 min_value_added_ = std::numeric_limits<Value>::max();
126 max_value_added_ = std::numeric_limits<Value>::min();
Sameer Abu Asala8439542013-02-14 16:06:42 -0800127 frequency_.clear();
Sameer Abu Asala8439542013-02-14 16:06:42 -0800128 Initialize();
129}
130
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700131template <class Value> inline Value Histogram<Value>::GetRange(size_t bucket_idx) const {
132 DCHECK_LE(bucket_idx, GetBucketCount());
133 return min_ + bucket_idx * bucket_width_;
Sameer Abu Asala8439542013-02-14 16:06:42 -0800134}
135
136template <class Value> inline double Histogram<Value>::Mean() const {
137 DCHECK_GT(sample_size_, 0ull);
138 return static_cast<double>(sum_) / static_cast<double>(sample_size_);
139}
140
141template <class Value> inline double Histogram<Value>::Variance() const {
142 DCHECK_GT(sample_size_, 0ull);
143 // Using algorithms for calculating variance over a population:
144 // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
145 Value sum_squared = sum_ * sum_;
146 double sum_squared_by_n_squared =
147 static_cast<double>(sum_squared) /
148 static_cast<double>(sample_size_ * sample_size_);
149 double sum_of_squares_by_n =
150 static_cast<double>(sum_of_squares_) / static_cast<double>(sample_size_);
151 return sum_of_squares_by_n - sum_squared_by_n_squared;
152}
153
154template <class Value>
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700155inline void Histogram<Value>::PrintBins(std::ostream& os, const CumulativeData& data) const {
Sameer Abu Asala8439542013-02-14 16:06:42 -0800156 DCHECK_GT(sample_size_, 0ull);
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700157 for (size_t bin_idx = 0; bin_idx < data.freq_.size(); ++bin_idx) {
158 if (bin_idx > 0 && data.perc_[bin_idx] == data.perc_[bin_idx - 1]) {
Sameer Abu Asala8439542013-02-14 16:06:42 -0800159 bin_idx++;
160 continue;
161 }
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700162 os << GetRange(bin_idx) << ": " << data.freq_[bin_idx] << "\t"
163 << data.perc_[bin_idx] * 100.0 << "%\n";
Sameer Abu Asala8439542013-02-14 16:06:42 -0800164 }
165}
166
167template <class Value>
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700168inline void Histogram<Value>::PrintConfidenceIntervals(std::ostream &os, double interval,
169 const CumulativeData& data) const {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700170 static constexpr size_t kFractionalDigits = 3;
Sameer Abu Asala8439542013-02-14 16:06:42 -0800171 DCHECK_GT(interval, 0);
172 DCHECK_LT(interval, 1.0);
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700173 const double per_0 = (1.0 - interval) / 2.0;
174 const double per_1 = per_0 + interval;
175 const TimeUnit unit = GetAppropriateTimeUnit(Mean() * kAdjust);
176 os << Name() << ":\tSum: " << PrettyDuration(Sum() * kAdjust) << " "
177 << (interval * 100) << "% C.I. " << FormatDuration(Percentile(per_0, data) * kAdjust, unit,
178 kFractionalDigits)
179 << "-" << FormatDuration(Percentile(per_1, data) * kAdjust, unit, kFractionalDigits) << " "
180 << "Avg: " << FormatDuration(Mean() * kAdjust, unit, kFractionalDigits) << " Max: "
181 << FormatDuration(Max() * kAdjust, unit, kFractionalDigits) << "\n";
Sameer Abu Asala8439542013-02-14 16:06:42 -0800182}
183
Mathieu Chartierb2f99362013-11-20 17:26:00 -0800184template <class Value>
185inline void Histogram<Value>::CreateHistogram(CumulativeData* out_data) const {
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700186 DCHECK_GT(sample_size_, 0ull);
Ian Rogers500793f2013-11-14 17:49:12 -0800187 out_data->freq_.clear();
188 out_data->perc_.clear();
Sameer Abu Asala8439542013-02-14 16:06:42 -0800189 uint64_t accumulated = 0;
Ian Rogers500793f2013-11-14 17:49:12 -0800190 out_data->freq_.push_back(accumulated);
191 out_data->perc_.push_back(0.0);
Sameer Abu Asala8439542013-02-14 16:06:42 -0800192 for (size_t idx = 0; idx < frequency_.size(); idx++) {
193 accumulated += frequency_[idx];
Ian Rogers500793f2013-11-14 17:49:12 -0800194 out_data->freq_.push_back(accumulated);
195 out_data->perc_.push_back(static_cast<double>(accumulated) / static_cast<double>(sample_size_));
Sameer Abu Asala8439542013-02-14 16:06:42 -0800196 }
Ian Rogers500793f2013-11-14 17:49:12 -0800197 DCHECK_EQ(out_data->freq_.back(), sample_size_);
198 DCHECK_LE(std::abs(out_data->perc_.back() - 1.0), 0.001);
Sameer Abu Asala8439542013-02-14 16:06:42 -0800199}
Sameer Abu Asala8439542013-02-14 16:06:42 -0800200
Ian Rogers647b1a82014-10-10 11:02:11 -0700201#if defined(__clang__)
202#pragma clang diagnostic push
203#pragma clang diagnostic ignored "-Wfloat-equal"
204#endif
205
Sameer Abu Asala8439542013-02-14 16:06:42 -0800206template <class Value>
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700207inline double Histogram<Value>::Percentile(double per, const CumulativeData& data) const {
208 DCHECK_GT(data.perc_.size(), 0ull);
209 size_t upper_idx = 0, lower_idx = 0;
210 for (size_t idx = 0; idx < data.perc_.size(); idx++) {
211 if (per <= data.perc_[idx]) {
Sameer Abu Asalc081e362013-02-20 16:45:38 -0800212 upper_idx = idx;
Sameer Abu Asala8439542013-02-14 16:06:42 -0800213 break;
Sameer Abu Asalc081e362013-02-20 16:45:38 -0800214 }
215
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700216 if (per >= data.perc_[idx] && idx != 0 && data.perc_[idx] != data.perc_[idx - 1]) {
Sameer Abu Asalc081e362013-02-20 16:45:38 -0800217 lower_idx = idx;
218 }
Sameer Abu Asala8439542013-02-14 16:06:42 -0800219 }
Sameer Abu Asalc081e362013-02-20 16:45:38 -0800220
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700221 const double lower_perc = data.perc_[lower_idx];
222 const double lower_value = static_cast<double>(GetRange(lower_idx));
Sameer Abu Asala8439542013-02-14 16:06:42 -0800223 if (per == lower_perc) {
224 return lower_value;
225 }
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700226
227 const double upper_perc = data.perc_[upper_idx];
228 const double upper_value = static_cast<double>(GetRange(upper_idx));
Sameer Abu Asala8439542013-02-14 16:06:42 -0800229 if (per == upper_perc) {
230 return upper_value;
231 }
232 DCHECK_GT(upper_perc, lower_perc);
Sameer Abu Asalc081e362013-02-20 16:45:38 -0800233
Sameer Abu Asala8439542013-02-14 16:06:42 -0800234 double value = lower_value + (upper_value - lower_value) *
235 (per - lower_perc) / (upper_perc - lower_perc);
Sameer Abu Asal857a0782013-02-21 11:00:20 -0800236
237 if (value < min_value_added_) {
238 value = min_value_added_;
239 } else if (value > max_value_added_) {
240 value = max_value_added_;
241 }
242
Sameer Abu Asala8439542013-02-14 16:06:42 -0800243 return value;
244}
245
Ian Rogers647b1a82014-10-10 11:02:11 -0700246#if defined(__clang__)
247#pragma clang diagnostic pop
248#endif
249
Sameer Abu Asalc081e362013-02-20 16:45:38 -0800250} // namespace art
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700251#endif // ART_RUNTIME_BASE_HISTOGRAM_INL_H_
Sameer Abu Asala8439542013-02-14 16:06:42 -0800252