1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <map> 20 #include <mutex> 21 #include <string> 22 #include <vector> 23 24 #include <android-base/thread_annotations.h> 25 #include <audio_utils/Statistics.h> 26 27 namespace android::mediautils { 28 29 /** 30 * MethodStatistics is used to associate Binder codes 31 * with a method name and execution time statistics. 32 * 33 * This is used to track binder transaction times for 34 * AudioFlinger and AudioPolicy services. 35 * 36 * Here, Code is the enumeration type for the method 37 * lookup. 38 */ 39 template <typename Code> 40 class MethodStatistics { 41 public: 42 using FloatType = float; 43 using StatsType = audio_utils::Statistics<FloatType>; 44 45 /** 46 * Method statistics. 47 * 48 * Initialized with the Binder transaction list for tracking AudioFlinger 49 * and AudioPolicyManager execution statistics. 50 */ 51 explicit MethodStatistics( 52 const std::initializer_list<std::pair<const Code, std::string>>& methodMap = {}) 53 : mMethodMap{methodMap} {} 54 55 /** 56 * Adds a method event, typically execution time in ms. 57 */ 58 template <typename C> event(C && code,FloatType executeMs)59 void event(C&& code, FloatType executeMs) { 60 std::lock_guard lg(mLock); 61 auto it = mStatisticsMap.lower_bound(code); 62 if (it != mStatisticsMap.end() && it->first == code) { 63 it->second.add(executeMs); 64 } else { 65 // StatsType ctor takes an optional array of data for initialization. 66 FloatType dataArray[1] = { executeMs }; 67 mStatisticsMap.emplace_hint(it, std::forward<C>(code), dataArray); 68 } 69 } 70 71 /** 72 * Returns the name for the method code. 73 */ getMethodForCode(const Code & code)74 std::string getMethodForCode(const Code& code) const { 75 auto it = mMethodMap.find(code); 76 return it == mMethodMap.end() ? std::to_string((int)code) : it->second; 77 } 78 79 /** 80 * Returns the number of times the method was invoked by event(). 81 */ getMethodCount(const Code & code)82 size_t getMethodCount(const Code& code) const { 83 std::lock_guard lg(mLock); 84 auto it = mStatisticsMap.find(code); 85 return it == mStatisticsMap.end() ? 0 : it->second.getN(); 86 } 87 88 /** 89 * Returns the statistics object for the method. 90 */ getStatistics(const Code & code)91 StatsType getStatistics(const Code& code) const { 92 std::lock_guard lg(mLock); 93 auto it = mStatisticsMap.find(code); 94 return it == mStatisticsMap.end() ? StatsType{} : it->second; 95 } 96 97 /** 98 * Dumps the current method statistics. 99 */ dump()100 std::string dump() const { 101 std::stringstream ss; 102 std::lock_guard lg(mLock); 103 if constexpr (std::is_same_v<Code, std::string>) { 104 for (const auto &[code, stats] : mStatisticsMap) { 105 ss << code << 106 " n=" << stats.getN() << " " << stats.toString() << "\n"; 107 } 108 } else /* constexpr */ { 109 for (const auto &[code, stats] : mStatisticsMap) { 110 ss << int(code) << " " << getMethodForCode(code) << 111 " n=" << stats.getN() << " " << stats.toString() << "\n"; 112 } 113 } 114 return ss.str(); 115 } 116 117 private: 118 // Note: we use a transparent comparator std::less<> for heterogeneous key lookup. 119 const std::map<Code, std::string, std::less<>> mMethodMap; 120 mutable std::mutex mLock; 121 std::map<Code, StatsType, std::less<>> mStatisticsMap GUARDED_BY(mLock); 122 }; 123 124 // Managed Statistics support. 125 // Supported Modules 126 #define METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL "AudioHidl" 127 128 // Returns a vector of class names for the module, or a nullptr if module not found. 129 std::shared_ptr<std::vector<std::string>> 130 getStatisticsClassesForModule(std::string_view moduleName); 131 132 // Returns a statistics object for that class, or a nullptr if class not found. 133 std::shared_ptr<MethodStatistics<std::string>> 134 getStatisticsForClass(std::string_view className); 135 136 // Only if used, requires IBinder.h to be included at the location of invocation. 137 #define METHOD_STATISTICS_BINDER_CODE_NAMES(CODE_TYPE) \ 138 {(CODE_TYPE)IBinder::PING_TRANSACTION , "ping"}, \ 139 {(CODE_TYPE)IBinder::DUMP_TRANSACTION , "dump"}, \ 140 {(CODE_TYPE)IBinder::SHELL_COMMAND_TRANSACTION , "shellCommand"}, \ 141 {(CODE_TYPE)IBinder::INTERFACE_TRANSACTION , "getInterfaceDescriptor"}, \ 142 {(CODE_TYPE)IBinder::SYSPROPS_TRANSACTION , "SYSPROPS_TRANSACTION"}, \ 143 {(CODE_TYPE)IBinder::EXTENSION_TRANSACTION , "EXTENSION_TRANSACTION"}, \ 144 {(CODE_TYPE)IBinder::DEBUG_PID_TRANSACTION , "DEBUG_PID_TRANSACTION"}, \ 145 146 } // android::mediautils 147