blob: c8b36d8c2955efa82f8d41895d14eed8f9a8d0cf [file] [log] [blame]
Andy Hungc747c532022-03-07 21:41:14 -08001/*
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>
Andy Hung224f82f2022-03-22 00:00:49 -070022#include <vector>
Andy Hungc747c532022-03-07 21:41:14 -080023
24#include <android-base/thread_annotations.h>
25#include <audio_utils/Statistics.h>
26
27namespace 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 */
39template <typename Code>
40class MethodStatistics {
41public:
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 */
Andy Hunga7733682022-07-08 17:19:46 -070058 template <typename C>
59 void event(C&& code, FloatType executeMs) {
Andy Hungc747c532022-03-07 21:41:14 -080060 std::lock_guard lg(mLock);
Andy Hunga7733682022-07-08 17:19:46 -070061 auto it = mStatisticsMap.lower_bound(code);
Andy Hung71ba4b32022-10-06 12:09:49 -070062 if (it != mStatisticsMap.end() && it->first == static_cast<Code>(code)) {
Andy Hunga7733682022-07-08 17:19:46 -070063 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 }
Andy Hungc747c532022-03-07 21:41:14 -080069 }
70
71 /**
72 * Returns the name for the method code.
73 */
Andy Hunga7733682022-07-08 17:19:46 -070074 std::string getMethodForCode(const Code& code) const {
Andy Hungc747c532022-03-07 21:41:14 -080075 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 */
Andy Hunga7733682022-07-08 17:19:46 -070082 size_t getMethodCount(const Code& code) const {
Andy Hungc747c532022-03-07 21:41:14 -080083 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 */
Andy Hunga7733682022-07-08 17:19:46 -070091 StatsType getStatistics(const Code& code) const {
Andy Hungc747c532022-03-07 21:41:14 -080092 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 */
100 std::string dump() const {
101 std::stringstream ss;
102 std::lock_guard lg(mLock);
Andy Hung224f82f2022-03-22 00:00:49 -0700103 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 }
Andy Hungc747c532022-03-07 21:41:14 -0800113 }
114 return ss.str();
115 }
116
117private:
Andy Hunga7733682022-07-08 17:19:46 -0700118 // Note: we use a transparent comparator std::less<> for heterogeneous key lookup.
119 const std::map<Code, std::string, std::less<>> mMethodMap;
Andy Hungc747c532022-03-07 21:41:14 -0800120 mutable std::mutex mLock;
Andy Hunga7733682022-07-08 17:19:46 -0700121 std::map<Code, StatsType, std::less<>> mStatisticsMap GUARDED_BY(mLock);
Andy Hungc747c532022-03-07 21:41:14 -0800122};
123
Andy Hung224f82f2022-03-22 00:00:49 -0700124// 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.
129std::shared_ptr<std::vector<std::string>>
130getStatisticsClassesForModule(std::string_view moduleName);
131
132// Returns a statistics object for that class, or a nullptr if class not found.
133std::shared_ptr<MethodStatistics<std::string>>
134getStatisticsForClass(std::string_view className);
135
Andy Hungc747c532022-03-07 21:41:14 -0800136// 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