xref: /aosp_15_r20/system/media/audio_utils/PowerLog.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
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