1 /*
2 * Copyright 2018 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
17 #include "histogram.h"
18
19 #include <sstream>
20 #include <cmath>
21
22 #define LOG_TAG "TuningFork"
23 #include "Log.h"
24
25 #include "clearcutserializer.h"
26
27 namespace tuningfork {
28
Histogram(float start_ms,float end_ms,int num_buckets_between)29 Histogram::Histogram(float start_ms, float end_ms, int num_buckets_between)
30 : start_ms_(start_ms), end_ms_(end_ms),
31 bucket_dt_ms_((end_ms_ - start_ms_) / num_buckets_between),
32 num_buckets_(num_buckets_between + 2),
33 buckets_(num_buckets_), auto_range_(start_ms_ == 0 && end_ms_ == 0), count_(0) {
34 std::fill(buckets_.begin(), buckets_.end(), 0);
35 if (auto_range_)
36 samples_.reserve(num_buckets_);
37 else if (bucket_dt_ms_ <= 0)
38 ALOGE("Histogram end needs to be larger than histogram begin");
39 }
40
Histogram(const Settings::Histogram & hs)41 Histogram::Histogram(const Settings::Histogram &hs)
42 : Histogram(hs.bucket_min, hs.bucket_max, hs.n_buckets) {
43 }
44
Add(Sample dt_ms)45 void Histogram::Add(Sample dt_ms) {
46 if (auto_range_) {
47 samples_.push_back(dt_ms);
48 if (samples_.size() == samples_.capacity()) {
49 CalcBucketsFromSamples();
50 }
51 } else {
52 int i = (dt_ms - start_ms_) / bucket_dt_ms_;
53 if (i < 0)
54 buckets_[0]++;
55 else if (i + 1 >= num_buckets_)
56 buckets_[num_buckets_ - 1]++;
57 else
58 buckets_[i + 1]++;
59 ++count_;
60 }
61 }
62
CalcBucketsFromSamples()63 void Histogram::CalcBucketsFromSamples() {
64 Sample min_dt = std::numeric_limits<Sample>::max();
65 Sample max_dt = std::numeric_limits<Sample>::min();
66 Sample sum = 0;
67 Sample sum2 = 0;
68 for (Sample d: samples_) {
69 if (d < min_dt) min_dt = d;
70 if (d > max_dt) max_dt = d;
71 sum += d;
72 sum2 += d * d;
73 }
74 size_t n = samples_.size();
75 Sample mean = sum / n;
76 Sample var = sum2 / n - mean * mean;
77 if (var < 0) var = 0; // Can be negative due to rounding errors
78 Sample stddev = sqrt(var);
79 start_ms_ = std::max(mean - kAutoSizeNumStdDev * stddev, 0.0);
80 end_ms_ = mean + kAutoSizeNumStdDev * stddev;
81 bucket_dt_ms_ = (end_ms_ - start_ms_) / (num_buckets_ - 2);
82 if (bucket_dt_ms_ < kAutoSizeMinBucketSizeMs) {
83 bucket_dt_ms_ = kAutoSizeMinBucketSizeMs;
84 Sample w = bucket_dt_ms_ * (num_buckets_ - 2);
85 start_ms_ = mean - w / 2;
86 end_ms_ = mean + w / 2;
87 }
88 auto_range_ = false;
89 for (Sample d: samples_) {
90 Add(d);
91 }
92 }
93
ToJSON() const94 std::string Histogram::ToJSON() const {
95 std::stringstream str;
96 str.precision(2);
97 str << std::fixed;
98 if (auto_range_) {
99 str << "{\"pmax\":[],\"cnts\":[]}";
100 } else {
101 str << "{\"pmax\":[";
102 Sample x = start_ms_;
103 for (int i = 0; i < num_buckets_ - 1; ++i) {
104 str << x << ",";
105 x += bucket_dt_ms_;
106 }
107 str << "99999],\"cnts\":[";
108 for (int i = 0; i < num_buckets_ - 1; ++i) {
109 str << buckets_[i] << ",";
110 }
111 if (num_buckets_ > 0)
112 str << buckets_.back();
113 str << "]}";
114 }
115 return str.str();
116 }
117
Clear(bool autorange)118 void Histogram::Clear(bool autorange) {
119 std::fill(buckets_.begin(), buckets_.end(), 0);
120 samples_.clear();
121 auto_range_ = autorange;
122 count_ = 0;
123 }
124
125 } // namespace tuningfork
126