blob: c7cbbe504f1d55265df67f9b90c28fd049e60783 [file] [log] [blame]
Sameer Abu Asala8439542013-02-14 16:06:42 -08001/*
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#include "timing_logger.h"
18
19#include "base/logging.h"
20#include "thread.h"
21#include "base/stl_util.h"
22#include "base/histogram-inl.h"
23
24#include <cmath>
25#include <iomanip>
26
27namespace art {
28
29void TimingLogger::Reset() {
30 times_.clear();
31 labels_.clear();
32 AddSplit("");
33}
34
35TimingLogger::TimingLogger(const std::string &name, bool precise)
36 : name_(name),
37 precise_(precise) {
38 AddSplit("");
39}
40
41void TimingLogger::AddSplit(const std::string &label) {
42 times_.push_back(NanoTime());
43 labels_.push_back(label);
44}
45
46uint64_t TimingLogger::GetTotalNs() const {
47 return times_.back() - times_.front();
48}
49;
50
51void TimingLogger::Dump(std::ostream &os) const {
52 uint64_t largest_time = 0;
53 os << name_ << ": begin\n";
54 for (size_t i = 1; i < times_.size(); ++i) {
55 uint64_t delta_time = times_[i] - times_[i - 1];
56 largest_time = std::max(largest_time, delta_time);
57 }
58 // Compute which type of unit we will use for printing the timings.
59 TimeUnit tu = GetAppropriateTimeUnit(largest_time);
60 uint64_t divisor = GetNsToTimeUnitDivisor(tu);
61 for (size_t i = 1; i < times_.size(); ++i) {
62 uint64_t delta_time = times_[i] - times_[i - 1];
63 if (!precise_ && divisor >= 1000) {
64 // Make the fraction 0.
65 delta_time -= delta_time % (divisor / 1000);
66 }
67 os << name_ << ": " << std::setw(8) << FormatDuration(delta_time, tu) << " "
68 << labels_[i] << "\n";
69 }
70 os << name_ << ": end, " << NsToMs(GetTotalNs()) << " ms\n";
71}
72
Ian Rogers45357052013-04-18 20:49:43 -070073CumulativeLogger::CumulativeLogger(const std::string& name)
Sameer Abu Asala8439542013-02-14 16:06:42 -080074 : name_(name),
Ian Rogers45357052013-04-18 20:49:43 -070075 lock_name_("CumulativeLoggerLock" + name),
76 lock_(lock_name_.c_str(), kDefaultMutexLevel, true) {
Sameer Abu Asala8439542013-02-14 16:06:42 -080077 Reset();
78}
79
Ian Rogers45357052013-04-18 20:49:43 -070080CumulativeLogger::~CumulativeLogger() {
81 STLDeleteElements(&histograms_);
82}
Sameer Abu Asala8439542013-02-14 16:06:42 -080083
Ian Rogers45357052013-04-18 20:49:43 -070084void CumulativeLogger::SetName(const std::string& name) {
Ian Rogers1d54e732013-05-02 21:10:01 -070085 name_.assign(name);
Ian Rogers45357052013-04-18 20:49:43 -070086}
Sameer Abu Asala8439542013-02-14 16:06:42 -080087
88void CumulativeLogger::Start() {
89 MutexLock mu(Thread::Current(), lock_);
90 index_ = 0;
91}
92
93void CumulativeLogger::End() {
94 MutexLock mu(Thread::Current(), lock_);
95 iterations_++;
96}
97void CumulativeLogger::Reset() {
98 MutexLock mu(Thread::Current(), lock_);
99 iterations_ = 0;
100 STLDeleteElements(&histograms_);
101}
102
103uint64_t CumulativeLogger::GetTotalNs() const {
104 return GetTotalTime() * kAdjust;
105}
106
107uint64_t CumulativeLogger::GetTotalTime() const {
108 MutexLock mu(Thread::Current(), lock_);
109 uint64_t total = 0;
110 for (size_t i = 0; i < histograms_.size(); ++i) {
111 total += histograms_[i]->Sum();
112 }
113 return total;
114}
115
116void CumulativeLogger::AddLogger(const TimingLogger &logger) {
117 MutexLock mu(Thread::Current(), lock_);
118 DCHECK_EQ(logger.times_.size(), logger.labels_.size());
119 for (size_t i = 1; i < logger.times_.size(); ++i) {
120 const uint64_t delta_time = logger.times_[i] - logger.times_[i - 1];
121 const std::string &label = logger.labels_[i];
122 AddPair(label, delta_time);
123 }
124}
125
Ian Rogers1d54e732013-05-02 21:10:01 -0700126void CumulativeLogger::AddNewLogger(const base::NewTimingLogger &logger) {
127 MutexLock mu(Thread::Current(), lock_);
128 const std::vector<std::pair<uint64_t, const char*> >& splits = logger.GetSplits();
129 typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
130 if (kIsDebugBuild && splits.size() != histograms_.size()) {
131 LOG(ERROR) << "Mismatch in splits.";
132 typedef std::vector<Histogram<uint64_t> *>::const_iterator It2;
133 It it = splits.begin();
134 It2 it2 = histograms_.begin();
135 while ((it != splits.end()) && (it2 != histograms_.end())) {
136 if (it != splits.end()) {
137 LOG(ERROR) << "\tsplit: " << it->second;
138 ++it;
139 }
140 if (it2 != histograms_.end()) {
141 LOG(ERROR) << "\tpreviously record: " << (*it2)->Name();
142 ++it2;
143 }
144 }
145 }
146 for (It it = splits.begin(), end = splits.end(); it != end; ++it) {
147 std::pair<uint64_t, const char*> split = *it;
148 uint64_t split_time = split.first;
149 const char* split_name = split.second;
150 AddPair(split_name, split_time);
151 }
152}
153
Sameer Abu Asala8439542013-02-14 16:06:42 -0800154void CumulativeLogger::Dump(std::ostream &os) {
155 MutexLock mu(Thread::Current(), lock_);
156 DumpHistogram(os);
157}
158
159void CumulativeLogger::AddPair(const std::string &label, uint64_t delta_time) {
Sameer Abu Asala8439542013-02-14 16:06:42 -0800160 // Convert delta time to microseconds so that we don't overflow our counters.
161 delta_time /= kAdjust;
162 if (index_ >= histograms_.size()) {
163 Histogram<uint64_t> *tmp_hist = new Histogram<uint64_t>(label);
164 tmp_hist->AddValue(delta_time);
165 histograms_.push_back(tmp_hist);
166 } else {
167 histograms_[index_]->AddValue(delta_time);
168 DCHECK_EQ(label, histograms_[index_]->Name());
169 }
170 index_++;
171}
172
173void CumulativeLogger::DumpHistogram(std::ostream &os) {
174 os << "Start Dumping histograms for " << iterations_ << " iterations"
175 << " for " << name_ << "\n";
176 for (size_t Idx = 0; Idx < histograms_.size(); Idx++) {
177 Histogram<uint64_t> &hist = *(histograms_[Idx]);
178 hist.CreateHistogram();
179 hist.PrintConfidenceIntervals(os, 0.99);
180 }
181 os << "Done Dumping histograms \n";
182}
183
Ian Rogers1d54e732013-05-02 21:10:01 -0700184
185namespace base {
186
187NewTimingLogger::NewTimingLogger(const char* name, bool precise, bool verbose)
188 : name_(name), precise_(precise), verbose_(verbose),
189 current_split_(NULL), current_split_start_ns_(0) {
190}
191
192void NewTimingLogger::Reset() {
193 current_split_ = NULL;
194 current_split_start_ns_ = 0;
195 splits_.clear();
196}
197
198void NewTimingLogger::StartSplit(const char* new_split_label) {
199 DCHECK(current_split_ == NULL);
200 if (verbose_) {
201 LOG(INFO) << "Begin: " << new_split_label;
202 }
203 current_split_ = new_split_label;
204 current_split_start_ns_ = NanoTime();
205}
206
207// Ends the current split and starts the one given by the label.
208void NewTimingLogger::NewSplit(const char* new_split_label) {
209 DCHECK(current_split_ != NULL);
210 uint64_t current_time = NanoTime();
211 uint64_t split_time = current_time - current_split_start_ns_;
212 splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
213 if (verbose_) {
214 LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time) << "\n"
215 << "Begin: " << new_split_label;
216 }
217 current_split_ = new_split_label;
218 current_split_start_ns_ = current_time;
219}
220
221void NewTimingLogger::EndSplit() {
222 DCHECK(current_split_ != NULL);
223 uint64_t current_time = NanoTime();
224 uint64_t split_time = current_time - current_split_start_ns_;
225 if (verbose_) {
226 LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time);
227 }
228 splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
229}
230
231uint64_t NewTimingLogger::GetTotalNs() const {
232 uint64_t total_ns = 0;
233 typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
234 for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
235 std::pair<uint64_t, const char*> split = *it;
236 total_ns += split.first;
237 }
238 return total_ns;
239}
240
241void NewTimingLogger::Dump(std::ostream &os) const {
242 uint64_t longest_split = 0;
243 uint64_t total_ns = 0;
244 typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
245 for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
246 std::pair<uint64_t, const char*> split = *it;
247 uint64_t split_time = split.first;
248 longest_split = std::max(longest_split, split_time);
249 total_ns += split_time;
250 }
251 // Compute which type of unit we will use for printing the timings.
252 TimeUnit tu = GetAppropriateTimeUnit(longest_split);
253 uint64_t divisor = GetNsToTimeUnitDivisor(tu);
254 // Print formatted splits.
255 for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
256 std::pair<uint64_t, const char*> split = *it;
257 uint64_t split_time = split.first;
258 if (!precise_ && divisor >= 1000) {
259 // Make the fractional part 0.
260 split_time -= split_time % (divisor / 1000);
261 }
262 os << name_ << ": " << std::setw(8) << FormatDuration(split_time, tu) << " "
263 << split.second << "\n";
264 }
265 os << name_ << ": end, " << NsToMs(total_ns) << " ms\n";
266}
267
268} // namespace base
Sameer Abu Asala8439542013-02-14 16:06:42 -0800269} // namespace art