blob: b0a3e660c4049b2b7be5e58717e8779c595661bb [file] [log] [blame]
Elliott Hughes307f75d2011-10-12 18:04:40 -07001/*
2 * Copyright (C) 2011 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#ifndef ART_SRC_TIMING_LOGGER_H_
18#define ART_SRC_TIMING_LOGGER_H_
19
Elliott Hughes07ed66b2012-12-12 18:34:25 -080020#include "base/logging.h"
Elliott Hughes307f75d2011-10-12 18:04:40 -070021#include "utils.h"
22
Mathieu Chartier0325e622012-09-05 14:22:51 -070023#include <cmath>
Elliott Hughes307f75d2011-10-12 18:04:40 -070024#include <stdint.h>
Elliott Hughes307f75d2011-10-12 18:04:40 -070025#include <string>
26#include <vector>
27
28namespace art {
29
Mathieu Chartier0325e622012-09-05 14:22:51 -070030class CumulativeLogger;
31
Elliott Hughes307f75d2011-10-12 18:04:40 -070032class TimingLogger {
Elliott Hughesff17f1f2012-01-24 18:12:29 -080033 public:
Mathieu Chartier2b82db42012-11-14 17:29:05 -080034 explicit TimingLogger(const std::string& name, bool precise = false)
Mathieu Chartier357e9be2012-08-01 11:00:14 -070035 : name_(name), precise_(precise) {
Elliott Hughes307f75d2011-10-12 18:04:40 -070036 AddSplit("");
37 }
38
Mathieu Chartier2b82db42012-11-14 17:29:05 -080039 void Reset() {
40 times_.clear();
41 labels_.clear();
42 AddSplit("");
43 }
44
Elliott Hughes307f75d2011-10-12 18:04:40 -070045 void AddSplit(const std::string& label) {
46 times_.push_back(NanoTime());
47 labels_.push_back(label);
48 }
49
Elliott Hughes73e66f72012-05-09 09:34:45 -070050 void Dump() const {
51 Dump(LOG(INFO));
Elliott Hughes601a1232012-02-02 17:47:38 -080052 }
53
Elliott Hughes73e66f72012-05-09 09:34:45 -070054 void Dump(std::ostream& os) const {
Mathieu Chartier0325e622012-09-05 14:22:51 -070055 uint64_t largest_time = 0;
Elliott Hughes4cb05682012-05-24 19:05:53 -070056 os << name_ << ": begin\n";
Elliott Hughes73e66f72012-05-09 09:34:45 -070057 for (size_t i = 1; i < times_.size(); ++i) {
Mathieu Chartier0325e622012-09-05 14:22:51 -070058 uint64_t delta_time = times_[i] - times_[i - 1];
59 largest_time = std::max(largest_time, delta_time);
60 }
61 // Compute which type of unit we will use for printing the timings.
62 TimeUnit tu = GetAppropriateTimeUnit(largest_time);
63 uint64_t divisor = GetNsToTimeUnitDivisor(tu);
64 for (size_t i = 1; i < times_.size(); ++i) {
65 uint64_t delta_time = times_[i] - times_[i - 1];
Mathieu Chartiere0f0cb32012-08-28 11:26:00 -070066 if (!precise_ && divisor >= 1000) {
Mathieu Chartier0325e622012-09-05 14:22:51 -070067 // Make the fraction 0.
Mathieu Chartiere0f0cb32012-08-28 11:26:00 -070068 delta_time -= delta_time % (divisor / 1000);
Mathieu Chartier357e9be2012-08-01 11:00:14 -070069 }
Mathieu Chartier0325e622012-09-05 14:22:51 -070070 os << name_ << ": " << std::setw(8) << FormatDuration(delta_time, tu) << " " << labels_[i]
71 << "\n";
Elliott Hughes73e66f72012-05-09 09:34:45 -070072 }
Elliott Hughes4cb05682012-05-24 19:05:53 -070073 os << name_ << ": end, " << NsToMs(GetTotalNs()) << " ms\n";
Elliott Hughes73e66f72012-05-09 09:34:45 -070074 }
75
76 uint64_t GetTotalNs() const {
Elliott Hughes601a1232012-02-02 17:47:38 -080077 return times_.back() - times_.front();
Elliott Hughes307f75d2011-10-12 18:04:40 -070078 }
79
Mathieu Chartier0325e622012-09-05 14:22:51 -070080 protected:
Elliott Hughes307f75d2011-10-12 18:04:40 -070081 std::string name_;
Mathieu Chartier357e9be2012-08-01 11:00:14 -070082 bool precise_;
Elliott Hughes307f75d2011-10-12 18:04:40 -070083 std::vector<uint64_t> times_;
84 std::vector<std::string> labels_;
Mathieu Chartier0325e622012-09-05 14:22:51 -070085
86 friend class CumulativeLogger;
87};
88
89class CumulativeLogger {
90 public:
Mathieu Chartier2b82db42012-11-14 17:29:05 -080091 explicit CumulativeLogger(const std::string& name = "", bool precise = false)
Mathieu Chartier0325e622012-09-05 14:22:51 -070092 : name_(name),
Ian Rogers5f5a2c02012-09-17 10:52:08 -070093 precise_(precise) {
94 Reset();
Mathieu Chartier0325e622012-09-05 14:22:51 -070095 }
96
Mathieu Chartier2b82db42012-11-14 17:29:05 -080097 void SetName(const std::string& name) {
98 name_ = name;
99 }
100
Mathieu Chartier0325e622012-09-05 14:22:51 -0700101 void Start() {
102 index_ = 0;
103 last_split_ = NanoTime();
104 }
105
106 void End() {
107 iterations_++;
108 }
109
110 void AddSplit(const std::string& label) {
111 uint64_t cur_time = NanoTime();
112 AddPair(label, cur_time - last_split_);
113 last_split_ = cur_time;
114 }
115
116 void Reset() {
Mathieu Chartier0325e622012-09-05 14:22:51 -0700117 times_.clear();
118 labels_.clear();
119 times_squared_.clear();
Ian Rogers5f5a2c02012-09-17 10:52:08 -0700120 iterations_ = 0;
121 total_time_squared_ = 0;
Mathieu Chartier0325e622012-09-05 14:22:51 -0700122 }
123
124 void AddPair(const std::string& label, uint64_t delta_time) {
125 // Convert delta time to microseconds so that we don't overflow our counters.
126 delta_time /= kAdjust;
127 if (index_ >= times_.size()) {
128 times_.push_back(delta_time);
129 times_squared_.push_back(delta_time * delta_time);
130 labels_.push_back(label);
131 } else {
132 times_[index_] += delta_time;
133 times_squared_[index_] += delta_time * delta_time;
134 DCHECK_EQ(labels_[index_], label);
135 }
136 index_++;
137 }
138
139 void AddLogger(const TimingLogger& logger) {
140 DCHECK_EQ(logger.times_.size(), logger.labels_.size());
141 uint64_t total_time = 0;
142 for (size_t i = 1; i < logger.times_.size(); ++i) {
143 const uint64_t delta_time = logger.times_[i] - logger.times_[i - 1];
144 const std::string& label = logger.labels_[i];
145 AddPair(label, delta_time);
146 total_time += delta_time;
147 }
148 total_time /= kAdjust;
149 total_time_squared_ += total_time * total_time;
150 }
151
152 void Dump() const {
153 Dump(LOG(INFO));
154 }
155
156 void Dump(std::ostream& os) const {
157 os << name_ << ": iterations " << iterations_ << " begin\n";
158 //Find which unit we will use for the timing logger.
159 uint64_t largest_mean = 0;
160 for (size_t i = 0; i < times_.size(); ++i) {
161 // Convert back to nanoseconds from microseconds.
162 uint64_t mean = times_[i] / iterations_;
163 largest_mean = std::max(largest_mean, mean);
164 }
165 // Convert largest mean back to ns
166 TimeUnit tu = GetAppropriateTimeUnit(largest_mean * kAdjust);
167 uint64_t divisor = GetNsToTimeUnitDivisor(tu);
168 for (size_t i = 0; i < times_.size(); ++i) {
169 uint64_t mean_x2 = times_squared_[i] / iterations_;
170 uint64_t mean = times_[i] / iterations_;
171 uint64_t variance = mean_x2 - (mean * mean);
172 uint64_t std_dev = static_cast<uint64_t>(std::sqrt(static_cast<double>(variance)));
Mathieu Chartiere0f0cb32012-08-28 11:26:00 -0700173 if (!precise_ && divisor >= 1000) {
Mathieu Chartier0325e622012-09-05 14:22:51 -0700174 // Make the fraction 0.
Mathieu Chartiere0f0cb32012-08-28 11:26:00 -0700175 mean -= mean % (divisor / 1000);
176 std_dev -= std_dev % (divisor / 1000);
Mathieu Chartier0325e622012-09-05 14:22:51 -0700177 }
178 os << name_ << ": " << std::setw(8)
179 << FormatDuration(mean * kAdjust, tu) << " std_dev "
180 << FormatDuration(std_dev * kAdjust, tu) << " " << labels_[i] << "\n";
181 }
182 uint64_t total_mean_x2 = total_time_squared_;
Mathieu Chartier155dfe92012-10-09 14:24:49 -0700183 uint64_t mean_total_ns = GetTotalTime();
Mathieu Chartier0325e622012-09-05 14:22:51 -0700184 if (iterations_ != 0) {
185 total_mean_x2 /= iterations_;
186 mean_total_ns /= iterations_;
187 }
188 uint64_t total_variance = total_mean_x2 - (mean_total_ns * mean_total_ns);
189 uint64_t total_std_dev = static_cast<uint64_t>(
190 std::sqrt(static_cast<double>(total_variance)));
191 os << name_ << ": end, mean " << PrettyDuration(mean_total_ns * kAdjust)
192 << " std_dev " << PrettyDuration(total_std_dev * kAdjust) << "\n";
193 }
194
195 uint64_t GetTotalNs() const {
Mathieu Chartier155dfe92012-10-09 14:24:49 -0700196 return GetTotalTime() * kAdjust;
197 }
198
199 private:
200
201 uint64_t GetTotalTime() const {
Mathieu Chartier0325e622012-09-05 14:22:51 -0700202 uint64_t total = 0;
203 for (size_t i = 0; i < times_.size(); ++i) {
204 total += times_[i];
205 }
206 return total;
207 }
208
Mathieu Chartier0325e622012-09-05 14:22:51 -0700209 static const uint64_t kAdjust = 1000;
210 std::string name_;
211 bool precise_;
212 uint64_t total_time_squared_;
213 std::vector<uint64_t> times_;
214 std::vector<uint64_t> times_squared_;
215 std::vector<std::string> labels_;
216 size_t index_;
217 size_t iterations_;
218 uint64_t last_split_;
Elliott Hughes307f75d2011-10-12 18:04:40 -0700219};
220
221} // namespace art
222
223#endif // ART_SRC_TIMING_LOGGER_H_