136 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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 "powerhal-adaptivecpu"
 | |
| #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
 | |
| 
 | |
| #include "KernelCpuFeatureReader.h"
 | |
| 
 | |
| #include <android-base/logging.h>
 | |
| #include <utils/Trace.h>
 | |
| 
 | |
| #include <ostream>
 | |
| 
 | |
| namespace aidl {
 | |
| namespace google {
 | |
| namespace hardware {
 | |
| namespace power {
 | |
| namespace impl {
 | |
| namespace pixel {
 | |
| 
 | |
| constexpr std::string_view kKernelFilePath("/proc/vendor_sched/acpu_stats");
 | |
| constexpr size_t kReadBufferSize = sizeof(acpu_stats) * NUM_CPU_CORES;
 | |
| 
 | |
| bool KernelCpuFeatureReader::Init() {
 | |
|     ATRACE_CALL();
 | |
|     if (!OpenStatsFile(&mStatsFile)) {
 | |
|         return false;
 | |
|     }
 | |
|     return ReadStats(&mPreviousStats, &mPreviousReadTime);
 | |
| }
 | |
| 
 | |
| bool KernelCpuFeatureReader::GetRecentCpuFeatures(
 | |
|         std::array<double, NUM_CPU_POLICIES> *cpuPolicyAverageFrequencyHz,
 | |
|         std::array<double, NUM_CPU_CORES> *cpuCoreIdleTimesPercentage) {
 | |
|     ATRACE_CALL();
 | |
|     std::array<acpu_stats, NUM_CPU_CORES> stats;
 | |
|     std::chrono::nanoseconds readTime;
 | |
|     if (!ReadStats(&stats, &readTime)) {
 | |
|         return false;
 | |
|     }
 | |
|     const std::chrono::nanoseconds timeDelta = readTime - mPreviousReadTime;
 | |
| 
 | |
|     for (size_t i = 0; i < NUM_CPU_POLICIES; i++) {
 | |
|         // acpu_stats has data per-CPU, but frequency data is equivalent for all CPUs in a policy.
 | |
|         // So, we only read the first CPU in each policy.
 | |
|         const size_t statsIdx = CPU_POLICY_INDICES[i];
 | |
|         if (stats[statsIdx].weighted_sum_freq < mPreviousStats[statsIdx].weighted_sum_freq) {
 | |
|             LOG(WARNING) << "New weighted_sum_freq is less than old: new="
 | |
|                          << stats[statsIdx].weighted_sum_freq
 | |
|                          << ", old=" << mPreviousStats[statsIdx].weighted_sum_freq;
 | |
|             mPreviousStats[statsIdx].weighted_sum_freq = stats[statsIdx].weighted_sum_freq;
 | |
|         }
 | |
|         (*cpuPolicyAverageFrequencyHz)[i] =
 | |
|                 static_cast<double>(stats[statsIdx].weighted_sum_freq -
 | |
|                                     mPreviousStats[statsIdx].weighted_sum_freq) /
 | |
|                 timeDelta.count();
 | |
|     }
 | |
|     for (size_t i = 0; i < NUM_CPU_CORES; i++) {
 | |
|         if (stats[i].total_idle_time_ns < mPreviousStats[i].total_idle_time_ns) {
 | |
|             LOG(WARNING) << "New total_idle_time_ns is less than old: new="
 | |
|                          << stats[i].total_idle_time_ns
 | |
|                          << ", old=" << mPreviousStats[i].total_idle_time_ns;
 | |
|             mPreviousStats[i].total_idle_time_ns = stats[i].total_idle_time_ns;
 | |
|         }
 | |
|         (*cpuCoreIdleTimesPercentage)[i] =
 | |
|                 static_cast<double>(stats[i].total_idle_time_ns -
 | |
|                                     mPreviousStats[i].total_idle_time_ns) /
 | |
|                 timeDelta.count();
 | |
|     }
 | |
| 
 | |
|     mPreviousStats = stats;
 | |
|     mPreviousReadTime = readTime;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool KernelCpuFeatureReader::OpenStatsFile(std::unique_ptr<std::istream> *file) {
 | |
|     ATRACE_CALL();
 | |
|     return mFilesystem->ReadFileStream(kKernelFilePath.data(), file);
 | |
| }
 | |
| 
 | |
| bool KernelCpuFeatureReader::ReadStats(std::array<acpu_stats, NUM_CPU_CORES> *stats,
 | |
|                                        std::chrono::nanoseconds *readTime) {
 | |
|     ATRACE_CALL();
 | |
|     *readTime = mTimeSource->GetKernelTime();
 | |
|     if (!mFilesystem->ResetFileStream(mStatsFile)) {
 | |
|         return false;
 | |
|     }
 | |
|     char buffer[kReadBufferSize];
 | |
|     {
 | |
|         ATRACE_NAME("read");
 | |
|         if (!mStatsFile->read(buffer, kReadBufferSize).good()) {
 | |
|             LOG(ERROR) << "Failed to read stats file";
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
|     const size_t bytesRead = mStatsFile->gcount();
 | |
|     if (bytesRead != kReadBufferSize) {
 | |
|         LOG(ERROR) << "Didn't read full data: expected=" << kReadBufferSize
 | |
|                    << ", actual=" << bytesRead;
 | |
|         return false;
 | |
|     }
 | |
|     const auto kernelStructs = reinterpret_cast<acpu_stats *>(buffer);
 | |
|     std::copy(kernelStructs, kernelStructs + NUM_CPU_CORES, stats->begin());
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| void KernelCpuFeatureReader::DumpToStream(std::ostream &stream) const {
 | |
|     ATRACE_CALL();
 | |
|     stream << "CPU features from acpu_stats:\n";
 | |
|     for (size_t i = 0; i < NUM_CPU_CORES; i++) {
 | |
|         stream << "- CPU " << i << ": weighted_sum_freq=" << mPreviousStats[i].weighted_sum_freq
 | |
|                << ", total_idle_time_ns=" << mPreviousStats[i].total_idle_time_ns << "\n";
 | |
|     }
 | |
|     stream << "- Last read time: " << mPreviousReadTime.count() << "ns\n";
 | |
| }
 | |
| 
 | |
| }  // namespace pixel
 | |
| }  // namespace impl
 | |
| }  // namespace power
 | |
| }  // namespace hardware
 | |
| }  // namespace google
 | |
| }  // namespace aidl
 |