• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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