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