blob: e91a5110d3239a2d614c1eec21696c1d6281fdb5 [file] [log] [blame]
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -07001/*
2 * Copyright (C) 2017 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
18#define LOG_TAG "PerformanceAnalysis"
19// #define LOG_NDEBUG 0
Eric Tane98dd6f2018-08-22 18:23:50 -070020// #define WRITE_TO_FILE
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070021
22#include <algorithm>
23#include <climits>
24#include <deque>
Eric Tancfa7c4b2018-09-17 09:46:07 -070025#include <iomanip>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070026#include <math.h>
27#include <numeric>
Eric Tane98dd6f2018-08-22 18:23:50 -070028#include <sstream>
29#include <string>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070030#include <vector>
31#include <stdarg.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <string.h>
35#include <sys/prctl.h>
36#include <time.h>
37#include <new>
Eric Tan39ec8d62018-07-24 09:49:29 -070038#include <audio_utils/LogPlot.h>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070039#include <audio_utils/roundup.h>
Glenn Kasten8589ce72017-09-08 17:03:42 -070040#include <media/nblog/NBLog.h>
41#include <media/nblog/PerformanceAnalysis.h>
42#include <media/nblog/ReportPerformance.h>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070043#include <utils/Log.h>
44#include <utils/String8.h>
Eric Tanfefe3162018-09-07 10:09:11 -070045#include <utils/Timers.h>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070046
47#include <queue>
48#include <utility>
49
50namespace android {
Eric Tand6eee712018-09-07 10:58:19 -070051namespace ReportPerformance {
52
Eric Tane98dd6f2018-08-22 18:23:50 -070053void Histogram::add(double value)
54{
Eric Tancfa7c4b2018-09-17 09:46:07 -070055 if (mBinSize <= 0 || mBins.size() < 2) {
56 return;
Eric Tane98dd6f2018-08-22 18:23:50 -070057 }
Eric Tancfa7c4b2018-09-17 09:46:07 -070058 // TODO Handle domain and range error exceptions?
59 const int unboundedIndex = lround((value - mLow) / mBinSize) + 1;
60 // std::clamp is introduced in C++17
61 //const int index = std::clamp(unboundedIndex, 0, (int)(mBins.size() - 1));
62 const int index = std::max(0, std::min((int)(mBins.size() - 1), unboundedIndex));
63 mBins[index]++;
Eric Tane98dd6f2018-08-22 18:23:50 -070064 mTotalCount++;
65}
66
67void Histogram::clear()
68{
69 std::fill(mBins.begin(), mBins.end(), 0);
Eric Tane98dd6f2018-08-22 18:23:50 -070070 mTotalCount = 0;
71}
72
73uint64_t Histogram::totalCount() const
74{
75 return mTotalCount;
76}
77
Eric Tanfefe3162018-09-07 10:09:11 -070078std::string Histogram::toString() const {
Eric Tane98dd6f2018-08-22 18:23:50 -070079 std::stringstream ss;
80 static constexpr char kDivider = '|';
Eric Tan24ee2da2018-09-13 10:53:17 -070081 ss << kVersion << "," << mBinSize << "," << mNumBins << "," << mLow << ",{";
Eric Tane98dd6f2018-08-22 18:23:50 -070082 bool first = true;
Eric Tancfa7c4b2018-09-17 09:46:07 -070083 for (size_t i = 0; i < mBins.size(); i++) {
Eric Tane98dd6f2018-08-22 18:23:50 -070084 if (mBins[i] != 0) {
85 if (!first) {
86 ss << ",";
87 }
Eric Tancfa7c4b2018-09-17 09:46:07 -070088 ss << static_cast<int>(i) - 1 << kDivider << mBins[i];
Eric Tane98dd6f2018-08-22 18:23:50 -070089 first = false;
90 }
91 }
Eric Tane98dd6f2018-08-22 18:23:50 -070092 ss << "}";
93
94 return ss.str();
95}
96
Eric Tancfa7c4b2018-09-17 09:46:07 -070097std::string Histogram::asciiArtString(size_t indent) const {
98 if (totalCount() == 0 || mBinSize <= 0 || mBins.size() < 2) {
99 return "";
100 }
101
102 static constexpr char kMarker = '-';
103 // One increment is considered one step of a bin's height.
104 static constexpr size_t kMarkersPerIncrement = 2;
105 static constexpr size_t kMaxIncrements = 64 + 1;
106 static constexpr size_t kMaxNumberWidth = 7;
107 static const std::string kMarkers(kMarkersPerIncrement * kMaxIncrements, kMarker);
108 static const std::string kSpaces(kMarkersPerIncrement * kMaxIncrements, ' ');
109 // get the last n characters of s, or the whole string if it is shorter
110 auto getTail = [](const size_t n, const std::string &s) {
111 return s.c_str() + s.size() - std::min(n, s.size());
112 };
113
114 // Since totalCount() > 0, mBins is not empty and maxCount > 0.
115 const unsigned maxCount = *std::max_element(mBins.begin(), mBins.end());
116 const size_t maxIncrements = log2(maxCount) + 1;
117
118 std::stringstream ss;
119
120 // Non-zero bins must exist at this point because totalCount() > 0.
121 size_t firstNonZeroBin = 0;
122 // If firstNonZeroBin reaches mBins.size() - 1, then it must be a nonzero bin.
123 for (; firstNonZeroBin < mBins.size() - 1 && mBins[firstNonZeroBin] == 0; firstNonZeroBin++) {}
124 const size_t firstBinToPrint = firstNonZeroBin == 0 ? 0 : firstNonZeroBin - 1;
125
126 size_t lastNonZeroBin = mBins.size() - 1;
127 // If lastNonZeroBin reaches 0, then it must be a nonzero bin.
128 for (; lastNonZeroBin > 0 && mBins[lastNonZeroBin] == 0; lastNonZeroBin--) {}
129 const size_t lastBinToPrint = lastNonZeroBin == mBins.size() - 1 ? lastNonZeroBin
130 : lastNonZeroBin + 1;
131
132 for (size_t bin = firstBinToPrint; bin <= lastBinToPrint; bin++) {
133 ss << std::setw(indent + kMaxNumberWidth);
134 if (bin == 0) {
135 ss << "<";
136 } else if (bin == mBins.size() - 1) {
137 ss << ">";
138 } else {
139 ss << mLow + (bin - 1) * mBinSize;
140 }
141 ss << " |";
142 size_t increments = 0;
143 const uint64_t binCount = mBins[bin];
144 if (binCount > 0) {
145 increments = log2(binCount) + 1;
146 ss << getTail(increments * kMarkersPerIncrement, kMarkers);
147 }
148 ss << getTail((maxIncrements - increments + 1) * kMarkersPerIncrement, kSpaces)
149 << binCount << "\n";
150 }
151 ss << "\n";
152
153 return ss.str();
154}
155
Eric Tane98dd6f2018-08-22 18:23:50 -0700156//------------------------------------------------------------------------------
157
Sanna Catherine de Treville Wager14316442017-08-11 10:45:29 -0700158// Given an audio processing wakeup timestamp, buckets the time interval
159// since the previous timestamp into a histogram, searches for
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700160// outliers, analyzes the outlier series for unexpectedly
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700161// small or large values and stores these as peaks
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700162void PerformanceAnalysis::logTsEntry(timestamp ts) {
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700163 // after a state change, start a new series and do not
164 // record time intervals in-between
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700165 if (mBufferPeriod.mPrevTs == 0) {
166 mBufferPeriod.mPrevTs = ts;
Sanna Catherine de Treville Wagera80649a2017-07-21 16:16:38 -0700167 return;
168 }
169
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700170 // calculate time interval between current and previous timestamp
171 const msInterval diffMs = static_cast<msInterval>(
172 deltaMs(mBufferPeriod.mPrevTs, ts));
173
174 const int diffJiffy = deltaJiffy(mBufferPeriod.mPrevTs, ts);
175
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700176 // old versus new weight ratio when updating the buffer period mean
177 static constexpr double exponentialWeight = 0.999;
178 // update buffer period mean with exponential weighting
179 mBufferPeriod.mMean = (mBufferPeriod.mMean < 0) ? diffMs :
180 exponentialWeight * mBufferPeriod.mMean + (1.0 - exponentialWeight) * diffMs;
181 // set mOutlierFactor to a smaller value for the fastmixer thread
182 const int kFastMixerMax = 10;
183 // NormalMixer times vary much more than FastMixer times.
184 // TODO: mOutlierFactor values are set empirically based on what appears to be
185 // an outlier. Learn these values from the data.
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700186 mBufferPeriod.mOutlierFactor = mBufferPeriod.mMean < kFastMixerMax ? 1.8 : 2.0;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700187 // set outlier threshold
188 mBufferPeriod.mOutlier = mBufferPeriod.mMean * mBufferPeriod.mOutlierFactor;
189
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700190 // Check whether the time interval between the current timestamp
191 // and the previous one is long enough to count as an outlier
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700192 const bool isOutlier = detectAndStoreOutlier(diffMs);
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700193 // If an outlier was found, check whether it was a peak
194 if (isOutlier) {
195 /*bool isPeak =*/ detectAndStorePeak(
196 mOutlierData[0].first, mOutlierData[0].second);
197 // TODO: decide whether to insert a new empty histogram if a peak
198 // TODO: remove isPeak if unused to avoid "unused variable" error
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700199 // occurred at the current timestamp
Sanna Catherine de Treville Wagera80649a2017-07-21 16:16:38 -0700200 }
201
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700202 // Insert a histogram to mHists if it is empty, or
203 // close the current histogram and insert a new empty one if
204 // if the current histogram has spanned its maximum time interval.
205 if (mHists.empty() ||
206 deltaMs(mHists[0].first, ts) >= kMaxLength.HistTimespanMs) {
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700207 mHists.emplace_front(ts, std::map<int, int>());
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700208 // When memory is full, delete oldest histogram
209 // TODO: use a circular buffer
210 if (mHists.size() >= kMaxLength.Hists) {
211 mHists.resize(kMaxLength.Hists);
212 }
213 }
214 // add current time intervals to histogram
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700215 ++mHists[0].second[diffJiffy];
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700216 // update previous timestamp
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700217 mBufferPeriod.mPrevTs = ts;
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700218}
219
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700220
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700221// forces short-term histogram storage to avoid adding idle audio time interval
222// to buffer period data
Sanna Catherine de Treville Wager80448082017-07-11 14:07:59 -0700223void PerformanceAnalysis::handleStateChange() {
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700224 mBufferPeriod.mPrevTs = 0;
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700225 return;
226}
227
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700228
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700229// Checks whether the time interval between two outliers is far enough from
230// a typical delta to be considered a peak.
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700231// looks for changes in distribution (peaks), which can be either positive or negative.
232// The function sets the mean to the starting value and sigma to 0, and updates
233// them as long as no peak is detected. When a value is more than 'threshold'
234// standard deviations from the mean, a peak is detected and the mean and sigma
235// are set to the peak value and 0.
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700236bool PerformanceAnalysis::detectAndStorePeak(msInterval diff, timestamp ts) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700237 bool isPeak = false;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700238 if (mOutlierData.empty()) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700239 return false;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700240 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700241 // Update mean of the distribution
242 // TypicalDiff is used to check whether a value is unusually large
243 // when we cannot use standard deviations from the mean because the sd is set to 0.
244 mOutlierDistribution.mTypicalDiff = (mOutlierDistribution.mTypicalDiff *
245 (mOutlierData.size() - 1) + diff) / mOutlierData.size();
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700246
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700247 // Initialize short-term mean at start of program
248 if (mOutlierDistribution.mMean == 0) {
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700249 mOutlierDistribution.mMean = diff;
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700250 }
251 // Update length of current sequence of outliers
252 mOutlierDistribution.mN++;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700253
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700254 // Check whether a large deviation from the mean occurred.
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700255 // If the standard deviation has been reset to zero, the comparison is
256 // instead to the mean of the full mOutlierInterval sequence.
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700257 if ((fabs(diff - mOutlierDistribution.mMean) <
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700258 mOutlierDistribution.kMaxDeviation * mOutlierDistribution.mSd) ||
259 (mOutlierDistribution.mSd == 0 &&
260 fabs(diff - mOutlierDistribution.mMean) <
261 mOutlierDistribution.mTypicalDiff)) {
262 // update the mean and sd using online algorithm
263 // https://en.wikipedia.org/wiki/
264 // Algorithms_for_calculating_variance#Online_algorithm
265 mOutlierDistribution.mN++;
266 const double kDelta = diff - mOutlierDistribution.mMean;
267 mOutlierDistribution.mMean += kDelta / mOutlierDistribution.mN;
268 const double kDelta2 = diff - mOutlierDistribution.mMean;
269 mOutlierDistribution.mM2 += kDelta * kDelta2;
270 mOutlierDistribution.mSd = (mOutlierDistribution.mN < 2) ? 0 :
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700271 sqrt(mOutlierDistribution.mM2 / (mOutlierDistribution.mN - 1));
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700272 } else {
273 // new value is far from the mean:
274 // store peak timestamp and reset mean, sd, and short-term sequence
275 isPeak = true;
276 mPeakTimestamps.emplace_front(ts);
277 // if mPeaks has reached capacity, delete oldest data
278 // Note: this means that mOutlierDistribution values do not exactly
279 // match the data we have in mPeakTimestamps, but this is not an issue
280 // in practice for estimating future peaks.
281 // TODO: turn this into a circular buffer
282 if (mPeakTimestamps.size() >= kMaxLength.Peaks) {
283 mPeakTimestamps.resize(kMaxLength.Peaks);
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700284 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700285 mOutlierDistribution.mMean = 0;
286 mOutlierDistribution.mSd = 0;
287 mOutlierDistribution.mN = 0;
288 mOutlierDistribution.mM2 = 0;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700289 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700290 return isPeak;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700291}
292
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700293
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700294// Determines whether the difference between a timestamp and the previous
295// one is beyond a threshold. If yes, stores the timestamp as an outlier
296// and writes to mOutlierdata in the following format:
297// Time elapsed since previous outlier: Timestamp of start of outlier
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700298// e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18).
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700299// TODO: learn what timestamp sequences correlate with glitches instead of
300// manually designing a heuristic.
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700301bool PerformanceAnalysis::detectAndStoreOutlier(const msInterval diffMs) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700302 bool isOutlier = false;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700303 if (diffMs >= mBufferPeriod.mOutlier) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700304 isOutlier = true;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700305 mOutlierData.emplace_front(
306 mOutlierDistribution.mElapsed, mBufferPeriod.mPrevTs);
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700307 // Remove oldest value if the vector is full
308 // TODO: turn this into a circular buffer
309 // TODO: make sure kShortHistSize is large enough that that data will never be lost
310 // before being written to file or to a FIFO
311 if (mOutlierData.size() >= kMaxLength.Outliers) {
312 mOutlierData.resize(kMaxLength.Outliers);
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700313 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700314 mOutlierDistribution.mElapsed = 0;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700315 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700316 mOutlierDistribution.mElapsed += diffMs;
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700317 return isOutlier;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700318}
319
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700320// rounds value to precision based on log-distance from mean
Ivan Lozanobb4b8b52017-11-30 15:43:19 -0800321__attribute__((no_sanitize("signed-integer-overflow")))
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700322inline double logRound(double x, double mean) {
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700323 // Larger values decrease range of high resolution and prevent overflow
324 // of a histogram on the console.
325 // The following formula adjusts kBase based on the buffer period length.
326 // Different threads have buffer periods ranging from 2 to 40. The
327 // formula below maps buffer period 2 to kBase = ~1, 4 to ~2, 20 to ~3, 40 to ~4.
328 // TODO: tighten this for higher means, the data still overflows
329 const double kBase = log(mean) / log(2.2);
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700330 const double power = floor(
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700331 log(abs(x - mean) / mean) / log(kBase)) + 2;
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700332 // do not round values close to the mean
333 if (power < 1) {
334 return x;
335 }
336 const int factor = static_cast<int>(pow(10, power));
337 return (static_cast<int>(x) * factor) / factor;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700338}
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700339
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700340// TODO Make it return a std::string instead of modifying body
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700341// TODO: move this to ReportPerformance, probably make it a friend function
342// of PerformanceAnalysis
343void PerformanceAnalysis::reportPerformance(String8 *body, int author, log_hash_t hash,
344 int maxHeight) {
Eric Tan8180b742018-07-10 15:23:29 -0700345 if (mHists.empty() || body == nullptr) {
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700346 return;
347 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700348
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700349 // ms of active audio in displayed histogram
350 double elapsedMs = 0;
351 // starting timestamp of histogram
352 timestamp startingTs = mHists[0].first;
353
354 // histogram which stores .1 precision ms counts instead of Jiffy multiple counts
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700355 std::map<double, int> buckets;
Sanna Catherine de Treville Wagera80649a2017-07-21 16:16:38 -0700356 for (const auto &shortHist: mHists) {
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700357 for (const auto &countPair : shortHist.second) {
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700358 const double ms = static_cast<double>(countPair.first) / kJiffyPerMs;
359 buckets[logRound(ms, mBufferPeriod.mMean)] += countPair.second;
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700360 elapsedMs += ms * countPair.second;
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700361 }
362 }
363
Eric Tan8180b742018-07-10 15:23:29 -0700364 static const int SIZE = 128;
365 char title[SIZE];
366 snprintf(title, sizeof(title), "\n%s %3.2f %s\n%s%d, %lld, %lld\n",
367 "Occurrences in", (elapsedMs / kMsPerSec), "seconds of audio:",
368 "Thread, hash, starting timestamp: ", author,
369 static_cast<long long>(hash), static_cast<long long>(startingTs));
370 static const char * const kLabel = "ms";
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700371
Eric Tan39ec8d62018-07-24 09:49:29 -0700372 body->appendFormat("%s",
373 audio_utils_plot_histogram(buckets, title, kLabel, maxHeight).c_str());
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700374
Sanna Catherine de Treville Wager316f1fd2017-06-23 09:10:15 -0700375 // Now report glitches
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700376 body->appendFormat("\ntime elapsed between glitches and glitch timestamps:\n");
Sanna Catherine de Treville Wager316f1fd2017-06-23 09:10:15 -0700377 for (const auto &outlier: mOutlierData) {
378 body->appendFormat("%lld: %lld\n", static_cast<long long>(outlier.first),
379 static_cast<long long>(outlier.second));
380 }
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700381}
382
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700383//------------------------------------------------------------------------------
384
385// writes summary of performance into specified file descriptor
Sanna Catherine de Treville Wager23f89d32017-07-24 18:24:48 -0700386void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) {
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700387 String8 body;
Eric Tane98dd6f2018-08-22 18:23:50 -0700388#ifdef WRITE_TO_FILE
Sanna Catherine de Treville Wagerf8c34282017-07-25 11:31:18 -0700389 const char* const kDirectory = "/data/misc/audioserver/";
Eric Tane98dd6f2018-08-22 18:23:50 -0700390#endif
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700391 for (auto & thread : threadPerformanceAnalysis) {
Sanna Catherine de Treville Wagerd0965172017-07-24 13:42:44 -0700392 for (auto & hash: thread.second) {
Sanna Catherine de Treville Wager23f89d32017-07-24 18:24:48 -0700393 PerformanceAnalysis& curr = hash.second;
Sanna Catherine de Treville Wager23f89d32017-07-24 18:24:48 -0700394 // write performance data to console
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700395 curr.reportPerformance(&body, thread.first, hash.first);
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700396 if (!body.isEmpty()) {
397 dumpLine(fd, indent, body);
398 body.clear();
399 }
Eric Tane98dd6f2018-08-22 18:23:50 -0700400#ifdef WRITE_TO_FILE
401 // write to file. Enable by uncommenting macro at top of file.
Sanna Catherine de Treville Wagerf8c34282017-07-25 11:31:18 -0700402 writeToFile(curr.mHists, curr.mOutlierData, curr.mPeakTimestamps,
403 kDirectory, false, thread.first, hash.first);
Eric Tane98dd6f2018-08-22 18:23:50 -0700404#endif
Sanna Catherine de Treville Wagerd0965172017-07-24 13:42:44 -0700405 }
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700406 }
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700407}
408
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700409
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700410// Writes a string into specified file descriptor
411void dumpLine(int fd, int indent, const String8 &body) {
412 dprintf(fd, "%.*s%s \n", indent, "", body.string());
413}
414
Sanna Catherine de Treville Wager80448082017-07-11 14:07:59 -0700415} // namespace ReportPerformance
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700416} // namespace android