blob: ce9e22a87b2f886ebe1eff14bbf5669887981ce9 [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>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070025#include <math.h>
26#include <numeric>
Eric Tane98dd6f2018-08-22 18:23:50 -070027#include <sstream>
28#include <string>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070029#include <vector>
30#include <stdarg.h>
31#include <stdint.h>
32#include <stdio.h>
33#include <string.h>
34#include <sys/prctl.h>
35#include <time.h>
36#include <new>
Eric Tan39ec8d62018-07-24 09:49:29 -070037#include <audio_utils/LogPlot.h>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070038#include <audio_utils/roundup.h>
Glenn Kasten8589ce72017-09-08 17:03:42 -070039#include <media/nblog/NBLog.h>
40#include <media/nblog/PerformanceAnalysis.h>
41#include <media/nblog/ReportPerformance.h>
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -070042#include <utils/Log.h>
43#include <utils/String8.h>
44
45#include <queue>
46#include <utility>
47
48namespace android {
49
Eric Tane98dd6f2018-08-22 18:23:50 -070050void Histogram::add(double value)
51{
52 // TODO Handle domain and range error exceptions?
53 const int binIndex = lround((value - mLow) / mBinSize);
54 if (binIndex < 0) {
55 mLowCount++;
56 } else if (binIndex >= mNumBins) {
57 mHighCount++;
58 } else {
59 mBins[binIndex]++;
60 }
61 mTotalCount++;
62}
63
64void Histogram::clear()
65{
66 std::fill(mBins.begin(), mBins.end(), 0);
67 mLowCount = 0;
68 mHighCount = 0;
69 mTotalCount = 0;
70}
71
72uint64_t Histogram::totalCount() const
73{
74 return mTotalCount;
75}
76
77std::string Histogram::serializeToString() const {
78 std::stringstream ss;
79 static constexpr char kDivider = '|';
80 ss << mBinSize << "," << mNumBins << "," << mLow << ",{";
81 bool first = true;
82 if (mLowCount != 0) {
83 ss << "-1" << kDivider << mLowCount;
84 first = false;
85 }
86 for (size_t i = 0; i < mNumBins; i++) {
87 if (mBins[i] != 0) {
88 if (!first) {
89 ss << ",";
90 }
91 ss << i << kDivider << mBins[i];
92 first = false;
93 }
94 }
95 if (mHighCount != 0) {
96 if (!first) {
97 ss << ",";
98 }
99 ss << mNumBins << kDivider << mHighCount;
100 first = false;
101 }
102 ss << "}";
103
104 return ss.str();
105}
106
107// TODO make a hash map from Event type to std::pair<HistConfig, unordered_map<int, Histogram>>
108// so that we don't have to create a "add histogram entry" method for every different metric.
109void PerformanceData::addCycleTimeEntry(int author, double cycleTimeMs)
110{
111 if (mCycleTimeMsHists.count(author) == 0) {
112 mCycleTimeMsHists.emplace(author, Histogram(kCycleTimeConfig));
113 }
114 mCycleTimeMsHists.at(author).add(cycleTimeMs);
115}
116
117void PerformanceData::addLatencyEntry(int author, double latencyMs)
118{
119 if (mLatencyMsHists.count(author) == 0) {
120 mLatencyMsHists.emplace(author, Histogram(kLatencyConfig));
121 }
122 mLatencyMsHists.at(author).add(latencyMs);
123}
124
125void PerformanceData::dump(int fd, int indent __unused)
126{
127 // TODO add thread metadata for better context.
128 // Also output in a more machine-readable friendly format.
129 dprintf(fd, "Thread cycle time histograms:\n");
130 for (const auto &item : mCycleTimeMsHists) {
131 dprintf(fd, " Thread %d: %s\n", item.first, item.second.serializeToString().c_str());
132 }
133 dprintf(fd, "Latency histograms:\n");
134 for (const auto &item : mLatencyMsHists) {
135 dprintf(fd, " Thread %d: %s\n", item.first, item.second.serializeToString().c_str());
136 }
137}
138
139//------------------------------------------------------------------------------
140
Sanna Catherine de Treville Wager80448082017-07-11 14:07:59 -0700141namespace ReportPerformance {
142
Sanna Catherine de Treville Wager14316442017-08-11 10:45:29 -0700143// Given an audio processing wakeup timestamp, buckets the time interval
144// since the previous timestamp into a histogram, searches for
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700145// outliers, analyzes the outlier series for unexpectedly
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700146// small or large values and stores these as peaks
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700147void PerformanceAnalysis::logTsEntry(timestamp ts) {
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700148 // after a state change, start a new series and do not
149 // record time intervals in-between
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700150 if (mBufferPeriod.mPrevTs == 0) {
151 mBufferPeriod.mPrevTs = ts;
Sanna Catherine de Treville Wagera80649a2017-07-21 16:16:38 -0700152 return;
153 }
154
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700155 // calculate time interval between current and previous timestamp
156 const msInterval diffMs = static_cast<msInterval>(
157 deltaMs(mBufferPeriod.mPrevTs, ts));
158
159 const int diffJiffy = deltaJiffy(mBufferPeriod.mPrevTs, ts);
160
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700161 // old versus new weight ratio when updating the buffer period mean
162 static constexpr double exponentialWeight = 0.999;
163 // update buffer period mean with exponential weighting
164 mBufferPeriod.mMean = (mBufferPeriod.mMean < 0) ? diffMs :
165 exponentialWeight * mBufferPeriod.mMean + (1.0 - exponentialWeight) * diffMs;
166 // set mOutlierFactor to a smaller value for the fastmixer thread
167 const int kFastMixerMax = 10;
168 // NormalMixer times vary much more than FastMixer times.
169 // TODO: mOutlierFactor values are set empirically based on what appears to be
170 // an outlier. Learn these values from the data.
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700171 mBufferPeriod.mOutlierFactor = mBufferPeriod.mMean < kFastMixerMax ? 1.8 : 2.0;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700172 // set outlier threshold
173 mBufferPeriod.mOutlier = mBufferPeriod.mMean * mBufferPeriod.mOutlierFactor;
174
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700175 // Check whether the time interval between the current timestamp
176 // and the previous one is long enough to count as an outlier
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700177 const bool isOutlier = detectAndStoreOutlier(diffMs);
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700178 // If an outlier was found, check whether it was a peak
179 if (isOutlier) {
180 /*bool isPeak =*/ detectAndStorePeak(
181 mOutlierData[0].first, mOutlierData[0].second);
182 // TODO: decide whether to insert a new empty histogram if a peak
183 // TODO: remove isPeak if unused to avoid "unused variable" error
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700184 // occurred at the current timestamp
Sanna Catherine de Treville Wagera80649a2017-07-21 16:16:38 -0700185 }
186
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700187 // Insert a histogram to mHists if it is empty, or
188 // close the current histogram and insert a new empty one if
189 // if the current histogram has spanned its maximum time interval.
190 if (mHists.empty() ||
191 deltaMs(mHists[0].first, ts) >= kMaxLength.HistTimespanMs) {
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700192 mHists.emplace_front(ts, std::map<int, int>());
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700193 // When memory is full, delete oldest histogram
194 // TODO: use a circular buffer
195 if (mHists.size() >= kMaxLength.Hists) {
196 mHists.resize(kMaxLength.Hists);
197 }
198 }
199 // add current time intervals to histogram
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700200 ++mHists[0].second[diffJiffy];
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700201 // update previous timestamp
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700202 mBufferPeriod.mPrevTs = ts;
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700203}
204
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700205
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700206// forces short-term histogram storage to avoid adding idle audio time interval
207// to buffer period data
Sanna Catherine de Treville Wager80448082017-07-11 14:07:59 -0700208void PerformanceAnalysis::handleStateChange() {
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700209 mBufferPeriod.mPrevTs = 0;
Sanna Catherine de Treville Wagera8a8a472017-07-11 09:41:25 -0700210 return;
211}
212
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700213
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700214// Checks whether the time interval between two outliers is far enough from
215// a typical delta to be considered a peak.
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700216// looks for changes in distribution (peaks), which can be either positive or negative.
217// The function sets the mean to the starting value and sigma to 0, and updates
218// them as long as no peak is detected. When a value is more than 'threshold'
219// standard deviations from the mean, a peak is detected and the mean and sigma
220// are set to the peak value and 0.
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700221bool PerformanceAnalysis::detectAndStorePeak(msInterval diff, timestamp ts) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700222 bool isPeak = false;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700223 if (mOutlierData.empty()) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700224 return false;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700225 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700226 // Update mean of the distribution
227 // TypicalDiff is used to check whether a value is unusually large
228 // when we cannot use standard deviations from the mean because the sd is set to 0.
229 mOutlierDistribution.mTypicalDiff = (mOutlierDistribution.mTypicalDiff *
230 (mOutlierData.size() - 1) + diff) / mOutlierData.size();
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700231
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700232 // Initialize short-term mean at start of program
233 if (mOutlierDistribution.mMean == 0) {
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700234 mOutlierDistribution.mMean = diff;
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700235 }
236 // Update length of current sequence of outliers
237 mOutlierDistribution.mN++;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700238
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700239 // Check whether a large deviation from the mean occurred.
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700240 // If the standard deviation has been reset to zero, the comparison is
241 // instead to the mean of the full mOutlierInterval sequence.
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700242 if ((fabs(diff - mOutlierDistribution.mMean) <
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700243 mOutlierDistribution.kMaxDeviation * mOutlierDistribution.mSd) ||
244 (mOutlierDistribution.mSd == 0 &&
245 fabs(diff - mOutlierDistribution.mMean) <
246 mOutlierDistribution.mTypicalDiff)) {
247 // update the mean and sd using online algorithm
248 // https://en.wikipedia.org/wiki/
249 // Algorithms_for_calculating_variance#Online_algorithm
250 mOutlierDistribution.mN++;
251 const double kDelta = diff - mOutlierDistribution.mMean;
252 mOutlierDistribution.mMean += kDelta / mOutlierDistribution.mN;
253 const double kDelta2 = diff - mOutlierDistribution.mMean;
254 mOutlierDistribution.mM2 += kDelta * kDelta2;
255 mOutlierDistribution.mSd = (mOutlierDistribution.mN < 2) ? 0 :
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700256 sqrt(mOutlierDistribution.mM2 / (mOutlierDistribution.mN - 1));
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700257 } else {
258 // new value is far from the mean:
259 // store peak timestamp and reset mean, sd, and short-term sequence
260 isPeak = true;
261 mPeakTimestamps.emplace_front(ts);
262 // if mPeaks has reached capacity, delete oldest data
263 // Note: this means that mOutlierDistribution values do not exactly
264 // match the data we have in mPeakTimestamps, but this is not an issue
265 // in practice for estimating future peaks.
266 // TODO: turn this into a circular buffer
267 if (mPeakTimestamps.size() >= kMaxLength.Peaks) {
268 mPeakTimestamps.resize(kMaxLength.Peaks);
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700269 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700270 mOutlierDistribution.mMean = 0;
271 mOutlierDistribution.mSd = 0;
272 mOutlierDistribution.mN = 0;
273 mOutlierDistribution.mM2 = 0;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700274 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700275 return isPeak;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700276}
277
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700278
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700279// Determines whether the difference between a timestamp and the previous
280// one is beyond a threshold. If yes, stores the timestamp as an outlier
281// and writes to mOutlierdata in the following format:
282// Time elapsed since previous outlier: Timestamp of start of outlier
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700283// 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 -0700284// TODO: learn what timestamp sequences correlate with glitches instead of
285// manually designing a heuristic.
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700286bool PerformanceAnalysis::detectAndStoreOutlier(const msInterval diffMs) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700287 bool isOutlier = false;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700288 if (diffMs >= mBufferPeriod.mOutlier) {
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700289 isOutlier = true;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700290 mOutlierData.emplace_front(
291 mOutlierDistribution.mElapsed, mBufferPeriod.mPrevTs);
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700292 // Remove oldest value if the vector is full
293 // TODO: turn this into a circular buffer
294 // TODO: make sure kShortHistSize is large enough that that data will never be lost
295 // before being written to file or to a FIFO
296 if (mOutlierData.size() >= kMaxLength.Outliers) {
297 mOutlierData.resize(kMaxLength.Outliers);
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700298 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700299 mOutlierDistribution.mElapsed = 0;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700300 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700301 mOutlierDistribution.mElapsed += diffMs;
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700302 return isOutlier;
Sanna Catherine de Treville Wager41cad592017-06-29 14:57:59 -0700303}
304
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700305// rounds value to precision based on log-distance from mean
Ivan Lozanobb4b8b52017-11-30 15:43:19 -0800306__attribute__((no_sanitize("signed-integer-overflow")))
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700307inline double logRound(double x, double mean) {
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700308 // Larger values decrease range of high resolution and prevent overflow
309 // of a histogram on the console.
310 // The following formula adjusts kBase based on the buffer period length.
311 // Different threads have buffer periods ranging from 2 to 40. The
312 // formula below maps buffer period 2 to kBase = ~1, 4 to ~2, 20 to ~3, 40 to ~4.
313 // TODO: tighten this for higher means, the data still overflows
314 const double kBase = log(mean) / log(2.2);
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700315 const double power = floor(
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700316 log(abs(x - mean) / mean) / log(kBase)) + 2;
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700317 // do not round values close to the mean
318 if (power < 1) {
319 return x;
320 }
321 const int factor = static_cast<int>(pow(10, power));
322 return (static_cast<int>(x) * factor) / factor;
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700323}
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700324
Sanna Catherine de Treville Wager6ad40ee2017-07-28 10:10:55 -0700325// TODO Make it return a std::string instead of modifying body
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700326// TODO: move this to ReportPerformance, probably make it a friend function
327// of PerformanceAnalysis
328void PerformanceAnalysis::reportPerformance(String8 *body, int author, log_hash_t hash,
329 int maxHeight) {
Eric Tan8180b742018-07-10 15:23:29 -0700330 if (mHists.empty() || body == nullptr) {
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700331 return;
332 }
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700333
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700334 // ms of active audio in displayed histogram
335 double elapsedMs = 0;
336 // starting timestamp of histogram
337 timestamp startingTs = mHists[0].first;
338
339 // histogram which stores .1 precision ms counts instead of Jiffy multiple counts
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700340 std::map<double, int> buckets;
Sanna Catherine de Treville Wagera80649a2017-07-21 16:16:38 -0700341 for (const auto &shortHist: mHists) {
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700342 for (const auto &countPair : shortHist.second) {
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700343 const double ms = static_cast<double>(countPair.first) / kJiffyPerMs;
344 buckets[logRound(ms, mBufferPeriod.mMean)] += countPair.second;
Sanna Catherine de Treville Wager847b6e62017-08-03 11:35:51 -0700345 elapsedMs += ms * countPair.second;
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700346 }
347 }
348
Eric Tan8180b742018-07-10 15:23:29 -0700349 static const int SIZE = 128;
350 char title[SIZE];
351 snprintf(title, sizeof(title), "\n%s %3.2f %s\n%s%d, %lld, %lld\n",
352 "Occurrences in", (elapsedMs / kMsPerSec), "seconds of audio:",
353 "Thread, hash, starting timestamp: ", author,
354 static_cast<long long>(hash), static_cast<long long>(startingTs));
355 static const char * const kLabel = "ms";
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700356
Eric Tan39ec8d62018-07-24 09:49:29 -0700357 body->appendFormat("%s",
358 audio_utils_plot_histogram(buckets, title, kLabel, maxHeight).c_str());
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700359
Sanna Catherine de Treville Wager316f1fd2017-06-23 09:10:15 -0700360 // Now report glitches
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700361 body->appendFormat("\ntime elapsed between glitches and glitch timestamps:\n");
Sanna Catherine de Treville Wager316f1fd2017-06-23 09:10:15 -0700362 for (const auto &outlier: mOutlierData) {
363 body->appendFormat("%lld: %lld\n", static_cast<long long>(outlier.first),
364 static_cast<long long>(outlier.second));
365 }
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700366}
367
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700368//------------------------------------------------------------------------------
369
370// writes summary of performance into specified file descriptor
Sanna Catherine de Treville Wager23f89d32017-07-24 18:24:48 -0700371void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis) {
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700372 String8 body;
Eric Tane98dd6f2018-08-22 18:23:50 -0700373#ifdef WRITE_TO_FILE
Sanna Catherine de Treville Wagerf8c34282017-07-25 11:31:18 -0700374 const char* const kDirectory = "/data/misc/audioserver/";
Eric Tane98dd6f2018-08-22 18:23:50 -0700375#endif
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700376 for (auto & thread : threadPerformanceAnalysis) {
Sanna Catherine de Treville Wagerd0965172017-07-24 13:42:44 -0700377 for (auto & hash: thread.second) {
Sanna Catherine de Treville Wager23f89d32017-07-24 18:24:48 -0700378 PerformanceAnalysis& curr = hash.second;
Sanna Catherine de Treville Wager23f89d32017-07-24 18:24:48 -0700379 // write performance data to console
Sanna Catherine de Treville Wager2a6a9452017-07-28 11:02:01 -0700380 curr.reportPerformance(&body, thread.first, hash.first);
Sanna Catherine de Treville Wager0a3959e2017-07-25 16:08:17 -0700381 if (!body.isEmpty()) {
382 dumpLine(fd, indent, body);
383 body.clear();
384 }
Eric Tane98dd6f2018-08-22 18:23:50 -0700385#ifdef WRITE_TO_FILE
386 // write to file. Enable by uncommenting macro at top of file.
Sanna Catherine de Treville Wagerf8c34282017-07-25 11:31:18 -0700387 writeToFile(curr.mHists, curr.mOutlierData, curr.mPeakTimestamps,
388 kDirectory, false, thread.first, hash.first);
Eric Tane98dd6f2018-08-22 18:23:50 -0700389#endif
Sanna Catherine de Treville Wagerd0965172017-07-24 13:42:44 -0700390 }
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700391 }
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700392}
393
Sanna Catherine de Treville Wager85768942017-07-26 20:17:30 -0700394
Sanna Catherine de Treville Wagercf6c75a2017-07-21 17:05:25 -0700395// Writes a string into specified file descriptor
396void dumpLine(int fd, int indent, const String8 &body) {
397 dprintf(fd, "%.*s%s \n", indent, "", body.string());
398}
399
Sanna Catherine de Treville Wager80448082017-07-11 14:07:59 -0700400} // namespace ReportPerformance
401
Sanna Catherine de Treville Wagerd0dfe432017-06-22 15:09:38 -0700402} // namespace android