• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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