MediaUtils: Add ScopedStatistics for effect tuning
Used for performance tuning of Spatial audio.
Test: adb shell dumpsys media.audio_flinger
Test: atest mediautils_scopedstatistics_tests
Bug: 228862341
Change-Id: I914a4cf9815d49fa413c19cc562a3e1101a4ced2
diff --git a/media/utils/include/mediautils/ScopedStatistics.h b/media/utils/include/mediautils/ScopedStatistics.h
new file mode 100644
index 0000000..c5fc1e9
--- /dev/null
+++ b/media/utils/include/mediautils/ScopedStatistics.h
@@ -0,0 +1,81 @@
+/*
+ * 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 "MethodStatistics.h"
+#include <chrono>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace android::mediautils {
+
+class ScopedStatistics {
+ public:
+ /**
+ * ScopedStatistics is a RAII way of obtaining
+ * execution time statistics for a scoped C++ block.
+ *
+ * It updates the MethodStatistics shared pointer parameter
+ * with the methodName parameter and the duration/lifetime of the
+ * ScopedStatistics object.
+ *
+ * Not thread-safe, but expected to run in a single execution
+ * thread, and there are no user serviceable parts exposed.
+ *
+ * Example:
+ *
+ * std::shared_ptr<mediautils::MethodStatistics<std::string>> stats =
+ * std::make_shared<mediautils::MethodStatistics<std::string>>();
+ *
+ * // ...
+ * {
+ * mediautils::ScopedStatistics scopedStatistics("MyClass:myMethod", stats);
+ *
+ * // some work to be timed here - up to the end of the block.
+ * }
+ *
+ * \param methodName the methodname to use "ClassName::methodName"
+ * \param statistics a shared ptr to the MethodStatistics object to use.
+ */
+ ScopedStatistics(std::string methodName,
+ std::shared_ptr<mediautils::MethodStatistics<std::string>> statistics)
+ : mMethodName{std::move(methodName)}
+ , mStatistics{std::move(statistics)}
+ , mBegin{std::chrono::steady_clock::now()} {}
+
+ // No copy constructor.
+ ScopedStatistics(const ScopedStatistics& scopedStatistics) = delete;
+ ScopedStatistics& operator=(const ScopedStatistics& scopedStatistics) = delete;
+
+ ~ScopedStatistics() {
+ if (mStatistics) {
+ const float elapsedMs = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now() - mBegin)
+ .count() *
+ 1e-6; // ns to ms.
+ mStatistics->event(mMethodName, elapsedMs);
+ }
+ }
+
+ private:
+ const std::string mMethodName;
+ const std::shared_ptr<mediautils::MethodStatistics<std::string>> mStatistics;
+ const std::chrono::steady_clock::time_point mBegin;
+};
+
+} // namespace android::mediautils
diff --git a/media/utils/tests/Android.bp b/media/utils/tests/Android.bp
index a6f408d..1024018 100644
--- a/media/utils/tests/Android.bp
+++ b/media/utils/tests/Android.bp
@@ -124,6 +124,27 @@
}
cc_test {
+ name: "mediautils_scopedstatistics_tests",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "liblog",
+ "libmediautils",
+ "libutils",
+ ],
+
+ srcs: [
+ "mediautils_scopedstatistics_tests.cpp",
+ ],
+}
+
+cc_test {
name: "methodstatistics_tests",
cflags: [
diff --git a/media/utils/tests/mediautils_scopedstatistics_tests.cpp b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
new file mode 100644
index 0000000..807ce63
--- /dev/null
+++ b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "mediautils_scopedstatistics_tests"
+
+#include <mediautils/ScopedStatistics.h>
+
+#include <atomic>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <thread>
+#include <utils/Log.h>
+
+using namespace android::mediautils;
+using namespace std::chrono_literals;
+
+TEST(mediautils_scopedstatistics_tests, basic) {
+ auto methodStatistics = std::make_shared<MethodStatistics<std::string>>();
+ std::string METHOD_NAME{"MyMethod"};
+
+ // no stats before
+ auto empty = methodStatistics->getStatistics(METHOD_NAME);
+ ASSERT_EQ(0, empty.getN());
+
+ // create a scoped statistics object.
+ {
+ ScopedStatistics scopedStatistics(METHOD_NAME, methodStatistics);
+
+ std::this_thread::sleep_for(100ms);
+ }
+
+ // check that some stats were logged.
+ auto stats = methodStatistics->getStatistics(METHOD_NAME);
+ ASSERT_EQ(1, stats.getN());
+ auto mean = stats.getMean();
+
+ // mean should be about 100ms, but to avoid false failures,
+ // we check 50ms < mean < 300ms.
+ ASSERT_GT(mean, 50.); // took more than 50ms.
+ ASSERT_LT(mean, 300.); // took less than 300ms.
+}