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 #define LOG_TAG "powerhal-adaptivecpu"
18 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
19
20 #include "KernelCpuFeatureReader.h"
21
22 #include <android-base/logging.h>
23 #include <utils/Trace.h>
24
25 #include <ostream>
26
27 namespace aidl {
28 namespace google {
29 namespace hardware {
30 namespace power {
31 namespace impl {
32 namespace pixel {
33
34 constexpr std::string_view kKernelFilePath("/proc/vendor_sched/acpu_stats");
35 constexpr size_t kReadBufferSize = sizeof(acpu_stats) * NUM_CPU_CORES;
36
Init()37 bool KernelCpuFeatureReader::Init() {
38 ATRACE_CALL();
39 if (!OpenStatsFile(&mStatsFile)) {
40 return false;
41 }
42 return ReadStats(&mPreviousStats, &mPreviousReadTime);
43 }
44
GetRecentCpuFeatures(std::array<double,NUM_CPU_POLICIES> * cpuPolicyAverageFrequencyHz,std::array<double,NUM_CPU_CORES> * cpuCoreIdleTimesPercentage)45 bool KernelCpuFeatureReader::GetRecentCpuFeatures(
46 std::array<double, NUM_CPU_POLICIES> *cpuPolicyAverageFrequencyHz,
47 std::array<double, NUM_CPU_CORES> *cpuCoreIdleTimesPercentage) {
48 ATRACE_CALL();
49 std::array<acpu_stats, NUM_CPU_CORES> stats;
50 std::chrono::nanoseconds readTime;
51 if (!ReadStats(&stats, &readTime)) {
52 return false;
53 }
54 const std::chrono::nanoseconds timeDelta = readTime - mPreviousReadTime;
55
56 for (size_t i = 0; i < NUM_CPU_POLICIES; i++) {
57 // acpu_stats has data per-CPU, but frequency data is equivalent for all CPUs in a policy.
58 // So, we only read the first CPU in each policy.
59 const size_t statsIdx = CPU_POLICY_INDICES[i];
60 if (stats[statsIdx].weighted_sum_freq < mPreviousStats[statsIdx].weighted_sum_freq) {
61 LOG(WARNING) << "New weighted_sum_freq is less than old: new="
62 << stats[statsIdx].weighted_sum_freq
63 << ", old=" << mPreviousStats[statsIdx].weighted_sum_freq;
64 mPreviousStats[statsIdx].weighted_sum_freq = stats[statsIdx].weighted_sum_freq;
65 }
66 (*cpuPolicyAverageFrequencyHz)[i] =
67 static_cast<double>(stats[statsIdx].weighted_sum_freq -
68 mPreviousStats[statsIdx].weighted_sum_freq) /
69 timeDelta.count();
70 }
71 for (size_t i = 0; i < NUM_CPU_CORES; i++) {
72 if (stats[i].total_idle_time_ns < mPreviousStats[i].total_idle_time_ns) {
73 LOG(WARNING) << "New total_idle_time_ns is less than old: new="
74 << stats[i].total_idle_time_ns
75 << ", old=" << mPreviousStats[i].total_idle_time_ns;
76 mPreviousStats[i].total_idle_time_ns = stats[i].total_idle_time_ns;
77 }
78 (*cpuCoreIdleTimesPercentage)[i] =
79 static_cast<double>(stats[i].total_idle_time_ns -
80 mPreviousStats[i].total_idle_time_ns) /
81 timeDelta.count();
82 }
83
84 mPreviousStats = stats;
85 mPreviousReadTime = readTime;
86 return true;
87 }
88
OpenStatsFile(std::unique_ptr<std::istream> * file)89 bool KernelCpuFeatureReader::OpenStatsFile(std::unique_ptr<std::istream> *file) {
90 ATRACE_CALL();
91 return mFilesystem->ReadFileStream(kKernelFilePath.data(), file);
92 }
93
ReadStats(std::array<acpu_stats,NUM_CPU_CORES> * stats,std::chrono::nanoseconds * readTime)94 bool KernelCpuFeatureReader::ReadStats(std::array<acpu_stats, NUM_CPU_CORES> *stats,
95 std::chrono::nanoseconds *readTime) {
96 ATRACE_CALL();
97 *readTime = mTimeSource->GetKernelTime();
98 if (!mFilesystem->ResetFileStream(mStatsFile)) {
99 return false;
100 }
101 char buffer[kReadBufferSize];
102 {
103 ATRACE_NAME("read");
104 if (!mStatsFile->read(buffer, kReadBufferSize).good()) {
105 LOG(ERROR) << "Failed to read stats file";
106 return false;
107 }
108 }
109 const size_t bytesRead = mStatsFile->gcount();
110 if (bytesRead != kReadBufferSize) {
111 LOG(ERROR) << "Didn't read full data: expected=" << kReadBufferSize
112 << ", actual=" << bytesRead;
113 return false;
114 }
115 const auto kernelStructs = reinterpret_cast<acpu_stats *>(buffer);
116 std::copy(kernelStructs, kernelStructs + NUM_CPU_CORES, stats->begin());
117 return true;
118 }
119
DumpToStream(std::ostream & stream) const120 void KernelCpuFeatureReader::DumpToStream(std::ostream &stream) const {
121 ATRACE_CALL();
122 stream << "CPU features from acpu_stats:\n";
123 for (size_t i = 0; i < NUM_CPU_CORES; i++) {
124 stream << "- CPU " << i << ": weighted_sum_freq=" << mPreviousStats[i].weighted_sum_freq
125 << ", total_idle_time_ns=" << mPreviousStats[i].total_idle_time_ns << "\n";
126 }
127 stream << "- Last read time: " << mPreviousReadTime.count() << "ns\n";
128 }
129
130 } // namespace pixel
131 } // namespace impl
132 } // namespace power
133 } // namespace hardware
134 } // namespace google
135 } // namespace aidl
136