• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "CpuLoadReaderSysDevices.h"
21 
22 #include <android-base/logging.h>
23 #include <inttypes.h>
24 #include <utils/Trace.h>
25 
26 #include <fstream>
27 #include <sstream>
28 #include <string>
29 
30 namespace aidl {
31 namespace google {
32 namespace hardware {
33 namespace power {
34 namespace impl {
35 namespace pixel {
36 
getKernelTime()37 std::chrono::nanoseconds getKernelTime() {
38     timespec ts;
39     clock_gettime(CLOCK_MONOTONIC, &ts);
40     return std::chrono::nanoseconds(ts.tv_sec * 1000000000UL + ts.tv_nsec);
41 }
42 
Init()43 bool CpuLoadReaderSysDevices::Init() {
44     mIdleStateNames.clear();
45     if (!ReadIdleStateNames(&mIdleStateNames)) {
46         return false;
47     }
48     return ReadCpuTimes(&mPreviousCpuTimes);
49 }
50 
GetRecentCpuLoads(std::array<double,NUM_CPU_CORES> * cpuCoreIdleTimesPercentage)51 bool CpuLoadReaderSysDevices::GetRecentCpuLoads(
52         std::array<double, NUM_CPU_CORES> *cpuCoreIdleTimesPercentage) {
53     ATRACE_CALL();
54     if (cpuCoreIdleTimesPercentage == nullptr) {
55         LOG(ERROR) << "Got nullptr output in getRecentCpuLoads";
56         return false;
57     }
58     std::array<CpuTime, NUM_CPU_CORES> cpuTimes;
59     if (!ReadCpuTimes(&cpuTimes)) {
60         return false;
61     }
62     if (cpuTimes.empty()) {
63         LOG(ERROR) << "Failed to find any CPU times";
64         return false;
65     }
66     for (size_t cpuId = 0; cpuId < NUM_CPU_CORES; cpuId++) {
67         const auto cpuTime = cpuTimes[cpuId];
68         const auto previousCpuTime = mPreviousCpuTimes[cpuId];
69         auto recentIdleTime = cpuTime.idleTime - previousCpuTime.idleTime;
70         const auto recentTotalTime = cpuTime.totalTime - previousCpuTime.totalTime;
71         if (recentIdleTime > recentTotalTime) {
72             // This happens occasionally, as we use the idle time from the kernel, and the current
73             // time from userspace.
74             recentIdleTime = recentTotalTime;
75         }
76         const double idleTimePercentage =
77                 static_cast<double>(recentIdleTime.count()) / recentTotalTime.count();
78         (*cpuCoreIdleTimesPercentage)[cpuId] = idleTimePercentage;
79     }
80     mPreviousCpuTimes = cpuTimes;
81     return true;
82 }
83 
DumpToStream(std::stringstream & stream) const84 void CpuLoadReaderSysDevices::DumpToStream(std::stringstream &stream) const {
85     stream << "CPU loads from /sys/devices/system/cpu/cpuN/cpuidle:\n";
86     for (size_t cpuId = 0; cpuId < NUM_CPU_CORES; cpuId++) {
87         stream << "- CPU=" << cpuId << ", idleTime=" << mPreviousCpuTimes[cpuId].idleTime.count()
88                << "ms, totalTime=" << mPreviousCpuTimes[cpuId].totalTime.count() << "ms\n";
89     }
90 }
91 
ReadCpuTimes(std::array<CpuTime,NUM_CPU_CORES> * result) const92 bool CpuLoadReaderSysDevices::ReadCpuTimes(std::array<CpuTime, NUM_CPU_CORES> *result) const {
93     ATRACE_CALL();
94     const auto totalTime = mTimeSource->GetTime();
95 
96     for (size_t cpuId = 0; cpuId < NUM_CPU_CORES; cpuId++) {
97         std::chrono::microseconds idleTime;
98         for (const auto &idleStateName : mIdleStateNames) {
99             std::stringstream cpuIdlePath;
100             cpuIdlePath << "/sys/devices/system/cpu/"
101                         << "cpu" << cpuId << "/cpuidle/" << idleStateName << "/time";
102             std::unique_ptr<std::istream> file;
103             if (!mFilesystem->ReadFileStream(cpuIdlePath.str(), &file)) {
104                 return false;
105             }
106             // Times are reported in microseconds:
107             // https://www.kernel.org/doc/Documentation/cpuidle/sysfs.txt
108             std::string idleTimeUs(std::istreambuf_iterator<char>(*file), {});
109             idleTime += std::chrono::microseconds(std::atoi(idleTimeUs.c_str()));
110         }
111         (*result)[cpuId] = {
112                 .idleTime = idleTime,
113                 .totalTime = std::chrono::duration_cast<std::chrono::microseconds>(totalTime),
114         };
115     }
116 
117     return true;
118 }
119 
ReadIdleStateNames(std::vector<std::string> * result) const120 bool CpuLoadReaderSysDevices::ReadIdleStateNames(std::vector<std::string> *result) const {
121     std::vector<std::string> idleStateNames;
122     if (!mFilesystem->ListDirectory("/sys/devices/system/cpu/cpu0/cpuidle", &idleStateNames)) {
123         return false;
124     }
125     for (const auto &idleStateName : idleStateNames) {
126         if (idleStateName.length() == 0 || idleStateName[0] == '.') {
127             continue;
128         }
129         std::vector<std::string> files;
130         if (!mFilesystem->ListDirectory(
131                     std::string("/sys/devices/system/cpu/cpu0/cpuidle/") + idleStateName, &files)) {
132             return false;
133         }
134         if (std::find(files.begin(), files.end(), "time") == files.end()) {
135             continue;
136         }
137         result->push_back(idleStateName);
138     }
139     if (idleStateNames.empty()) {
140         LOG(ERROR) << "Found no idle state names";
141         return false;
142     }
143     return true;
144 }
145 
146 }  // namespace pixel
147 }  // namespace impl
148 }  // namespace power
149 }  // namespace hardware
150 }  // namespace google
151 }  // namespace aidl
152