1 /*
2 * Copyright (C) 2024 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 <audio_utils/threads.h>
20 #include <benchmark/benchmark.h>
21 #include <psh_utils/PowerStats.h>
22 #include <psh_utils/PowerStatsCollector.h>
23
24 #include <future>
25
26 namespace android::media::psh_utils {
27
28 enum CoreClass {
29 CORE_LITTLE,
30 CORE_MID,
31 CORE_BIG,
32 };
33
toString(CoreClass coreClass)34 inline std::string toString(CoreClass coreClass) {
35 switch (coreClass) {
36 case CORE_LITTLE: return "LITTLE";
37 case CORE_MID: return "MID";
38 case CORE_BIG: return "BIG";
39 default: return "UNKNOWN";
40 }
41 }
42
43 /**
44 * A benchmark fixture is used to specify benchmarks that have a custom SetUp() and
45 * TearDown(). This is **required** for performance testing, as a typical benchmark
46 * method **may be called several times** during a run.
47 *
48 * A fixture ensures that SetUp() and TearDown() and the resulting statistics accumulation
49 * is done only once. Note: BENCHMARK(BM_func)->Setup(DoSetup)->Teardown(DoTeardown)
50 * does something similar, but it requires some singleton to contain the state properly.
51 */
52 class PerformanceFixture : public benchmark::Fixture {
53 public:
54 // call this to start the profiling
startProfiler(CoreClass coreClass)55 virtual void startProfiler(CoreClass coreClass) {
56 mCores = android::audio_utils::get_number_cpus();
57 if (mCores == 0) return;
58 mCoreClass = coreClass;
59 std::array<unsigned, 3> coreSelection{0U, mCores / 2 + 1, mCores - 1};
60 mCore = coreSelection[std::min((size_t)coreClass, std::size(coreSelection) - 1)];
61
62 auto& collector = android::media::psh_utils::PowerStatsCollector::getCollector();
63 mStartStats = collector.getStats();
64
65 const pid_t tid = gettid(); // us.
66
67 // Possibly change priority to improve benchmarking
68 // android::audio_utils::set_thread_priority(gettid(), 98);
69
70 android::audio_utils::set_thread_affinity(0 /* pid */, 1 << mCore);
71 }
72
TearDown(benchmark::State & state)73 void TearDown(benchmark::State &state) override {
74 const auto N = state.complexity_length_n();
75 state.counters["N"] = benchmark::Counter(N,
76 benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::OneK::kIs1024);
77 if (mStartStats) {
78 auto& collector = android::media::psh_utils::PowerStatsCollector::getCollector();
79 const auto stopStats = collector.getStats();
80 android::media::psh_utils::PowerStats diff = *stopStats - *mStartStats;
81 auto cpuEnergy = diff.energyFrom("CPU");
82 auto memEnergy = diff.energyFrom("MEM");
83
84 constexpr float kMwToW = 1e-3;
85 state.counters["WCPU"] = benchmark::Counter(std::get<2>(cpuEnergy) * kMwToW,
86 benchmark::Counter::kDefaults,
87 benchmark::Counter::OneK::kIs1000);
88 state.counters["WMem"] = benchmark::Counter(std::get<2>(memEnergy) * kMwToW,
89 benchmark::Counter::kDefaults,
90 benchmark::Counter::OneK::kIs1000);
91 state.counters["JCPU"] = benchmark::Counter(
92 std::get<1>(cpuEnergy) / N / state.iterations(), benchmark::Counter::kDefaults,
93 benchmark::Counter::OneK::kIs1000);
94 state.counters["JMem"] = benchmark::Counter(
95 std::get<1>(memEnergy) / N / state.iterations(), benchmark::Counter::kDefaults,
96 benchmark::Counter::OneK::kIs1000);
97 }
98 }
99
100 protected:
101 // these are only initialized upon startProfiler.
102 unsigned mCores = 0;
103 int mCore = 0;
104 CoreClass mCoreClass = CORE_LITTLE;
105 std::shared_ptr<const android::media::psh_utils::PowerStats> mStartStats;
106 };
107
108 } // namespace android::media::psh_utils
109