/* ** ** Copyright 2023, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "ResourceManagerMetrics" #include #include #include #include "UidObserver.h" #include "ResourceManagerMetrics.h" #include #include namespace android { using stats::media_metrics::stats_write; using stats::media_metrics::MEDIA_CODEC_STARTED; using stats::media_metrics::MEDIA_CODEC_STOPPED; // Disabling this for now. #ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED using stats::media_metrics::MEDIA_CODEC_CONCURRENT_USAGE_REPORTED; #endif using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED; using stats::media_metrics::MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS; using stats::media_metrics::\ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS; using stats::media_metrics::\ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES; using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED; using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_AUDIO; using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_VIDEO; using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_IMAGE; // Map MediaResourceSubType to stats::media_metrics::CodecType inline int32_t getMetricsCodecType(MediaResourceSubType codecType) { switch (codecType) { case MediaResourceSubType::kHwAudioCodec: case MediaResourceSubType::kSwAudioCodec: return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_AUDIO; case MediaResourceSubType::kHwVideoCodec: case MediaResourceSubType::kSwVideoCodec: return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_VIDEO; case MediaResourceSubType::kHwImageCodec: case MediaResourceSubType::kSwImageCodec: return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_IMAGE; case MediaResourceSubType::kUnspecifiedSubType: return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED; } return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED; } inline const char* getCodecType(MediaResourceSubType codecType) { switch (codecType) { case MediaResourceSubType::kHwAudioCodec: return "Hw Audio"; case MediaResourceSubType::kSwAudioCodec: return "Sw Audio"; case MediaResourceSubType::kHwVideoCodec: return "Hw Video"; case MediaResourceSubType::kSwVideoCodec: return "Sw Video"; case MediaResourceSubType::kHwImageCodec: return "Hw Image"; case MediaResourceSubType::kSwImageCodec: return "Sw Image"; case MediaResourceSubType::kUnspecifiedSubType: default: return "Unspecified"; } return "Unspecified"; } inline bool isHardwareCodec(MediaResourceSubType codecType) { return (codecType == MediaResourceSubType::kHwAudioCodec || codecType == MediaResourceSubType::kHwVideoCodec || codecType == MediaResourceSubType::kHwImageCodec); } static CodecBucket getCodecBucket(bool isEncoder, MediaResourceSubType codecType) { switch (codecType) { case MediaResourceSubType::kHwAudioCodec: return isEncoder? HwAudioEncoder : HwAudioDecoder; case MediaResourceSubType::kSwAudioCodec: return isEncoder? SwAudioEncoder : SwAudioDecoder; case MediaResourceSubType::kHwVideoCodec: return isEncoder? HwVideoEncoder : HwVideoDecoder; case MediaResourceSubType::kSwVideoCodec: return isEncoder? SwVideoEncoder : SwVideoDecoder; case MediaResourceSubType::kHwImageCodec: return isEncoder? HwImageEncoder : HwImageDecoder; case MediaResourceSubType::kSwImageCodec: return isEncoder? SwImageEncoder : SwImageDecoder; case MediaResourceSubType::kUnspecifiedSubType: default: return CodecBucketUnspecified; } return CodecBucketUnspecified; } static std::string getLogMessage(const std::string& firstKey, const long& firstValue, const std::string& secondKey, const long& secondValue) { std::stringstream logMsg; if (firstValue > 0) { logMsg << firstKey << firstValue; } if (secondValue > 0) { logMsg << secondKey << secondValue; } return logMsg.str(); } ResourceManagerMetrics::ResourceManagerMetrics(const sp& processInfo) { // Create a process termination watcher, with 5seconds of polling frequency. mUidObserver = sp::make(processInfo, [this] (int32_t pid, uid_t uid) { onProcessTerminated(pid, uid); }); mUidObserver->start(); } ResourceManagerMetrics::~ResourceManagerMetrics() { mUidObserver->stop(); } void ResourceManagerMetrics::addPid(int pid, uid_t uid) { if (uid != 0) { std::scoped_lock lock(mLock); mUidObserver->add(pid, uid); } } void ResourceManagerMetrics::notifyClientCreated(const ClientInfoParcel& clientInfo) { std::scoped_lock lock(mLock); // Update the resource instance count. std::map::iterator found = mConcurrentResourceCountMap.find(clientInfo.name); if (found == mConcurrentResourceCountMap.end()) { mConcurrentResourceCountMap[clientInfo.name] = 1; } else { found->second++; } } void ResourceManagerMetrics::notifyClientReleased(const ClientInfoParcel& clientInfo) { bool stopCalled = true; ClientConfigParcel clientConfig; { std::scoped_lock lock(mLock); ClientConfigMap::iterator found = mClientConfigMap.find(clientInfo.id); if (found != mClientConfigMap.end()) { // Release is called without Stop! stopCalled = false; clientConfig = found->second; // Update the timestamp for stopping the codec. clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL; } } if (!stopCalled) { // call Stop to update the metrics. notifyClientStopped(clientConfig); } { std::scoped_lock lock(mLock); // Update the resource instance count also. std::map::iterator found = mConcurrentResourceCountMap.find(clientInfo.name); if (found != mConcurrentResourceCountMap.end()) { if (found->second > 0) { found->second--; } } } } void ResourceManagerMetrics::notifyClientConfigChanged(const ClientConfigParcel& clientConfig) { std::scoped_lock lock(mLock); ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id); if (entry != mClientConfigMap.end() && (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec || clientConfig.codecType == MediaResourceSubType::kSwVideoCodec || clientConfig.codecType == MediaResourceSubType::kHwImageCodec || clientConfig.codecType == MediaResourceSubType::kSwImageCodec)) { int pid = clientConfig.clientInfo.pid; // Update the pixel count for this process updatePixelCount(pid, clientConfig.width * (long)clientConfig.height, entry->second.width * (long)entry->second.height); // Update the resolution in the record. entry->second.width = clientConfig.width; entry->second.height = clientConfig.height; } } void ResourceManagerMetrics::notifyClientStarted(const ClientConfigParcel& clientConfig) { std::scoped_lock lock(mLock); int pid = clientConfig.clientInfo.pid; // We need to observer this process. mUidObserver->add(pid, clientConfig.clientInfo.uid); // Update the client config for thic client. mClientConfigMap[clientConfig.clientInfo.id] = clientConfig; // Update the concurrent codec count for this process. CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType); increaseConcurrentCodecs(pid, codecBucket); if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec || clientConfig.codecType == MediaResourceSubType::kSwVideoCodec || clientConfig.codecType == MediaResourceSubType::kHwImageCodec || clientConfig.codecType == MediaResourceSubType::kSwImageCodec) { // Update the pixel count for this process increasePixelCount(pid, clientConfig.width * (long)clientConfig.height); } // System concurrent codec usage int systemConcurrentCodecs = mConcurrentCodecsMap[codecBucket]; // Process/Application concurrent codec usage for this type of codec const ConcurrentCodecs& concurrentCodecs = mProcessConcurrentCodecsMap[pid]; int appConcurrentCodecs = concurrentCodecs.mCurrent[codecBucket]; int hwVideoCodecs = concurrentCodecs.mHWVideoCodecs; int swVideoCodecs = concurrentCodecs.mSWVideoCodecs; int videoCodecs = concurrentCodecs.mVideoCodecs; int audioCodecs = concurrentCodecs.mAudioCodecs; int imageCodecs = concurrentCodecs.mImageCodecs; // Process/Application's current pixel count. long pixelCount = 0; std::map::iterator it = mProcessPixelsMap.find(pid); if (it != mProcessPixelsMap.end()) { pixelCount = it->second.mCurrent; } int result = stats_write( MEDIA_CODEC_STARTED, clientConfig.clientInfo.uid, clientConfig.id, clientConfig.clientInfo.name.c_str(), getMetricsCodecType(clientConfig.codecType), clientConfig.isEncoder, isHardwareCodec(clientConfig.codecType), clientConfig.width, clientConfig.height, systemConcurrentCodecs, appConcurrentCodecs, pixelCount, hwVideoCodecs, swVideoCodecs, videoCodecs, audioCodecs, imageCodecs); ALOGV("%s: Pushed MEDIA_CODEC_STARTED atom: " "Process[pid(%d): uid(%d)] " "Codec: [%s: %ju] is %s %s " "Timestamp: %jd " "Resolution: %d x %d " "ConcurrentCodec[%d]={System: %d App: %d} " "AppConcurrentCodecs{Video: %d(HW[%d] SW[%d]) Audio: %d Image: %d} " "result: %d", __func__, pid, clientConfig.clientInfo.uid, clientConfig.clientInfo.name.c_str(), clientConfig.id, getCodecType(clientConfig.codecType), clientConfig.isEncoder? "encoder" : "decoder", clientConfig.timeStamp, clientConfig.width, clientConfig.height, codecBucket, systemConcurrentCodecs, appConcurrentCodecs, videoCodecs, hwVideoCodecs, swVideoCodecs, audioCodecs, imageCodecs, result); } void ResourceManagerMetrics::notifyClientStopped(const ClientConfigParcel& clientConfig) { std::scoped_lock lock(mLock); int pid = clientConfig.clientInfo.pid; // Update the concurrent codec count for this process. CodecBucket codecBucket = getCodecBucket(clientConfig.isEncoder, clientConfig.codecType); decreaseConcurrentCodecs(pid, codecBucket); if (clientConfig.codecType == MediaResourceSubType::kHwVideoCodec || clientConfig.codecType == MediaResourceSubType::kSwVideoCodec || clientConfig.codecType == MediaResourceSubType::kHwImageCodec || clientConfig.codecType == MediaResourceSubType::kSwImageCodec) { // Update the pixel count for this process decreasePixelCount(pid, clientConfig.width * (long)clientConfig.height); } // System concurrent codec usage int systemConcurrentCodecs = mConcurrentCodecsMap[codecBucket]; // Process/Application concurrent codec usage for this type of codec int appConcurrentCodecs = 0; std::map::iterator found = mProcessConcurrentCodecsMap.find(pid); if (found != mProcessConcurrentCodecsMap.end()) { appConcurrentCodecs = found->second.mCurrent[codecBucket]; } // Process/Application's current pixel count. long pixelCount = 0; std::map::iterator it = mProcessPixelsMap.find(pid); if (it != mProcessPixelsMap.end()) { pixelCount = it->second.mCurrent; } // calculate the usageTime as: // MediaCodecStopped.clientConfig.timeStamp - // MediaCodecStarted.clientConfig.timeStamp int64_t usageTime = 0; ClientConfigMap::iterator entry = mClientConfigMap.find(clientConfig.clientInfo.id); if (entry != mClientConfigMap.end()) { usageTime = clientConfig.timeStamp - entry->second.timeStamp; // And we can erase this config now. mClientConfigMap.erase(entry); } else { ALOGW("%s: Start Config is missing!", __func__); } int result = stats_write( MEDIA_CODEC_STOPPED, clientConfig.clientInfo.uid, clientConfig.id, clientConfig.clientInfo.name.c_str(), getMetricsCodecType(clientConfig.codecType), clientConfig.isEncoder, isHardwareCodec(clientConfig.codecType), clientConfig.width, clientConfig.height, systemConcurrentCodecs, appConcurrentCodecs, pixelCount, usageTime); ALOGV("%s: Pushed MEDIA_CODEC_STOPPED atom: " "Process[pid(%d): uid(%d)] " "Codec: [%s: %ju] is %s %s " "Timestamp: %jd Usage time: %jd " "Resolution: %d x %d " "ConcurrentCodec[%d]={System: %d App: %d} " "result: %d", __func__, pid, clientConfig.clientInfo.uid, clientConfig.clientInfo.name.c_str(), clientConfig.id, getCodecType(clientConfig.codecType), clientConfig.isEncoder? "encoder" : "decoder", clientConfig.timeStamp, usageTime, clientConfig.width, clientConfig.height, codecBucket, systemConcurrentCodecs, appConcurrentCodecs, result); } void ResourceManagerMetrics::onProcessTerminated(int32_t pid, uid_t uid) { std::scoped_lock lock(mLock); // post MediaCodecConcurrentUsageReported for this terminated pid. pushConcurrentUsageReport(pid, uid); // Remove all the metrics associated with this process. std::map::iterator it1 = mProcessConcurrentCodecsMap.find(pid); if (it1 != mProcessConcurrentCodecsMap.end()) { mProcessConcurrentCodecsMap.erase(it1); } std::map::iterator it2 = mProcessPixelsMap.find(pid); if (it2 != mProcessPixelsMap.end()) { mProcessPixelsMap.erase(it2); } } void ResourceManagerMetrics::pushConcurrentUsageReport(int32_t pid, uid_t uid) { // Process/Application peak concurrent codec usage std::map::iterator found = mProcessConcurrentCodecsMap.find(pid); if (found == mProcessConcurrentCodecsMap.end()) { ALOGI("%s: No MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom Entry for: " "Application[pid(%d): uid(%d)]", __func__, pid, uid); return; } const ConcurrentCodecsMap& codecsMap = found->second.mPeak; int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder]; int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder]; int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder]; int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder]; int peakHwImageEncoderCount = codecsMap[HwImageEncoder]; int peakHwImageDecoderCount = codecsMap[HwImageDecoder]; int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder]; int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder]; int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder]; int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder]; int peakSwImageEncoderCount = codecsMap[SwImageEncoder]; int peakSwImageDecoderCount = codecsMap[SwImageDecoder]; long peakPixels = 0; std::map::iterator it = mProcessPixelsMap.find(pid); if (it == mProcessPixelsMap.end()) { ALOGI("%s: No Video Codec Entry for Application[pid(%d): uid(%d)]", __func__, pid, uid); } else { peakPixels = it->second.mPeak; } std::string peakPixelsLog("Peak Pixels: " + std::to_string(peakPixels)); std::stringstream peakCodecLog; peakCodecLog << "Peak { "; std::string logMsg; logMsg = getLogMessage(" HW: ", peakHwAudioEncoderCount, " SW: ", peakSwAudioEncoderCount); if (!logMsg.empty()) { peakCodecLog << "AudioEnc[ " << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwAudioDecoderCount, " SW: ", peakSwAudioDecoderCount); if (!logMsg.empty()) { peakCodecLog << "AudioDec[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwVideoEncoderCount, " SW: ", peakSwVideoEncoderCount); if (!logMsg.empty()) { peakCodecLog << "VideoEnc[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwVideoDecoderCount, " SW: ", peakSwVideoDecoderCount); if (!logMsg.empty()) { peakCodecLog << "VideoDec[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwImageEncoderCount, " SW: ", peakSwImageEncoderCount); if (!logMsg.empty()) { peakCodecLog << "ImageEnc[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwImageDecoderCount, " SW: ", peakSwImageDecoderCount); if (!logMsg.empty()) { peakCodecLog << "ImageDec[" << logMsg << " ] "; } peakCodecLog << "}"; #ifdef ENABLE_MEDIA_CODEC_CONCURRENT_USAGE_REPORTED int result = stats_write( MEDIA_CODEC_CONCURRENT_USAGE_REPORTED, uid, peakHwVideoDecoderCount, peakHwVideoEncoderCount, peakSwVideoDecoderCount, peakSwVideoEncoderCount, peakHwAudioDecoderCount, peakHwAudioEncoderCount, peakSwAudioDecoderCount, peakSwAudioEncoderCount, peakHwImageDecoderCount, peakHwImageEncoderCount, peakSwImageDecoderCount, peakSwImageEncoderCount, peakPixels); ALOGI("%s: Pushed MEDIA_CODEC_CONCURRENT_USAGE_REPORTED atom: " "Process[pid(%d): uid(%d)] %s %s result: %d", __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str(), result); #else ALOGI("%s: Concurrent Codec Usage Report for the Process[pid(%d): uid(%d)] is %s %s", __func__, pid, uid, peakCodecLog.str().c_str(), peakPixelsLog.c_str()); #endif } inline void pushReclaimStats(int32_t callingPid, int32_t requesterUid, int requesterPriority, const std::string& clientName, int32_t noOfConcurrentCodecs, int32_t reclaimStatus, int32_t noOfCodecsReclaimed = 0, int32_t targetIndex = -1, int32_t targetClientPid = -1, int32_t targetClientUid = -1, int32_t targetPriority = -1) { // Post the pushed atom int result = stats_write( MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED, requesterUid, requesterPriority, clientName.c_str(), noOfConcurrentCodecs, reclaimStatus, noOfCodecsReclaimed, targetIndex, targetClientUid, targetPriority); ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: " "Requester[pid(%d): uid(%d): priority(%d)] " "Codec: [%s] " "No of concurrent codecs: %d " "Reclaim Status: %d " "No of codecs reclaimed: %d " "Target[%d][pid(%d): uid(%d): priority(%d)] result: %d", __func__, callingPid, requesterUid, requesterPriority, clientName.c_str(), noOfConcurrentCodecs, reclaimStatus, noOfCodecsReclaimed, targetIndex, targetClientPid, targetClientUid, targetPriority, result); } void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo, const std::vector& priorities, const std::vector& targetClients, bool reclaimed) { // Construct the metrics for codec reclaim as a pushed atom. // 1. Information about the requester. // - UID and the priority (oom score) int32_t callingPid = clientInfo.pid; int32_t requesterUid = clientInfo.uid; std::string clientName = clientInfo.name; int requesterPriority = priorities[0]; // 2. Information about the codec. // - Name of the codec requested // - Number of concurrent codecs running. int32_t noOfConcurrentCodecs = 0; std::map::iterator found = mConcurrentResourceCountMap.find(clientName); if (found != mConcurrentResourceCountMap.end()) { noOfConcurrentCodecs = found->second; } // 3. Information about the Reclaim: // - Status of reclaim request // - How many codecs are reclaimed // - For each codecs reclaimed, information of the process that it belonged to: // - UID and the Priority (oom score) int32_t reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_SUCCESS; if (!reclaimed) { if (targetClients.size() == 0) { // No clients to reclaim from reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS; } else { // Couldn't reclaim resources from the clients reclaimStatus = MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES; } } if (targetClients.empty()) { // Push the reclaim atom to stats. pushReclaimStats(callingPid, requesterUid, requesterPriority, clientName, noOfConcurrentCodecs, reclaimStatus); return; } int32_t noOfCodecsReclaimed = targetClients.size(); int32_t targetIndex = 1; for (const ClientInfo& targetClient : targetClients) { int targetPriority = priorities[targetIndex]; // Push the reclaim atom to stats. pushReclaimStats(callingPid, requesterUid, requesterPriority, clientName, noOfConcurrentCodecs, reclaimStatus, noOfCodecsReclaimed, targetIndex, targetClient.mPid, targetClient.mUid, targetPriority); targetIndex++; } } void ResourceManagerMetrics::increaseConcurrentCodecs(int32_t pid, CodecBucket codecBucket) { // Increase the codec usage across the system. mConcurrentCodecsMap[codecBucket]++; // Now update the codec usage for this (pid) process. std::map::iterator found = mProcessConcurrentCodecsMap.find(pid); if (found == mProcessConcurrentCodecsMap.end()) { ConcurrentCodecs codecs; codecs.mCurrent[codecBucket] = 1; codecs.mPeak[codecBucket] = 1; auto added = mProcessConcurrentCodecsMap.emplace(pid, codecs); found = added.first; } else { found->second.mCurrent[codecBucket]++; // Check if it's the peak count for this slot. if (found->second.mPeak[codecBucket] < found->second.mCurrent[codecBucket]) { found->second.mPeak[codecBucket] = found->second.mCurrent[codecBucket]; } } switch (codecBucket) { case HwVideoEncoder: case HwVideoDecoder: case SwVideoEncoder: case SwVideoDecoder: if (codecBucket == HwVideoEncoder || codecBucket == HwVideoDecoder) { found->second.mHWVideoCodecs++; } else { found->second.mSWVideoCodecs++; } found->second.mVideoCodecs++; break; case HwAudioEncoder: case HwAudioDecoder: case SwAudioEncoder: case SwAudioDecoder: found->second.mAudioCodecs++; break; case HwImageEncoder: case HwImageDecoder: case SwImageEncoder: case SwImageDecoder: found->second.mImageCodecs++; break; default: break; } } void ResourceManagerMetrics::decreaseConcurrentCodecs(int32_t pid, CodecBucket codecBucket) { // Decrease the codec usage across the system. if (mConcurrentCodecsMap[codecBucket] > 0) { mConcurrentCodecsMap[codecBucket]--; } // Now update the codec usage for this (pid) process. std::map::iterator found = mProcessConcurrentCodecsMap.find(pid); if (found != mProcessConcurrentCodecsMap.end()) { if (found->second.mCurrent[codecBucket] > 0) { found->second.mCurrent[codecBucket]--; } switch (codecBucket) { case HwVideoEncoder: case HwVideoDecoder: case SwVideoEncoder: case SwVideoDecoder: if (codecBucket == HwVideoEncoder || codecBucket == HwVideoDecoder) { found->second.mHWVideoCodecs--; } else { found->second.mSWVideoCodecs--; } found->second.mVideoCodecs--; break; case HwAudioEncoder: case HwAudioDecoder: case SwAudioEncoder: case SwAudioDecoder: found->second.mAudioCodecs--; break; case HwImageEncoder: case HwImageDecoder: case SwImageEncoder: case SwImageDecoder: found->second.mImageCodecs--; break; default: break; } } } void ResourceManagerMetrics::increasePixelCount(int32_t pid, long pixels) { // Now update the current pixel usage for this (pid) process. std::map::iterator found = mProcessPixelsMap.find(pid); if (found == mProcessPixelsMap.end()) { PixelCount pixelCount {pixels, pixels}; mProcessPixelsMap.emplace(pid, pixelCount); } else { if (__builtin_add_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) { ALOGI("Pixel Count overflow"); return; } // Check if it's the peak count for this slot. if (found->second.mPeak < found->second.mCurrent) { found->second.mPeak = found->second.mCurrent; } } } void ResourceManagerMetrics::updatePixelCount(int32_t pid, long newPixels, long lastPixels) { // Since there is change in resolution, decrease it by last pixels and // increase it by new pixels. decreasePixelCount(pid, lastPixels); increasePixelCount(pid, newPixels); } void ResourceManagerMetrics::decreasePixelCount(int32_t pid, long pixels) { // Now update the current pixel usage for this (pid) process. std::map::iterator found = mProcessPixelsMap.find(pid); if (found != mProcessPixelsMap.end()) { if (found->second.mCurrent < pixels) { found->second.mCurrent = 0; } else { if (__builtin_sub_overflow(found->second.mCurrent, pixels, &found->second.mCurrent)) { ALOGI("Pixel Count overflow"); return; } } } } long ResourceManagerMetrics::getPeakConcurrentPixelCount(int pid) const { std::map::const_iterator found = mProcessPixelsMap.find(pid); if (found != mProcessPixelsMap.end()) { return found->second.mPeak; } return 0; } long ResourceManagerMetrics::getCurrentConcurrentPixelCount(int pid) const { std::map::const_iterator found = mProcessPixelsMap.find(pid); if (found != mProcessPixelsMap.end()) { return found->second.mCurrent; } return 0; } static std::string getConcurrentInstanceCount(const std::map& resourceMap) { if (resourceMap.empty()) { return ""; } std::stringstream concurrentInstanceInfo; for (const auto& [name, count] : resourceMap) { if (count > 0) { concurrentInstanceInfo << " Name: " << name << " Instances: " << count << "\n"; } } std::string info = concurrentInstanceInfo.str(); if (info.empty()) { return ""; } return " Current Concurrent Codec Instances:\n" + info; } static std::string getAppsPixelCount(const std::map& pixelMap) { if (pixelMap.empty()) { return ""; } std::stringstream pixelInfo; for (const auto& [pid, pixelCount] : pixelMap) { std::string logMsg = getLogMessage(" Current Pixels: ", pixelCount.mCurrent, " Peak Pixels: ", pixelCount.mPeak); if (!logMsg.empty()) { pixelInfo << " PID[" << pid << "]: {" << logMsg << " }\n"; } } return " Applications Pixel Usage:\n" + pixelInfo.str(); } static std::string getCodecUsageMetrics(const ConcurrentCodecsMap& codecsMap) { int peakHwAudioEncoderCount = codecsMap[HwAudioEncoder]; int peakHwAudioDecoderCount = codecsMap[HwAudioDecoder]; int peakHwVideoEncoderCount = codecsMap[HwVideoEncoder]; int peakHwVideoDecoderCount = codecsMap[HwVideoDecoder]; int peakHwImageEncoderCount = codecsMap[HwImageEncoder]; int peakHwImageDecoderCount = codecsMap[HwImageDecoder]; int peakSwAudioEncoderCount = codecsMap[SwAudioEncoder]; int peakSwAudioDecoderCount = codecsMap[SwAudioDecoder]; int peakSwVideoEncoderCount = codecsMap[SwVideoEncoder]; int peakSwVideoDecoderCount = codecsMap[SwVideoDecoder]; int peakSwImageEncoderCount = codecsMap[SwImageEncoder]; int peakSwImageDecoderCount = codecsMap[SwImageDecoder]; std::stringstream usageMetrics; std::string logMsg; logMsg = getLogMessage(" HW: ", peakHwAudioEncoderCount, " SW: ", peakSwAudioEncoderCount); if (!logMsg.empty()) { usageMetrics << "AudioEnc[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwAudioDecoderCount, " SW: ", peakSwAudioDecoderCount); if (!logMsg.empty()) { usageMetrics << "AudioDec[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwVideoEncoderCount, " SW: ", peakSwVideoEncoderCount); if (!logMsg.empty()) { usageMetrics << "VideoEnc[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwVideoDecoderCount, " SW: ", peakSwVideoDecoderCount); if (!logMsg.empty()) { usageMetrics << "VideoDec[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwImageEncoderCount, " SW: ", peakSwImageEncoderCount); if (!logMsg.empty()) { usageMetrics << "ImageEnc[" << logMsg << " ] "; } logMsg = getLogMessage(" HW: ", peakHwImageDecoderCount, " SW: ", peakSwImageDecoderCount); if (!logMsg.empty()) { usageMetrics << "ImageDec[" << logMsg << " ] "; } return usageMetrics.str(); } static std::string getAppsCodecUsageMetrics( const std::map& processCodecsMap) { if (processCodecsMap.empty()) { return ""; } std::stringstream codecUsage; std::string info; for (const auto& [pid, codecMap] : processCodecsMap) { codecUsage << " PID[" << pid << "]: "; info = getCodecUsageMetrics(codecMap.mCurrent); if (!info.empty()) { codecUsage << "Current Codec Usage: { " << info << "} "; } info = getCodecUsageMetrics(codecMap.mPeak); if (!info.empty()) { codecUsage << "Peak Codec Usage: { " << info << "}"; } codecUsage << "\n"; } return " Applications Codec Usage:\n" + codecUsage.str(); } std::string ResourceManagerMetrics::dump() const { std::string metricsLog(" Metrics logs:\n"); metricsLog += getConcurrentInstanceCount(mConcurrentResourceCountMap); metricsLog += getAppsPixelCount(mProcessPixelsMap); metricsLog += getAppsCodecUsageMetrics(mProcessConcurrentCodecsMap); return std::move(metricsLog); } } // namespace android