blob: e2d2d4c8ef51dda19147b30b62f95ee866cb5ce4 [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
Anwar Ghuloum6f28d912013-07-24 15:02:53 -070017
18#define ATRACE_TAG ATRACE_TAG_DALVIK
19#include <stdio.h>
20#include <cutils/trace.h>
21
Sameer Abu Asala8439542013-02-14 16:06:42 -080022#include "timing_logger.h"
23
24#include "base/logging.h"
25#include "thread.h"
26#include "base/stl_util.h"
27#include "base/histogram-inl.h"
28
29#include <cmath>
30#include <iomanip>
31
32namespace art {
33
Ian Rogers45357052013-04-18 20:49:43 -070034CumulativeLogger::CumulativeLogger(const std::string& name)
Sameer Abu Asala8439542013-02-14 16:06:42 -080035 : name_(name),
Ian Rogers45357052013-04-18 20:49:43 -070036 lock_name_("CumulativeLoggerLock" + name),
37 lock_(lock_name_.c_str(), kDefaultMutexLevel, true) {
Sameer Abu Asala8439542013-02-14 16:06:42 -080038 Reset();
39}
40
Ian Rogers45357052013-04-18 20:49:43 -070041CumulativeLogger::~CumulativeLogger() {
42 STLDeleteElements(&histograms_);
43}
Sameer Abu Asala8439542013-02-14 16:06:42 -080044
Ian Rogers45357052013-04-18 20:49:43 -070045void CumulativeLogger::SetName(const std::string& name) {
Ian Rogers1d54e732013-05-02 21:10:01 -070046 name_.assign(name);
Ian Rogers45357052013-04-18 20:49:43 -070047}
Sameer Abu Asala8439542013-02-14 16:06:42 -080048
49void CumulativeLogger::Start() {
50 MutexLock mu(Thread::Current(), lock_);
51 index_ = 0;
52}
53
54void CumulativeLogger::End() {
55 MutexLock mu(Thread::Current(), lock_);
56 iterations_++;
57}
58void CumulativeLogger::Reset() {
59 MutexLock mu(Thread::Current(), lock_);
60 iterations_ = 0;
61 STLDeleteElements(&histograms_);
62}
63
64uint64_t CumulativeLogger::GetTotalNs() const {
65 return GetTotalTime() * kAdjust;
66}
67
68uint64_t CumulativeLogger::GetTotalTime() const {
69 MutexLock mu(Thread::Current(), lock_);
70 uint64_t total = 0;
71 for (size_t i = 0; i < histograms_.size(); ++i) {
72 total += histograms_[i]->Sum();
73 }
74 return total;
75}
76
Sameer Abu Asala8439542013-02-14 16:06:42 -080077
Anwar Ghuloum6f28d912013-07-24 15:02:53 -070078void CumulativeLogger::AddLogger(const base::TimingLogger &logger) {
Ian Rogers1d54e732013-05-02 21:10:01 -070079 MutexLock mu(Thread::Current(), lock_);
80 const std::vector<std::pair<uint64_t, const char*> >& splits = logger.GetSplits();
81 typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
Mathieu Chartiere5426c92013-08-01 13:55:42 -070082 // The first time this is run, the histograms array will be empty.
83 if (kIsDebugBuild && !histograms_.empty() && splits.size() != histograms_.size()) {
Ian Rogers1d54e732013-05-02 21:10:01 -070084 LOG(ERROR) << "Mismatch in splits.";
85 typedef std::vector<Histogram<uint64_t> *>::const_iterator It2;
86 It it = splits.begin();
87 It2 it2 = histograms_.begin();
88 while ((it != splits.end()) && (it2 != histograms_.end())) {
89 if (it != splits.end()) {
90 LOG(ERROR) << "\tsplit: " << it->second;
91 ++it;
92 }
93 if (it2 != histograms_.end()) {
94 LOG(ERROR) << "\tpreviously record: " << (*it2)->Name();
95 ++it2;
96 }
97 }
98 }
99 for (It it = splits.begin(), end = splits.end(); it != end; ++it) {
100 std::pair<uint64_t, const char*> split = *it;
101 uint64_t split_time = split.first;
102 const char* split_name = split.second;
103 AddPair(split_name, split_time);
104 }
105}
106
Sameer Abu Asala8439542013-02-14 16:06:42 -0800107void CumulativeLogger::Dump(std::ostream &os) {
108 MutexLock mu(Thread::Current(), lock_);
109 DumpHistogram(os);
110}
111
112void CumulativeLogger::AddPair(const std::string &label, uint64_t delta_time) {
Sameer Abu Asala8439542013-02-14 16:06:42 -0800113 // Convert delta time to microseconds so that we don't overflow our counters.
114 delta_time /= kAdjust;
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700115 if (histograms_.size() <= index_) {
116 histograms_.push_back(new Histogram<uint64_t>(label.c_str(), 50));
117 DCHECK_GT(histograms_.size(), index_);
Sameer Abu Asala8439542013-02-14 16:06:42 -0800118 }
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700119 histograms_[index_]->AddValue(delta_time);
120 DCHECK_EQ(label, histograms_[index_]->Name());
121 ++index_;
Sameer Abu Asala8439542013-02-14 16:06:42 -0800122}
123
124void CumulativeLogger::DumpHistogram(std::ostream &os) {
125 os << "Start Dumping histograms for " << iterations_ << " iterations"
126 << " for " << name_ << "\n";
127 for (size_t Idx = 0; Idx < histograms_.size(); Idx++) {
Mathieu Chartiere5426c92013-08-01 13:55:42 -0700128 Histogram<uint64_t>::CumulativeData cumulative_data;
129 histograms_[Idx]->CreateHistogram(cumulative_data);
130 histograms_[Idx]->PrintConfidenceIntervals(os, 0.99, cumulative_data);
131 // Reset cumulative values to save memory. We don't expect DumpHistogram to be called often, so
132 // it is not performance critical.
Sameer Abu Asala8439542013-02-14 16:06:42 -0800133 }
134 os << "Done Dumping histograms \n";
135}
136
Ian Rogers1d54e732013-05-02 21:10:01 -0700137
138namespace base {
139
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700140TimingLogger::TimingLogger(const char* name, bool precise, bool verbose)
Ian Rogers1d54e732013-05-02 21:10:01 -0700141 : name_(name), precise_(precise), verbose_(verbose),
142 current_split_(NULL), current_split_start_ns_(0) {
143}
144
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700145void TimingLogger::Reset() {
Ian Rogers1d54e732013-05-02 21:10:01 -0700146 current_split_ = NULL;
147 current_split_start_ns_ = 0;
148 splits_.clear();
149}
150
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700151void TimingLogger::StartSplit(const char* new_split_label) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700152 DCHECK(current_split_ == NULL);
153 if (verbose_) {
154 LOG(INFO) << "Begin: " << new_split_label;
155 }
156 current_split_ = new_split_label;
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700157 ATRACE_BEGIN(current_split_);
Ian Rogers1d54e732013-05-02 21:10:01 -0700158 current_split_start_ns_ = NanoTime();
159}
160
161// Ends the current split and starts the one given by the label.
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700162void TimingLogger::NewSplit(const char* new_split_label) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700163 DCHECK(current_split_ != NULL);
164 uint64_t current_time = NanoTime();
165 uint64_t split_time = current_time - current_split_start_ns_;
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700166 ATRACE_END();
Ian Rogers1d54e732013-05-02 21:10:01 -0700167 splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
168 if (verbose_) {
169 LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time) << "\n"
170 << "Begin: " << new_split_label;
171 }
172 current_split_ = new_split_label;
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700173 ATRACE_BEGIN(current_split_);
Ian Rogers1d54e732013-05-02 21:10:01 -0700174 current_split_start_ns_ = current_time;
175}
176
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700177void TimingLogger::EndSplit() {
Ian Rogers1d54e732013-05-02 21:10:01 -0700178 DCHECK(current_split_ != NULL);
179 uint64_t current_time = NanoTime();
180 uint64_t split_time = current_time - current_split_start_ns_;
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700181 ATRACE_END();
Ian Rogers1d54e732013-05-02 21:10:01 -0700182 if (verbose_) {
183 LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time);
184 }
185 splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
186}
187
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700188uint64_t TimingLogger::GetTotalNs() const {
Ian Rogers1d54e732013-05-02 21:10:01 -0700189 uint64_t total_ns = 0;
190 typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
191 for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
192 std::pair<uint64_t, const char*> split = *it;
193 total_ns += split.first;
194 }
195 return total_ns;
196}
197
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700198void TimingLogger::Dump(std::ostream &os) const {
Ian Rogers1d54e732013-05-02 21:10:01 -0700199 uint64_t longest_split = 0;
200 uint64_t total_ns = 0;
201 typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
202 for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
203 std::pair<uint64_t, const char*> split = *it;
204 uint64_t split_time = split.first;
205 longest_split = std::max(longest_split, split_time);
206 total_ns += split_time;
207 }
208 // Compute which type of unit we will use for printing the timings.
209 TimeUnit tu = GetAppropriateTimeUnit(longest_split);
210 uint64_t divisor = GetNsToTimeUnitDivisor(tu);
211 // Print formatted splits.
212 for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
213 std::pair<uint64_t, const char*> split = *it;
214 uint64_t split_time = split.first;
215 if (!precise_ && divisor >= 1000) {
216 // Make the fractional part 0.
217 split_time -= split_time % (divisor / 1000);
218 }
219 os << name_ << ": " << std::setw(8) << FormatDuration(split_time, tu) << " "
220 << split.second << "\n";
221 }
222 os << name_ << ": end, " << NsToMs(total_ns) << " ms\n";
223}
224
225} // namespace base
Sameer Abu Asala8439542013-02-14 16:06:42 -0800226} // namespace art