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 #define LOG_TAG "powerhal-libperfmgr"
18 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
19 
20 #include "GpuCapacityNode.h"
21 
22 #include <android-base/logging.h>
23 #include <utils/Trace.h>
24 
25 #include <charconv>
26 
27 #include "perfmgr/HintManager.h"
28 
29 namespace aidl {
30 namespace google {
31 namespace hardware {
32 namespace power {
33 namespace impl {
34 namespace pixel {
35 
~GpuCapacityNode()36 GpuCapacityNode::~GpuCapacityNode() {
37     fd_interface_->close(frequency_fd_);
38     fd_interface_->close(capacity_headroom_fd_);
39 }
40 
GpuCapacityNode(std::unique_ptr<FdInterface> fd_interface,int validated_capacity_headroom_fd,int validated_frequency_fd,std::string_view node_path)41 GpuCapacityNode::GpuCapacityNode(std::unique_ptr<FdInterface> fd_interface,
42                                  int validated_capacity_headroom_fd, int validated_frequency_fd,
43                                  std::string_view node_path)
44     : fd_interface_(std::move(fd_interface)),
45       capacity_node_path_(node_path),
46       capacity_headroom_fd_(validated_capacity_headroom_fd),
47       frequency_fd_(validated_frequency_fd) {
48     if (capacity_headroom_fd_ < 0) {
49         LOG(FATAL) << ("precondition violation for GpuCapacityNode: invalid capacity_headroom_fd_");
50     }
51     if (frequency_fd_ < 0) {
52         LOG(FATAL) << ("precondition violation for GpuCapacityNode: invalid frequency_fd_");
53     }
54 }
55 
init_gpu_capacity_node(std::unique_ptr<FdInterface> fd_interface,std::string_view gpu_node_dir)56 std::unique_ptr<GpuCapacityNode> GpuCapacityNode::init_gpu_capacity_node(
57         std::unique_ptr<FdInterface> fd_interface, std::string_view gpu_node_dir) {
58     static constexpr auto fd_flags_common = O_CLOEXEC | O_NONBLOCK;
59     auto const capacity_headroom_file = std::string(gpu_node_dir) + "/capacity_headroom";
60     auto const capacity_headroom_fd =
61             fd_interface->open(capacity_headroom_file.c_str(), O_RDWR | fd_flags_common);
62     if (capacity_headroom_fd < 0) {
63         LOG(ERROR) << "could not open gpu capacity path: " << capacity_headroom_file << ": "
64                    << strerror(errno);
65         return nullptr;
66     }
67     auto const gpu_freq_file = std::string(gpu_node_dir) + "/cur_freq";
68     auto const frequency_fd = fd_interface->open(gpu_freq_file.c_str(), O_RDONLY | fd_flags_common);
69     if (frequency_fd < 0) {
70         fd_interface->close(capacity_headroom_fd);
71         LOG(ERROR) << "could not open gpu capacity path: " << gpu_freq_file << ": "
72                    << strerror(errno);
73         return nullptr;
74     }
75     return std::make_unique<GpuCapacityNode>(std::move(fd_interface), capacity_headroom_fd,
76                                              frequency_fd, gpu_node_dir);
77 }
78 
set_gpu_capacity(Cycles capacity) const79 bool GpuCapacityNode::set_gpu_capacity(Cycles capacity) const {
80     std::lock_guard lk(capacity_mutex_);
81     auto const capacity_str = std::to_string(static_cast<int>(capacity));
82     ATRACE_INT("gpuCapacitySet", static_cast<int>(static_cast<int>(capacity)));
83     auto const rc =
84             fd_interface_->write(capacity_headroom_fd_, capacity_str.c_str(), capacity_str.size());
85     if (!rc) {
86         LOG(ERROR) << "could not write to capacity node: " << capacity_node_path_ << ": "
87                    << strerror(errno);
88     }
89     return !rc;
90 }
91 
gpu_frequency() const92 std::optional<Frequency> GpuCapacityNode::gpu_frequency() const {
93     std::lock_guard lk(freq_mutex_);
94     std::array<char, 16> buffer;
95     buffer.fill('\0');
96 
97     ssize_t bytes_read_total = 0;
98     size_t const effective_size = buffer.size() - 1;
99     do {
100         auto const bytes_read = fd_interface_->read(frequency_fd_, buffer.data() + bytes_read_total,
101                                                     effective_size - bytes_read_total);
102         if (bytes_read == 0) {
103             break;
104         }
105 
106         if (bytes_read < 0) {
107             LOG(ERROR) << "could not read gpu frequency:" << bytes_read << ": " << strerror(errno);
108             return {};
109         }
110         bytes_read_total += bytes_read;
111     } while (bytes_read_total < effective_size);
112 
113     auto const rc = fd_interface_->lseek(frequency_fd_, 0, SEEK_SET);
114     if (rc < 0) {
115         LOG(ERROR) << "could not seek gpu frequency file: " << strerror(errno);
116         return {};
117     }
118 
119     int frequency_raw = 0;
120     auto [ptr, ec] = std::from_chars(buffer.data(), buffer.data() + buffer.size(), frequency_raw);
121     if (ec != std::errc() || frequency_raw <= 0) {
122         LOG(ERROR) << "could not parse gpu frequency" << buffer.data();
123         return {};
124     }
125 
126     auto const frequency = Frequency(frequency_raw * 1000);
127     ATRACE_INT("gpuRecordedFreq", static_cast<int>(frequency));
128     return frequency;
129 }
130 
createGpuCapacityNode()131 std::optional<std::unique_ptr<GpuCapacityNode>> createGpuCapacityNode() {
132     auto const path = ::android::perfmgr::HintManager::GetInstance()->gpu_sysfs_config_path();
133     if (!path) {
134         return {};
135     }
136     return {GpuCapacityNode::init_gpu_capacity_node(std::make_unique<FdWriter>(), *path)};
137 }
138 
139 }  // namespace pixel
140 }  // namespace impl
141 }  // namespace power
142 }  // namespace hardware
143 }  // namespace google
144 }  // namespace aidl
145