blob: 2543dfa2da3052eaf23ed5e937ef4cf0f22f5708 [file] [log] [blame]
/*
* Copyright (C) 2022 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.
*/
#pragma once
#include <map>
#include <mutex>
#include <string>
#include <vector>
#include <android-base/thread_annotations.h>
#include <audio_utils/Statistics.h>
namespace android::mediautils {
/**
* MethodStatistics is used to associate Binder codes
* with a method name and execution time statistics.
*
* This is used to track binder transaction times for
* AudioFlinger and AudioPolicy services.
*
* Here, Code is the enumeration type for the method
* lookup.
*/
template <typename Code>
class MethodStatistics {
public:
using FloatType = float;
using StatsType = audio_utils::Statistics<FloatType>;
/**
* Method statistics.
*
* Initialized with the Binder transaction list for tracking AudioFlinger
* and AudioPolicyManager execution statistics.
*/
explicit MethodStatistics(
const std::initializer_list<std::pair<const Code, std::string>>& methodMap = {})
: mMethodMap{methodMap} {}
/**
* Adds a method event, typically execution time in ms.
*/
template <typename C>
void event(C&& code, FloatType executeMs) {
std::lock_guard lg(mLock);
auto it = mStatisticsMap.lower_bound(code);
if (it != mStatisticsMap.end() && it->first == static_cast<Code>(code)) {
it->second.add(executeMs);
} else {
// StatsType ctor takes an optional array of data for initialization.
FloatType dataArray[1] = { executeMs };
mStatisticsMap.emplace_hint(it, std::forward<C>(code), dataArray);
}
}
/**
* Returns the name for the method code.
*/
std::string getMethodForCode(const Code& code) const {
auto it = mMethodMap.find(code);
return it == mMethodMap.end() ? std::to_string((int)code) : it->second;
}
/**
* Returns the number of times the method was invoked by event().
*/
size_t getMethodCount(const Code& code) const {
std::lock_guard lg(mLock);
auto it = mStatisticsMap.find(code);
return it == mStatisticsMap.end() ? 0 : it->second.getN();
}
/**
* Returns the statistics object for the method.
*/
StatsType getStatistics(const Code& code) const {
std::lock_guard lg(mLock);
auto it = mStatisticsMap.find(code);
return it == mStatisticsMap.end() ? StatsType{} : it->second;
}
/**
* Dumps the current method statistics.
*/
std::string dump() const {
std::stringstream ss;
std::lock_guard lg(mLock);
if constexpr (std::is_same_v<Code, std::string>) {
for (const auto &[code, stats] : mStatisticsMap) {
ss << code <<
" n=" << stats.getN() << " " << stats.toString() << "\n";
}
} else /* constexpr */ {
for (const auto &[code, stats] : mStatisticsMap) {
ss << int(code) << " " << getMethodForCode(code) <<
" n=" << stats.getN() << " " << stats.toString() << "\n";
}
}
return ss.str();
}
private:
// Note: we use a transparent comparator std::less<> for heterogeneous key lookup.
const std::map<Code, std::string, std::less<>> mMethodMap;
mutable std::mutex mLock;
std::map<Code, StatsType, std::less<>> mStatisticsMap GUARDED_BY(mLock);
};
// Managed Statistics support.
// Supported Modules
#define METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL "AudioHidl"
#define METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL "AudioAidl"
// Returns a vector of class names for the module, or a nullptr if module not found.
std::shared_ptr<std::vector<std::string>>
getStatisticsClassesForModule(std::string_view moduleName);
// Returns a statistics object for that class, or a nullptr if class not found.
std::shared_ptr<MethodStatistics<std::string>>
getStatisticsForClass(std::string_view className);
// Only if used, requires IBinder.h to be included at the location of invocation.
#define METHOD_STATISTICS_BINDER_CODE_NAMES(CODE_TYPE) \
{(CODE_TYPE)IBinder::PING_TRANSACTION , "ping"}, \
{(CODE_TYPE)IBinder::DUMP_TRANSACTION , "dump"}, \
{(CODE_TYPE)IBinder::SHELL_COMMAND_TRANSACTION , "shellCommand"}, \
{(CODE_TYPE)IBinder::INTERFACE_TRANSACTION , "getInterfaceDescriptor"}, \
{(CODE_TYPE)IBinder::SYSPROPS_TRANSACTION , "SYSPROPS_TRANSACTION"}, \
{(CODE_TYPE)IBinder::EXTENSION_TRANSACTION , "EXTENSION_TRANSACTION"}, \
{(CODE_TYPE)IBinder::DEBUG_PID_TRANSACTION , "DEBUG_PID_TRANSACTION"}, \
} // android::mediautils