xref: /aosp_15_r20/frameworks/av/services/audioflinger/datapath/ThreadMetrics.h (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #pragma once
18*ec779b8eSAndroid Build Coastguard Worker 
19*ec779b8eSAndroid Build Coastguard Worker #include <media/MediaMetricsItem.h>
20*ec779b8eSAndroid Build Coastguard Worker 
21*ec779b8eSAndroid Build Coastguard Worker #include <mutex>
22*ec779b8eSAndroid Build Coastguard Worker 
23*ec779b8eSAndroid Build Coastguard Worker namespace android {
24*ec779b8eSAndroid Build Coastguard Worker 
25*ec779b8eSAndroid Build Coastguard Worker /**
26*ec779b8eSAndroid Build Coastguard Worker  * ThreadMetrics handles the AudioFlinger thread log statistics.
27*ec779b8eSAndroid Build Coastguard Worker  *
28*ec779b8eSAndroid Build Coastguard Worker  * We aggregate metrics for a particular device for proper analysis.
29*ec779b8eSAndroid Build Coastguard Worker  * This includes power, performance, and usage metrics.
30*ec779b8eSAndroid Build Coastguard Worker  *
31*ec779b8eSAndroid Build Coastguard Worker  * This class is thread-safe with a lock for safety.  There is no risk of deadlock
32*ec779b8eSAndroid Build Coastguard Worker  * as this class only executes external one-way calls in Mediametrics and does not
33*ec779b8eSAndroid Build Coastguard Worker  * call any other AudioFlinger class.
34*ec779b8eSAndroid Build Coastguard Worker  *
35*ec779b8eSAndroid Build Coastguard Worker  * Terminology:
36*ec779b8eSAndroid Build Coastguard Worker  * An AudioInterval is a contiguous playback segment.
37*ec779b8eSAndroid Build Coastguard Worker  * An AudioIntervalGroup is a group of continuous playback segments on the same device.
38*ec779b8eSAndroid Build Coastguard Worker  *
39*ec779b8eSAndroid Build Coastguard Worker  * We currently deliver metrics based on an AudioIntervalGroup.
40*ec779b8eSAndroid Build Coastguard Worker  */
41*ec779b8eSAndroid Build Coastguard Worker class ThreadMetrics final {
42*ec779b8eSAndroid Build Coastguard Worker public:
ThreadMetrics(std::string metricsId,bool isOut)43*ec779b8eSAndroid Build Coastguard Worker     ThreadMetrics(std::string metricsId, bool isOut)
44*ec779b8eSAndroid Build Coastguard Worker         : mMetricsId(std::move(metricsId))
45*ec779b8eSAndroid Build Coastguard Worker         , mIsOut(isOut)
46*ec779b8eSAndroid Build Coastguard Worker         {}
47*ec779b8eSAndroid Build Coastguard Worker 
~ThreadMetrics()48*ec779b8eSAndroid Build Coastguard Worker     ~ThreadMetrics() {
49*ec779b8eSAndroid Build Coastguard Worker         logEndInterval(); // close any open interval groups
50*ec779b8eSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
51*ec779b8eSAndroid Build Coastguard Worker         deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
52*ec779b8eSAndroid Build Coastguard Worker         mediametrics::LogItem(mMetricsId)
53*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
54*ec779b8eSAndroid Build Coastguard Worker             .record();
55*ec779b8eSAndroid Build Coastguard Worker     }
56*ec779b8eSAndroid Build Coastguard Worker 
57*ec779b8eSAndroid Build Coastguard Worker     // Called under the following circumstances
58*ec779b8eSAndroid Build Coastguard Worker     // 1) Upon a createPatch and we are not in standby
59*ec779b8eSAndroid Build Coastguard Worker     // 2) We come out of standby
logBeginInterval()60*ec779b8eSAndroid Build Coastguard Worker     void logBeginInterval() {
61*ec779b8eSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
62*ec779b8eSAndroid Build Coastguard Worker         // The devices we look for change depend on whether the Thread is input or output.
63*ec779b8eSAndroid Build Coastguard Worker         const std::string& patchDevices = mIsOut ? mCreatePatchOutDevices : mCreatePatchInDevices;
64*ec779b8eSAndroid Build Coastguard Worker         if (mDevices != patchDevices) {
65*ec779b8eSAndroid Build Coastguard Worker             deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
66*ec779b8eSAndroid Build Coastguard Worker             mDevices = patchDevices; // set after endAudioIntervalGroup
67*ec779b8eSAndroid Build Coastguard Worker             resetIntervalGroupMetrics();
68*ec779b8eSAndroid Build Coastguard Worker             deliverDeviceMetrics(
69*ec779b8eSAndroid Build Coastguard Worker                     AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, mDevices.c_str());
70*ec779b8eSAndroid Build Coastguard Worker         }
71*ec779b8eSAndroid Build Coastguard Worker         if (mIntervalStartTimeNs == 0) {
72*ec779b8eSAndroid Build Coastguard Worker             ++mIntervalCount;
73*ec779b8eSAndroid Build Coastguard Worker             mIntervalStartTimeNs = systemTime();
74*ec779b8eSAndroid Build Coastguard Worker         }
75*ec779b8eSAndroid Build Coastguard Worker     }
76*ec779b8eSAndroid Build Coastguard Worker 
logConstructor(pid_t pid,const char * threadType,int32_t id)77*ec779b8eSAndroid Build Coastguard Worker     void logConstructor(pid_t pid, const char *threadType, int32_t id) const {
78*ec779b8eSAndroid Build Coastguard Worker         mediametrics::LogItem(mMetricsId)
79*ec779b8eSAndroid Build Coastguard Worker             .setPid(pid)
80*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
81*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_TYPE, threadType)
82*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_THREADID, id)
83*ec779b8eSAndroid Build Coastguard Worker             .record();
84*ec779b8eSAndroid Build Coastguard Worker     }
85*ec779b8eSAndroid Build Coastguard Worker 
logCreatePatch(const std::string & inDevices,const std::string & outDevices)86*ec779b8eSAndroid Build Coastguard Worker     void logCreatePatch(const std::string& inDevices, const std::string& outDevices) {
87*ec779b8eSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
88*ec779b8eSAndroid Build Coastguard Worker         mCreatePatchInDevices = inDevices;
89*ec779b8eSAndroid Build Coastguard Worker         mCreatePatchOutDevices = outDevices;
90*ec779b8eSAndroid Build Coastguard Worker         mediametrics::LogItem(mMetricsId)
91*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
92*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_INPUTDEVICES, inDevices)
93*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, outDevices)
94*ec779b8eSAndroid Build Coastguard Worker             .record();
95*ec779b8eSAndroid Build Coastguard Worker     }
96*ec779b8eSAndroid Build Coastguard Worker 
97*ec779b8eSAndroid Build Coastguard Worker     // Called when we are removed from the Thread.
logEndInterval()98*ec779b8eSAndroid Build Coastguard Worker     void logEndInterval() {
99*ec779b8eSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
100*ec779b8eSAndroid Build Coastguard Worker         if (mIntervalStartTimeNs != 0) {
101*ec779b8eSAndroid Build Coastguard Worker             const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
102*ec779b8eSAndroid Build Coastguard Worker             mIntervalStartTimeNs = 0;
103*ec779b8eSAndroid Build Coastguard Worker             mCumulativeTimeNs += elapsedTimeNs;
104*ec779b8eSAndroid Build Coastguard Worker             mDeviceTimeNs += elapsedTimeNs;
105*ec779b8eSAndroid Build Coastguard Worker         }
106*ec779b8eSAndroid Build Coastguard Worker     }
107*ec779b8eSAndroid Build Coastguard Worker 
logThrottleMs(double throttleMs)108*ec779b8eSAndroid Build Coastguard Worker     void logThrottleMs(double throttleMs) const {
109*ec779b8eSAndroid Build Coastguard Worker         mediametrics::LogItem(mMetricsId)
110*ec779b8eSAndroid Build Coastguard Worker             // ms units always double
111*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_THROTTLEMS, (double)throttleMs)
112*ec779b8eSAndroid Build Coastguard Worker             .record();
113*ec779b8eSAndroid Build Coastguard Worker     }
114*ec779b8eSAndroid Build Coastguard Worker 
logLatency(double latencyMs)115*ec779b8eSAndroid Build Coastguard Worker     void logLatency(double latencyMs) {
116*ec779b8eSAndroid Build Coastguard Worker         mediametrics::LogItem(mMetricsId)
117*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
118*ec779b8eSAndroid Build Coastguard Worker             .record();
119*ec779b8eSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
120*ec779b8eSAndroid Build Coastguard Worker         mDeviceLatencyMs.add(latencyMs);
121*ec779b8eSAndroid Build Coastguard Worker     }
122*ec779b8eSAndroid Build Coastguard Worker 
logUnderrunFrames(size_t frames)123*ec779b8eSAndroid Build Coastguard Worker     void logUnderrunFrames(size_t frames) {
124*ec779b8eSAndroid Build Coastguard Worker         std::lock_guard l(mLock);
125*ec779b8eSAndroid Build Coastguard Worker         if (mLastUnderrun == false && frames > 0) {
126*ec779b8eSAndroid Build Coastguard Worker             ++mUnderrunCount; // count non-continguous underrun sequences.
127*ec779b8eSAndroid Build Coastguard Worker         }
128*ec779b8eSAndroid Build Coastguard Worker         mLastUnderrun = (frames > 0);
129*ec779b8eSAndroid Build Coastguard Worker         mUnderrunFrames += frames;
130*ec779b8eSAndroid Build Coastguard Worker     }
131*ec779b8eSAndroid Build Coastguard Worker 
getMetricsId()132*ec779b8eSAndroid Build Coastguard Worker     const std::string& getMetricsId() const {
133*ec779b8eSAndroid Build Coastguard Worker         return mMetricsId;
134*ec779b8eSAndroid Build Coastguard Worker     }
135*ec779b8eSAndroid Build Coastguard Worker 
136*ec779b8eSAndroid Build Coastguard Worker private:
137*ec779b8eSAndroid Build Coastguard Worker     // no lock required - all arguments and constants.
deliverDeviceMetrics(const char * eventName,const char * devices)138*ec779b8eSAndroid Build Coastguard Worker     void deliverDeviceMetrics(const char *eventName, const char *devices) const {
139*ec779b8eSAndroid Build Coastguard Worker         mediametrics::LogItem(mMetricsId)
140*ec779b8eSAndroid Build Coastguard Worker             .set(AMEDIAMETRICS_PROP_EVENT, eventName)
141*ec779b8eSAndroid Build Coastguard Worker             .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
142*ec779b8eSAndroid Build Coastguard Worker                    : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
143*ec779b8eSAndroid Build Coastguard Worker            .record();
144*ec779b8eSAndroid Build Coastguard Worker     }
145*ec779b8eSAndroid Build Coastguard Worker 
deliverCumulativeMetrics(const char * eventName)146*ec779b8eSAndroid Build Coastguard Worker     void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
147*ec779b8eSAndroid Build Coastguard Worker         if (mIntervalCount > 0) {
148*ec779b8eSAndroid Build Coastguard Worker             mediametrics::LogItem item(mMetricsId);
149*ec779b8eSAndroid Build Coastguard Worker             item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
150*ec779b8eSAndroid Build Coastguard Worker                 .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
151*ec779b8eSAndroid Build Coastguard Worker                 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
152*ec779b8eSAndroid Build Coastguard Worker                 .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount)
153*ec779b8eSAndroid Build Coastguard Worker                 // we set "last" device to indicate the device the group was
154*ec779b8eSAndroid Build Coastguard Worker                 // associated with (because a createPatch which is logged in ThreadMetrics
155*ec779b8eSAndroid Build Coastguard Worker                 // could have changed the device).
156*ec779b8eSAndroid Build Coastguard Worker                 .set(mIsOut
157*ec779b8eSAndroid Build Coastguard Worker                         ? AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_OUTPUTDEVICES
158*ec779b8eSAndroid Build Coastguard Worker                         : AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_INPUTDEVICES,
159*ec779b8eSAndroid Build Coastguard Worker                         mDevices.c_str());
160*ec779b8eSAndroid Build Coastguard Worker             if (mDeviceLatencyMs.getN() > 0) {
161*ec779b8eSAndroid Build Coastguard Worker                 item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean());
162*ec779b8eSAndroid Build Coastguard Worker             }
163*ec779b8eSAndroid Build Coastguard Worker             if (mUnderrunCount > 0) {
164*ec779b8eSAndroid Build Coastguard Worker                 item.set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t)mUnderrunCount)
165*ec779b8eSAndroid Build Coastguard Worker                     .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES, (int64_t)mUnderrunFrames);
166*ec779b8eSAndroid Build Coastguard Worker             }
167*ec779b8eSAndroid Build Coastguard Worker             item.record();
168*ec779b8eSAndroid Build Coastguard Worker         }
169*ec779b8eSAndroid Build Coastguard Worker     }
170*ec779b8eSAndroid Build Coastguard Worker 
resetIntervalGroupMetrics()171*ec779b8eSAndroid Build Coastguard Worker     void resetIntervalGroupMetrics() REQUIRES(mLock) {
172*ec779b8eSAndroid Build Coastguard Worker         // mDevices is not reset by clear
173*ec779b8eSAndroid Build Coastguard Worker 
174*ec779b8eSAndroid Build Coastguard Worker         mIntervalCount = 0;
175*ec779b8eSAndroid Build Coastguard Worker         mIntervalStartTimeNs = 0;
176*ec779b8eSAndroid Build Coastguard Worker         // mCumulativeTimeNs is not reset by clear.
177*ec779b8eSAndroid Build Coastguard Worker         mDeviceTimeNs = 0;
178*ec779b8eSAndroid Build Coastguard Worker 
179*ec779b8eSAndroid Build Coastguard Worker         mDeviceLatencyMs.reset();
180*ec779b8eSAndroid Build Coastguard Worker 
181*ec779b8eSAndroid Build Coastguard Worker         mLastUnderrun = false;
182*ec779b8eSAndroid Build Coastguard Worker         mUnderrunCount = 0;
183*ec779b8eSAndroid Build Coastguard Worker         mUnderrunFrames = 0;
184*ec779b8eSAndroid Build Coastguard Worker     }
185*ec779b8eSAndroid Build Coastguard Worker 
186*ec779b8eSAndroid Build Coastguard Worker     const std::string mMetricsId;
187*ec779b8eSAndroid Build Coastguard Worker     const bool        mIsOut;  // if true, than a playback track, otherwise used for record.
188*ec779b8eSAndroid Build Coastguard Worker 
189*ec779b8eSAndroid Build Coastguard Worker     mutable           std::mutex mLock;
190*ec779b8eSAndroid Build Coastguard Worker 
191*ec779b8eSAndroid Build Coastguard Worker     // Devices in the interval group.
192*ec779b8eSAndroid Build Coastguard Worker     std::string       mDevices GUARDED_BY(mLock); // last input or output devices based on mIsOut.
193*ec779b8eSAndroid Build Coastguard Worker     std::string       mCreatePatchInDevices GUARDED_BY(mLock);
194*ec779b8eSAndroid Build Coastguard Worker     std::string       mCreatePatchOutDevices GUARDED_BY(mLock);
195*ec779b8eSAndroid Build Coastguard Worker 
196*ec779b8eSAndroid Build Coastguard Worker     // Number of intervals and playing time
197*ec779b8eSAndroid Build Coastguard Worker     int32_t           mIntervalCount GUARDED_BY(mLock) = 0;
198*ec779b8eSAndroid Build Coastguard Worker     int64_t           mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
199*ec779b8eSAndroid Build Coastguard Worker     int64_t           mCumulativeTimeNs GUARDED_BY(mLock) = 0;
200*ec779b8eSAndroid Build Coastguard Worker     int64_t           mDeviceTimeNs GUARDED_BY(mLock) = 0;
201*ec779b8eSAndroid Build Coastguard Worker 
202*ec779b8eSAndroid Build Coastguard Worker     // latency and startup for each interval.
203*ec779b8eSAndroid Build Coastguard Worker     audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
204*ec779b8eSAndroid Build Coastguard Worker 
205*ec779b8eSAndroid Build Coastguard Worker     // underrun count and frames
206*ec779b8eSAndroid Build Coastguard Worker     bool              mLastUnderrun GUARDED_BY(mLock) = false; // checks consecutive underruns
207*ec779b8eSAndroid Build Coastguard Worker     int64_t           mUnderrunCount GUARDED_BY(mLock) = 0;    // number of consecutive underruns
208*ec779b8eSAndroid Build Coastguard Worker     int64_t           mUnderrunFrames GUARDED_BY(mLock) = 0;   // total estimated frames underrun
209*ec779b8eSAndroid Build Coastguard Worker };
210*ec779b8eSAndroid Build Coastguard Worker 
211*ec779b8eSAndroid Build Coastguard Worker } // namespace android
212