1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker * Copyright 2017 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker *
4*b9df5ad1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker *
8*b9df5ad1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker *
10*b9df5ad1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker */
16*b9df5ad1SAndroid Build Coastguard Worker
17*b9df5ad1SAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
18*b9df5ad1SAndroid Build Coastguard Worker #define LOG_TAG "audio_utils_PowerLog"
19*b9df5ad1SAndroid Build Coastguard Worker #include <log/log.h>
20*b9df5ad1SAndroid Build Coastguard Worker
21*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/PowerLog.h>
22*b9df5ad1SAndroid Build Coastguard Worker
23*b9df5ad1SAndroid Build Coastguard Worker #include <algorithm>
24*b9df5ad1SAndroid Build Coastguard Worker #include <iomanip>
25*b9df5ad1SAndroid Build Coastguard Worker #include <math.h>
26*b9df5ad1SAndroid Build Coastguard Worker #include <sstream>
27*b9df5ad1SAndroid Build Coastguard Worker #include <stdint.h>
28*b9df5ad1SAndroid Build Coastguard Worker #include <unistd.h>
29*b9df5ad1SAndroid Build Coastguard Worker #include <vector>
30*b9df5ad1SAndroid Build Coastguard Worker
31*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/clock.h>
32*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/LogPlot.h>
33*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/power.h>
34*b9df5ad1SAndroid Build Coastguard Worker
35*b9df5ad1SAndroid Build Coastguard Worker namespace android {
36*b9df5ad1SAndroid Build Coastguard Worker
PowerLogBase(uint32_t sampleRate,uint32_t channelCount,audio_format_t format,size_t entries,size_t framesPerEntry)37*b9df5ad1SAndroid Build Coastguard Worker PowerLogBase::PowerLogBase(uint32_t sampleRate,
38*b9df5ad1SAndroid Build Coastguard Worker uint32_t channelCount,
39*b9df5ad1SAndroid Build Coastguard Worker audio_format_t format,
40*b9df5ad1SAndroid Build Coastguard Worker size_t entries,
41*b9df5ad1SAndroid Build Coastguard Worker size_t framesPerEntry)
42*b9df5ad1SAndroid Build Coastguard Worker : mSampleRate(sampleRate)
43*b9df5ad1SAndroid Build Coastguard Worker , mChannelCount(channelCount)
44*b9df5ad1SAndroid Build Coastguard Worker , mFormat(format)
45*b9df5ad1SAndroid Build Coastguard Worker , mFramesPerEntry(framesPerEntry)
46*b9df5ad1SAndroid Build Coastguard Worker , mEntryTimeNs(framesPerEntry * 1e9 / sampleRate)
47*b9df5ad1SAndroid Build Coastguard Worker , mMaxTimeSlipNs(std::min((int64_t)200'000'000, mEntryTimeNs))
48*b9df5ad1SAndroid Build Coastguard Worker , mEntries(entries)
49*b9df5ad1SAndroid Build Coastguard Worker {
50*b9df5ad1SAndroid Build Coastguard Worker (void)mFormat; // currently unused, for future use
51*b9df5ad1SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!audio_utils_is_compute_power_format_supported(format),
52*b9df5ad1SAndroid Build Coastguard Worker "unsupported format: %#x", format);
53*b9df5ad1SAndroid Build Coastguard Worker }
54*b9df5ad1SAndroid Build Coastguard Worker
processEnergy(size_t frames,float energy,int64_t nowNs)55*b9df5ad1SAndroid Build Coastguard Worker void PowerLogBase::processEnergy(size_t frames, float energy, int64_t nowNs) {
56*b9df5ad1SAndroid Build Coastguard Worker // For big entries (i.e. 1 second+) we want to ensure we don't have new data
57*b9df5ad1SAndroid Build Coastguard Worker // accumulating into a previous energy segment.
58*b9df5ad1SAndroid Build Coastguard Worker if (mCurrentTime > 0
59*b9df5ad1SAndroid Build Coastguard Worker && nowNs > mCurrentTime + mCurrentFrames * 1e9 / mSampleRate + mMaxTimeSlipNs) {
60*b9df5ad1SAndroid Build Coastguard Worker flushEntry();
61*b9df5ad1SAndroid Build Coastguard Worker }
62*b9df5ad1SAndroid Build Coastguard Worker
63*b9df5ad1SAndroid Build Coastguard Worker mCurrentEnergy += energy;
64*b9df5ad1SAndroid Build Coastguard Worker
65*b9df5ad1SAndroid Build Coastguard Worker // if we are in a zero run, do not advance.
66*b9df5ad1SAndroid Build Coastguard Worker if (mCurrentEnergy == 0.f && mConsecutiveZeroes > 0) return;
67*b9df5ad1SAndroid Build Coastguard Worker
68*b9df5ad1SAndroid Build Coastguard Worker mCurrentFrames += frames;
69*b9df5ad1SAndroid Build Coastguard Worker if (mCurrentTime == 0) {
70*b9df5ad1SAndroid Build Coastguard Worker mCurrentTime = nowNs;
71*b9df5ad1SAndroid Build Coastguard Worker }
72*b9df5ad1SAndroid Build Coastguard Worker
73*b9df5ad1SAndroid Build Coastguard Worker ALOGV("%s: nowNs:%lld, frames:%zu, mCurrentEnergy:%f, mCurrentFrames:%zu",
74*b9df5ad1SAndroid Build Coastguard Worker __func__, (long long)nowNs, frames, mCurrentEnergy, mCurrentFrames);
75*b9df5ad1SAndroid Build Coastguard Worker if (mCurrentFrames < mFramesPerEntry) return;
76*b9df5ad1SAndroid Build Coastguard Worker
77*b9df5ad1SAndroid Build Coastguard Worker flushEntry();
78*b9df5ad1SAndroid Build Coastguard Worker }
79*b9df5ad1SAndroid Build Coastguard Worker
dumpToString(const char * prefix,size_t lines,int64_t limitNs,bool logPlot) const80*b9df5ad1SAndroid Build Coastguard Worker std::string PowerLogBase::dumpToString(
81*b9df5ad1SAndroid Build Coastguard Worker const char *prefix, size_t lines, int64_t limitNs, bool logPlot) const
82*b9df5ad1SAndroid Build Coastguard Worker {
83*b9df5ad1SAndroid Build Coastguard Worker const size_t maxColumns = 10;
84*b9df5ad1SAndroid Build Coastguard Worker const size_t numberOfEntries = mEntries.size();
85*b9df5ad1SAndroid Build Coastguard Worker if (lines == 0) lines = SIZE_MAX;
86*b9df5ad1SAndroid Build Coastguard Worker
87*b9df5ad1SAndroid Build Coastguard Worker // compute where to start logging
88*b9df5ad1SAndroid Build Coastguard Worker enum {
89*b9df5ad1SAndroid Build Coastguard Worker AT_END,
90*b9df5ad1SAndroid Build Coastguard Worker IN_SIGNAL,
91*b9df5ad1SAndroid Build Coastguard Worker } state = IN_SIGNAL;
92*b9df5ad1SAndroid Build Coastguard Worker size_t count = 1;
93*b9df5ad1SAndroid Build Coastguard Worker size_t column = 0;
94*b9df5ad1SAndroid Build Coastguard Worker size_t nonzeros = 0;
95*b9df5ad1SAndroid Build Coastguard Worker ssize_t offset; // TODO doesn't dump if # entries exceeds SSIZE_MAX
96*b9df5ad1SAndroid Build Coastguard Worker for (offset = 0; offset < (ssize_t)numberOfEntries && count < lines; ++offset) {
97*b9df5ad1SAndroid Build Coastguard Worker const size_t idx = (mIdx + numberOfEntries - offset - 1) % numberOfEntries;
98*b9df5ad1SAndroid Build Coastguard Worker // reverse direction
99*b9df5ad1SAndroid Build Coastguard Worker const int64_t time = mEntries[idx].first;
100*b9df5ad1SAndroid Build Coastguard Worker const float energy = mEntries[idx].second;
101*b9df5ad1SAndroid Build Coastguard Worker
102*b9df5ad1SAndroid Build Coastguard Worker if (state == AT_END) {
103*b9df5ad1SAndroid Build Coastguard Worker if (energy == 0.f) {
104*b9df5ad1SAndroid Build Coastguard Worker ALOGV("two zeroes detected");
105*b9df5ad1SAndroid Build Coastguard Worker break; // normally single zero terminated - two zeroes means no more data.
106*b9df5ad1SAndroid Build Coastguard Worker }
107*b9df5ad1SAndroid Build Coastguard Worker state = IN_SIGNAL;
108*b9df5ad1SAndroid Build Coastguard Worker } else { // IN_SIGNAL
109*b9df5ad1SAndroid Build Coastguard Worker if (energy == 0.f) {
110*b9df5ad1SAndroid Build Coastguard Worker if (column != 0) {
111*b9df5ad1SAndroid Build Coastguard Worker column = 0;
112*b9df5ad1SAndroid Build Coastguard Worker ++count;
113*b9df5ad1SAndroid Build Coastguard Worker }
114*b9df5ad1SAndroid Build Coastguard Worker state = AT_END;
115*b9df5ad1SAndroid Build Coastguard Worker continue;
116*b9df5ad1SAndroid Build Coastguard Worker }
117*b9df5ad1SAndroid Build Coastguard Worker }
118*b9df5ad1SAndroid Build Coastguard Worker if (column == 0 && time < limitNs) {
119*b9df5ad1SAndroid Build Coastguard Worker break;
120*b9df5ad1SAndroid Build Coastguard Worker }
121*b9df5ad1SAndroid Build Coastguard Worker ++nonzeros;
122*b9df5ad1SAndroid Build Coastguard Worker if (++column == maxColumns) {
123*b9df5ad1SAndroid Build Coastguard Worker column = 0;
124*b9df5ad1SAndroid Build Coastguard Worker // TODO ideally we would peek the previous entry to see if it is 0
125*b9df5ad1SAndroid Build Coastguard Worker // to ensure we properly put in a starting signal bracket.
126*b9df5ad1SAndroid Build Coastguard Worker // We don't do that because it would complicate the logic here.
127*b9df5ad1SAndroid Build Coastguard Worker ++count;
128*b9df5ad1SAndroid Build Coastguard Worker }
129*b9df5ad1SAndroid Build Coastguard Worker }
130*b9df5ad1SAndroid Build Coastguard Worker if (offset > 0) {
131*b9df5ad1SAndroid Build Coastguard Worker --offset;
132*b9df5ad1SAndroid Build Coastguard Worker }
133*b9df5ad1SAndroid Build Coastguard Worker // We accumulate the log info into a string, and write to the fd once.
134*b9df5ad1SAndroid Build Coastguard Worker std::stringstream ss;
135*b9df5ad1SAndroid Build Coastguard Worker ss << std::fixed << std::setprecision(1);
136*b9df5ad1SAndroid Build Coastguard Worker // ss << std::scientific;
137*b9df5ad1SAndroid Build Coastguard Worker if (nonzeros == 0) {
138*b9df5ad1SAndroid Build Coastguard Worker ss << prefix << "Signal power history: (none)\n";
139*b9df5ad1SAndroid Build Coastguard Worker } else {
140*b9df5ad1SAndroid Build Coastguard Worker // First value is power, second value is whether value is start of
141*b9df5ad1SAndroid Build Coastguard Worker // a new time stamp.
142*b9df5ad1SAndroid Build Coastguard Worker std::vector<std::pair<float, bool>> plotEntries;
143*b9df5ad1SAndroid Build Coastguard Worker const float timeResolution = mFramesPerEntry * 1000.f / mSampleRate;
144*b9df5ad1SAndroid Build Coastguard Worker ss << prefix << "Signal power history (resolution: " << timeResolution << " ms):\n";
145*b9df5ad1SAndroid Build Coastguard Worker
146*b9df5ad1SAndroid Build Coastguard Worker size_t column = 0;
147*b9df5ad1SAndroid Build Coastguard Worker bool first = true;
148*b9df5ad1SAndroid Build Coastguard Worker bool start = false;
149*b9df5ad1SAndroid Build Coastguard Worker float cumulative = 0.f;
150*b9df5ad1SAndroid Build Coastguard Worker for (; offset >= 0; --offset) {
151*b9df5ad1SAndroid Build Coastguard Worker const size_t idx = (mIdx + numberOfEntries - offset - 1) % numberOfEntries;
152*b9df5ad1SAndroid Build Coastguard Worker const int64_t time = mEntries[idx].first;
153*b9df5ad1SAndroid Build Coastguard Worker const float energy = mEntries[idx].second;
154*b9df5ad1SAndroid Build Coastguard Worker
155*b9df5ad1SAndroid Build Coastguard Worker if (energy == 0.f) {
156*b9df5ad1SAndroid Build Coastguard Worker if (!first) {
157*b9df5ad1SAndroid Build Coastguard Worker ss << " ] sum(" << audio_utils_power_from_energy(cumulative) << ")";
158*b9df5ad1SAndroid Build Coastguard Worker // Add an entry to denote the start of a new time stamp series.
159*b9df5ad1SAndroid Build Coastguard Worker if (!plotEntries.empty()) {
160*b9df5ad1SAndroid Build Coastguard Worker // First value should be between min and max of all graph entries
161*b9df5ad1SAndroid Build Coastguard Worker // so that it doesn't mess with y-axis scaling.
162*b9df5ad1SAndroid Build Coastguard Worker plotEntries.emplace_back(plotEntries.back().first, true);
163*b9df5ad1SAndroid Build Coastguard Worker }
164*b9df5ad1SAndroid Build Coastguard Worker }
165*b9df5ad1SAndroid Build Coastguard Worker cumulative = 0.f;
166*b9df5ad1SAndroid Build Coastguard Worker column = 0;
167*b9df5ad1SAndroid Build Coastguard Worker start = true;
168*b9df5ad1SAndroid Build Coastguard Worker continue;
169*b9df5ad1SAndroid Build Coastguard Worker }
170*b9df5ad1SAndroid Build Coastguard Worker if (column == 0) {
171*b9df5ad1SAndroid Build Coastguard Worker // print time if at start of column
172*b9df5ad1SAndroid Build Coastguard Worker if (!first) {
173*b9df5ad1SAndroid Build Coastguard Worker ss << "\n";
174*b9df5ad1SAndroid Build Coastguard Worker }
175*b9df5ad1SAndroid Build Coastguard Worker ss << prefix << " " << audio_utils_time_string_from_ns(time).time
176*b9df5ad1SAndroid Build Coastguard Worker << (start ? ": [ ": ": ");
177*b9df5ad1SAndroid Build Coastguard Worker first = false;
178*b9df5ad1SAndroid Build Coastguard Worker start = false;
179*b9df5ad1SAndroid Build Coastguard Worker } else {
180*b9df5ad1SAndroid Build Coastguard Worker ss << " ";
181*b9df5ad1SAndroid Build Coastguard Worker }
182*b9df5ad1SAndroid Build Coastguard Worker if (++column >= maxColumns) {
183*b9df5ad1SAndroid Build Coastguard Worker column = 0;
184*b9df5ad1SAndroid Build Coastguard Worker }
185*b9df5ad1SAndroid Build Coastguard Worker
186*b9df5ad1SAndroid Build Coastguard Worker cumulative += energy;
187*b9df5ad1SAndroid Build Coastguard Worker // convert energy to power and print
188*b9df5ad1SAndroid Build Coastguard Worker const float power =
189*b9df5ad1SAndroid Build Coastguard Worker audio_utils_power_from_energy(energy / (mChannelCount * mFramesPerEntry));
190*b9df5ad1SAndroid Build Coastguard Worker ss << std::setw(6) << power;
191*b9df5ad1SAndroid Build Coastguard Worker ALOGV("state: %d %lld %f", state, (long long)time, power);
192*b9df5ad1SAndroid Build Coastguard Worker // Add an entry to the ASCII art power log graph.
193*b9df5ad1SAndroid Build Coastguard Worker // false indicates the value doesn't have a new series time stamp.
194*b9df5ad1SAndroid Build Coastguard Worker plotEntries.emplace_back(power, false);
195*b9df5ad1SAndroid Build Coastguard Worker }
196*b9df5ad1SAndroid Build Coastguard Worker if (logPlot) {
197*b9df5ad1SAndroid Build Coastguard Worker ss << "\n" << audio_utils_log_plot(plotEntries.begin(), plotEntries.end());
198*b9df5ad1SAndroid Build Coastguard Worker }
199*b9df5ad1SAndroid Build Coastguard Worker ss << "\n";
200*b9df5ad1SAndroid Build Coastguard Worker }
201*b9df5ad1SAndroid Build Coastguard Worker return ss.str();
202*b9df5ad1SAndroid Build Coastguard Worker }
203*b9df5ad1SAndroid Build Coastguard Worker
flushEntry()204*b9df5ad1SAndroid Build Coastguard Worker void PowerLogBase::flushEntry() {
205*b9df5ad1SAndroid Build Coastguard Worker // We store the data as normalized energy per sample. The energy sequence is
206*b9df5ad1SAndroid Build Coastguard Worker // zero terminated. Consecutive zero entries are ignored.
207*b9df5ad1SAndroid Build Coastguard Worker if (mCurrentEnergy == 0.f) {
208*b9df5ad1SAndroid Build Coastguard Worker if (mConsecutiveZeroes++ == 0) {
209*b9df5ad1SAndroid Build Coastguard Worker mEntries[mIdx++] = std::make_pair(mCurrentTime, 0.f);
210*b9df5ad1SAndroid Build Coastguard Worker // zero terminate the signal sequence.
211*b9df5ad1SAndroid Build Coastguard Worker }
212*b9df5ad1SAndroid Build Coastguard Worker } else {
213*b9df5ad1SAndroid Build Coastguard Worker mConsecutiveZeroes = 0;
214*b9df5ad1SAndroid Build Coastguard Worker mEntries[mIdx++] = std::make_pair(mCurrentTime, mCurrentEnergy);
215*b9df5ad1SAndroid Build Coastguard Worker ALOGV("writing %lld %f", (long long)mCurrentTime, mCurrentEnergy);
216*b9df5ad1SAndroid Build Coastguard Worker }
217*b9df5ad1SAndroid Build Coastguard Worker if (mIdx >= mEntries.size()) {
218*b9df5ad1SAndroid Build Coastguard Worker mIdx -= mEntries.size();
219*b9df5ad1SAndroid Build Coastguard Worker }
220*b9df5ad1SAndroid Build Coastguard Worker mCurrentTime = 0;
221*b9df5ad1SAndroid Build Coastguard Worker mCurrentEnergy = 0;
222*b9df5ad1SAndroid Build Coastguard Worker mCurrentFrames = 0;
223*b9df5ad1SAndroid Build Coastguard Worker }
224*b9df5ad1SAndroid Build Coastguard Worker
log(const void * buffer,size_t frames,int64_t nowNs)225*b9df5ad1SAndroid Build Coastguard Worker void PowerLog::log(const void *buffer, size_t frames, int64_t nowNs) {
226*b9df5ad1SAndroid Build Coastguard Worker if (frames == 0) return;
227*b9df5ad1SAndroid Build Coastguard Worker std::lock_guard <std::mutex> guard(mMutex);
228*b9df5ad1SAndroid Build Coastguard Worker
229*b9df5ad1SAndroid Build Coastguard Worker const size_t bytes_per_sample = audio_bytes_per_sample(mFormat);
230*b9df5ad1SAndroid Build Coastguard Worker while (true) {
231*b9df5ad1SAndroid Build Coastguard Worker // limit the number of frames to process from the requirements
232*b9df5ad1SAndroid Build Coastguard Worker // of each log base.
233*b9df5ad1SAndroid Build Coastguard Worker size_t processFrames = mBase[0]->framesToProcess(frames);
234*b9df5ad1SAndroid Build Coastguard Worker for (size_t i = 1; i < std::size(mBase); ++i) {
235*b9df5ad1SAndroid Build Coastguard Worker processFrames = std::min(processFrames, mBase[i]->framesToProcess(frames));
236*b9df5ad1SAndroid Build Coastguard Worker }
237*b9df5ad1SAndroid Build Coastguard Worker const float energy = audio_utils_compute_energy_mono(buffer, mFormat,
238*b9df5ad1SAndroid Build Coastguard Worker processFrames * mChannelCount);
239*b9df5ad1SAndroid Build Coastguard Worker for (const auto& base : mBase) {
240*b9df5ad1SAndroid Build Coastguard Worker base->processEnergy(processFrames, energy, nowNs);
241*b9df5ad1SAndroid Build Coastguard Worker }
242*b9df5ad1SAndroid Build Coastguard Worker frames -= processFrames;
243*b9df5ad1SAndroid Build Coastguard Worker if (frames == 0) return;
244*b9df5ad1SAndroid Build Coastguard Worker buffer = (const uint8_t *) buffer + processFrames * mChannelCount * bytes_per_sample;
245*b9df5ad1SAndroid Build Coastguard Worker nowNs += processFrames * NANOS_PER_SECOND / mSampleRate;
246*b9df5ad1SAndroid Build Coastguard Worker }
247*b9df5ad1SAndroid Build Coastguard Worker }
248*b9df5ad1SAndroid Build Coastguard Worker
dumpToString(const char * prefix,size_t lines,int64_t limitNs,bool logPlot) const249*b9df5ad1SAndroid Build Coastguard Worker std::string PowerLog::dumpToString(
250*b9df5ad1SAndroid Build Coastguard Worker const char *prefix, size_t lines, int64_t limitNs, bool logPlot) const
251*b9df5ad1SAndroid Build Coastguard Worker {
252*b9df5ad1SAndroid Build Coastguard Worker // Determine how to distribute lines among the logs.
253*b9df5ad1SAndroid Build Coastguard Worker const size_t logs = mBase.size();
254*b9df5ad1SAndroid Build Coastguard Worker std::vector<size_t> sublines(logs);
255*b9df5ad1SAndroid Build Coastguard Worker size_t start = 0;
256*b9df5ad1SAndroid Build Coastguard Worker
257*b9df5ad1SAndroid Build Coastguard Worker if (lines > 0) {
258*b9df5ad1SAndroid Build Coastguard Worker // we compute the # of lines per PowerLogBase starting from
259*b9df5ad1SAndroid Build Coastguard Worker // largest time granularity / resolution to the finest resolution.
260*b9df5ad1SAndroid Build Coastguard Worker //
261*b9df5ad1SAndroid Build Coastguard Worker // The largest granularity has the fewest lines, doubling
262*b9df5ad1SAndroid Build Coastguard Worker // as the granularity gets finer.
263*b9df5ad1SAndroid Build Coastguard Worker // The finest 2 levels have identical number of lines.
264*b9df5ad1SAndroid Build Coastguard Worker size_t norm = 1 << (logs - 1);
265*b9df5ad1SAndroid Build Coastguard Worker if (logs > 2) norm += (1 << (logs - 2)) - 1;
266*b9df5ad1SAndroid Build Coastguard Worker size_t alloc = 0;
267*b9df5ad1SAndroid Build Coastguard Worker for (size_t i = 0; i < logs - 1; ++i) {
268*b9df5ad1SAndroid Build Coastguard Worker const size_t l = (1 << i) * lines / norm;
269*b9df5ad1SAndroid Build Coastguard Worker if (l == 0) {
270*b9df5ad1SAndroid Build Coastguard Worker start = i + 1;
271*b9df5ad1SAndroid Build Coastguard Worker } else {
272*b9df5ad1SAndroid Build Coastguard Worker sublines[i] = l;
273*b9df5ad1SAndroid Build Coastguard Worker alloc += l;
274*b9df5ad1SAndroid Build Coastguard Worker }
275*b9df5ad1SAndroid Build Coastguard Worker }
276*b9df5ad1SAndroid Build Coastguard Worker sublines[logs - 1] = lines - alloc;
277*b9df5ad1SAndroid Build Coastguard Worker }
278*b9df5ad1SAndroid Build Coastguard Worker
279*b9df5ad1SAndroid Build Coastguard Worker // Our PowerLogBase vector is stored from finest granularity / resolution to largest
280*b9df5ad1SAndroid Build Coastguard Worker // granularity. We dump the logs in reverse order (logs - 1 - "index").
281*b9df5ad1SAndroid Build Coastguard Worker std::string s = mBase[logs - 1 - start]->dumpToString(
282*b9df5ad1SAndroid Build Coastguard Worker prefix, sublines[start], limitNs, start == logs - 1 ? logPlot : false);
283*b9df5ad1SAndroid Build Coastguard Worker for (size_t i = start + 1; i < logs; ++i) {
284*b9df5ad1SAndroid Build Coastguard Worker s.append(mBase[logs - 1 - i]->dumpToString(
285*b9df5ad1SAndroid Build Coastguard Worker prefix, sublines[i], limitNs, i == logs - 1 ? logPlot : false));
286*b9df5ad1SAndroid Build Coastguard Worker }
287*b9df5ad1SAndroid Build Coastguard Worker return s;
288*b9df5ad1SAndroid Build Coastguard Worker }
289*b9df5ad1SAndroid Build Coastguard Worker
dump(int fd,const char * prefix,size_t lines,int64_t limitNs,bool logPlot) const290*b9df5ad1SAndroid Build Coastguard Worker status_t PowerLog::dump(
291*b9df5ad1SAndroid Build Coastguard Worker int fd, const char *prefix, size_t lines, int64_t limitNs, bool logPlot) const
292*b9df5ad1SAndroid Build Coastguard Worker {
293*b9df5ad1SAndroid Build Coastguard Worker // Since dumpToString and write are thread safe, this function
294*b9df5ad1SAndroid Build Coastguard Worker // is conceptually thread-safe but simultaneous calls to dump
295*b9df5ad1SAndroid Build Coastguard Worker // by different threads to the same file descriptor may not write
296*b9df5ad1SAndroid Build Coastguard Worker // the two logs in time order.
297*b9df5ad1SAndroid Build Coastguard Worker const std::string s = dumpToString(prefix, lines, limitNs, logPlot);
298*b9df5ad1SAndroid Build Coastguard Worker if (s.size() > 0 && write(fd, s.c_str(), s.size()) < 0) {
299*b9df5ad1SAndroid Build Coastguard Worker return -errno;
300*b9df5ad1SAndroid Build Coastguard Worker }
301*b9df5ad1SAndroid Build Coastguard Worker return NO_ERROR;
302*b9df5ad1SAndroid Build Coastguard Worker }
303*b9df5ad1SAndroid Build Coastguard Worker
304*b9df5ad1SAndroid Build Coastguard Worker } // namespace android
305*b9df5ad1SAndroid Build Coastguard Worker
306*b9df5ad1SAndroid Build Coastguard Worker using namespace android;
307*b9df5ad1SAndroid Build Coastguard Worker
power_log_create(uint32_t sample_rate,uint32_t channel_count,audio_format_t format,size_t entries,size_t frames_per_entry)308*b9df5ad1SAndroid Build Coastguard Worker power_log_t *power_log_create(uint32_t sample_rate,
309*b9df5ad1SAndroid Build Coastguard Worker uint32_t channel_count, audio_format_t format, size_t entries, size_t frames_per_entry)
310*b9df5ad1SAndroid Build Coastguard Worker {
311*b9df5ad1SAndroid Build Coastguard Worker if (!audio_utils_is_compute_power_format_supported(format)) {
312*b9df5ad1SAndroid Build Coastguard Worker return nullptr;
313*b9df5ad1SAndroid Build Coastguard Worker }
314*b9df5ad1SAndroid Build Coastguard Worker return reinterpret_cast<power_log_t *>
315*b9df5ad1SAndroid Build Coastguard Worker (new(std::nothrow)
316*b9df5ad1SAndroid Build Coastguard Worker PowerLog(sample_rate, channel_count, format, entries, frames_per_entry));
317*b9df5ad1SAndroid Build Coastguard Worker }
318*b9df5ad1SAndroid Build Coastguard Worker
power_log_log(power_log_t * power_log,const void * buffer,size_t frames,int64_t now_ns)319*b9df5ad1SAndroid Build Coastguard Worker void power_log_log(power_log_t *power_log,
320*b9df5ad1SAndroid Build Coastguard Worker const void *buffer, size_t frames, int64_t now_ns)
321*b9df5ad1SAndroid Build Coastguard Worker {
322*b9df5ad1SAndroid Build Coastguard Worker if (power_log == nullptr) {
323*b9df5ad1SAndroid Build Coastguard Worker return;
324*b9df5ad1SAndroid Build Coastguard Worker }
325*b9df5ad1SAndroid Build Coastguard Worker reinterpret_cast<PowerLog *>(power_log)->log(buffer, frames, now_ns);
326*b9df5ad1SAndroid Build Coastguard Worker }
327*b9df5ad1SAndroid Build Coastguard Worker
power_log_dump(power_log_t * power_log,int fd,const char * prefix,size_t lines,int64_t limit_ns)328*b9df5ad1SAndroid Build Coastguard Worker int power_log_dump(
329*b9df5ad1SAndroid Build Coastguard Worker power_log_t *power_log, int fd, const char *prefix, size_t lines, int64_t limit_ns)
330*b9df5ad1SAndroid Build Coastguard Worker {
331*b9df5ad1SAndroid Build Coastguard Worker if (power_log == nullptr) {
332*b9df5ad1SAndroid Build Coastguard Worker return BAD_VALUE;
333*b9df5ad1SAndroid Build Coastguard Worker }
334*b9df5ad1SAndroid Build Coastguard Worker return reinterpret_cast<PowerLog *>(power_log)->dump(fd, prefix, lines, limit_ns);
335*b9df5ad1SAndroid Build Coastguard Worker }
336*b9df5ad1SAndroid Build Coastguard Worker
power_log_destroy(power_log_t * power_log)337*b9df5ad1SAndroid Build Coastguard Worker void power_log_destroy(power_log_t *power_log)
338*b9df5ad1SAndroid Build Coastguard Worker {
339*b9df5ad1SAndroid Build Coastguard Worker delete reinterpret_cast<PowerLog *>(power_log);
340*b9df5ad1SAndroid Build Coastguard Worker }
341