blob: 0ddd9087fc6a3fffad42c5efb8e46d22f0c17533 [file] [log] [blame]
Glenn Kasten04333cd2015-02-17 16:23:03 -08001/*
2 * Copyright (C) 2014 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#define LOG_TAG "FastMixerDumpState"
18//#define LOG_NDEBUG 0
19
20#include "Configuration.h"
21#ifdef FAST_MIXER_STATISTICS
22#include <cpustats/CentralTendencyStatistics.h>
23#ifdef CPU_FREQUENCY_STATISTICS
24#include <cpustats/ThreadCpuUsage.h>
25#endif
26#endif
27#include <utils/Debug.h>
28#include <utils/Log.h>
29#include "FastMixerDumpState.h"
30
31namespace android {
32
33FastMixerDumpState::FastMixerDumpState(
34#ifdef FAST_MIXER_STATISTICS
35 uint32_t samplingN
36#endif
37 ) : FastThreadDumpState(),
38 mWriteSequence(0), mFramesWritten(0),
39 mNumTracks(0), mWriteErrors(0),
40 mSampleRate(0), mFrameCount(0),
41 mTrackMask(0)
42{
43#ifdef FAST_MIXER_STATISTICS
44 increaseSamplingN(samplingN);
45#endif
46}
47
48#ifdef FAST_MIXER_STATISTICS
49void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
50{
51 if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
52 return;
53 }
54 uint32_t additional = samplingN - mSamplingN;
55 // sample arrays aren't accessed atomically with respect to the bounds,
56 // so clearing reduces chance for dumpsys to read random uninitialized samples
57 memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
58 memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
59#ifdef CPU_FREQUENCY_STATISTICS
60 memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
61#endif
62 mSamplingN = samplingN;
63}
64#endif
65
66FastMixerDumpState::~FastMixerDumpState()
67{
68}
69
70// helper function called by qsort()
71static int compare_uint32_t(const void *pa, const void *pb)
72{
73 uint32_t a = *(const uint32_t *)pa;
74 uint32_t b = *(const uint32_t *)pb;
75 if (a < b) {
76 return -1;
77 } else if (a > b) {
78 return 1;
79 } else {
80 return 0;
81 }
82}
83
84void FastMixerDumpState::dump(int fd) const
85{
86 if (mCommand == FastMixerState::INITIAL) {
87 dprintf(fd, " FastMixer not initialized\n");
88 return;
89 }
90#define COMMAND_MAX 32
91 char string[COMMAND_MAX];
92 switch (mCommand) {
93 case FastMixerState::INITIAL:
94 strcpy(string, "INITIAL");
95 break;
96 case FastMixerState::HOT_IDLE:
97 strcpy(string, "HOT_IDLE");
98 break;
99 case FastMixerState::COLD_IDLE:
100 strcpy(string, "COLD_IDLE");
101 break;
102 case FastMixerState::EXIT:
103 strcpy(string, "EXIT");
104 break;
105 case FastMixerState::MIX:
106 strcpy(string, "MIX");
107 break;
108 case FastMixerState::WRITE:
109 strcpy(string, "WRITE");
110 break;
111 case FastMixerState::MIX_WRITE:
112 strcpy(string, "MIX_WRITE");
113 break;
114 default:
115 snprintf(string, COMMAND_MAX, "%d", mCommand);
116 break;
117 }
118 double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
119 (mMeasuredWarmupTs.tv_nsec / 1000000.0);
120 double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
121 dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
122 " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
123 " sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
124 " mixPeriod=%.2f ms\n",
125 string, mWriteSequence, mFramesWritten,
126 mNumTracks, mWriteErrors, mUnderruns, mOverruns,
127 mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
128 mixPeriodSec * 1e3);
129#ifdef FAST_MIXER_STATISTICS
130 // find the interval of valid samples
131 uint32_t bounds = mBounds;
132 uint32_t newestOpen = bounds & 0xFFFF;
133 uint32_t oldestClosed = bounds >> 16;
134 uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
135 if (n > mSamplingN) {
136 ALOGE("too many samples %u", n);
137 n = mSamplingN;
138 }
139 // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
140 // and adjusted CPU load in MHz normalized for CPU clock frequency
141 CentralTendencyStatistics wall, loadNs;
142#ifdef CPU_FREQUENCY_STATISTICS
143 CentralTendencyStatistics kHz, loadMHz;
144 uint32_t previousCpukHz = 0;
145#endif
146 // Assuming a normal distribution for cycle times, three standard deviations on either side of
147 // the mean account for 99.73% of the population. So if we take each tail to be 1/1000 of the
148 // sample set, we get 99.8% combined, or close to three standard deviations.
149 static const uint32_t kTailDenominator = 1000;
150 uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
151 // loop over all the samples
152 for (uint32_t j = 0; j < n; ++j) {
153 size_t i = oldestClosed++ & (mSamplingN - 1);
154 uint32_t wallNs = mMonotonicNs[i];
155 if (tail != NULL) {
156 tail[j] = wallNs;
157 }
158 wall.sample(wallNs);
159 uint32_t sampleLoadNs = mLoadNs[i];
160 loadNs.sample(sampleLoadNs);
161#ifdef CPU_FREQUENCY_STATISTICS
162 uint32_t sampleCpukHz = mCpukHz[i];
163 // skip bad kHz samples
164 if ((sampleCpukHz & ~0xF) != 0) {
165 kHz.sample(sampleCpukHz >> 4);
166 if (sampleCpukHz == previousCpukHz) {
167 double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
168 double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9
169 loadMHz.sample(adjMHz);
170 }
171 }
172 previousCpukHz = sampleCpukHz;
173#endif
174 }
175 if (n) {
176 dprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
177 wall.n() * mixPeriodSec);
178 dprintf(fd, " wall clock time in ms per mix cycle:\n"
179 " mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
180 wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
181 wall.stddev()*1e-6);
182 dprintf(fd, " raw CPU load in us per mix cycle:\n"
183 " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
184 loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
185 loadNs.stddev()*1e-3);
186 } else {
187 dprintf(fd, " No FastMixer statistics available currently\n");
188 }
189#ifdef CPU_FREQUENCY_STATISTICS
190 dprintf(fd, " CPU clock frequency in MHz:\n"
191 " mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
192 kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
193 dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
194 " mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
195 loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
196#endif
197 if (tail != NULL) {
198 qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
199 // assume same number of tail samples on each side, left and right
200 uint32_t count = n / kTailDenominator;
201 CentralTendencyStatistics left, right;
202 for (uint32_t i = 0; i < count; ++i) {
203 left.sample(tail[i]);
204 right.sample(tail[n - (i + 1)]);
205 }
206 dprintf(fd, " Distribution of mix cycle times in ms for the tails "
207 "(> ~3 stddev outliers):\n"
208 " left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
209 " right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
210 left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
211 right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
212 right.stddev()*1e-6);
213 delete[] tail;
214 }
215#endif
216 // The active track mask and track states are updated non-atomically.
217 // So if we relied on isActive to decide whether to display,
218 // then we might display an obsolete track or omit an active track.
219 // Instead we always display all tracks, with an indication
220 // of whether we think the track is active.
221 uint32_t trackMask = mTrackMask;
222 dprintf(fd, " Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
223 FastMixerState::kMaxFastTracks, trackMask);
224 dprintf(fd, " Index Active Full Partial Empty Recent Ready\n");
225 for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
226 bool isActive = trackMask & 1;
227 const FastTrackDump *ftDump = &mTracks[i];
228 const FastTrackUnderruns& underruns = ftDump->mUnderruns;
229 const char *mostRecent;
230 switch (underruns.mBitFields.mMostRecent) {
231 case UNDERRUN_FULL:
232 mostRecent = "full";
233 break;
234 case UNDERRUN_PARTIAL:
235 mostRecent = "partial";
236 break;
237 case UNDERRUN_EMPTY:
238 mostRecent = "empty";
239 break;
240 default:
241 mostRecent = "?";
242 break;
243 }
244 dprintf(fd, " %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
245 (underruns.mBitFields.mFull) & UNDERRUN_MASK,
246 (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
247 (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
248 mostRecent, ftDump->mFramesReady);
249 }
250}
251
252} // android