blob: a0ea912bcc7782c700e02bd593836e61910200e4 [file] [log] [blame]
/*
* Copyright (C) 2024 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.
*/
#include "GpuCapacityNode.h"
#define LOG_TAG "powerhal-libperfmgr"
#include <android-base/logging.h>
#include <charconv>
namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {
GpuCapacityNode::~GpuCapacityNode() {
fd_interface_->close(frequency_fd_);
fd_interface_->close(capacity_headroom_fd_);
}
GpuCapacityNode::GpuCapacityNode(std::unique_ptr<FdInterface> fd_interface,
int validated_capacity_headroom_fd, int validated_frequency_fd,
std::string_view node_path)
: fd_interface_(std::move(fd_interface)),
capacity_node_path_(node_path),
capacity_headroom_fd_(validated_capacity_headroom_fd),
frequency_fd_(validated_frequency_fd) {
if (capacity_headroom_fd_ < 0) {
LOG(FATAL) << ("precondition violation for GpuCapacityNode: invalid capacity_headroom_fd_");
}
if (frequency_fd_ < 0) {
LOG(FATAL) << ("precondition violation for GpuCapacityNode: invalid frequency_fd_");
}
}
std::unique_ptr<GpuCapacityNode> GpuCapacityNode::init_gpu_capacity_node(
std::unique_ptr<FdInterface> fd_interface, std::string_view gpu_node_dir) {
static constexpr auto fd_flags_common = O_CLOEXEC | O_NONBLOCK;
auto const capacity_headroom_file = std::string(gpu_node_dir) + "/capacity_headroom";
auto const capacity_headroom_fd =
fd_interface->open(capacity_headroom_file.c_str(), O_RDWR | fd_flags_common);
if (capacity_headroom_fd < 0) {
LOG(ERROR) << "could not open gpu capacity path: " << capacity_headroom_file << ": "
<< strerror(errno);
return nullptr;
}
auto const gpu_freq_file = std::string(gpu_node_dir) + "/cur_freq";
auto const frequency_fd = fd_interface->open(gpu_freq_file.c_str(), O_RDONLY | fd_flags_common);
if (frequency_fd < 0) {
fd_interface->close(capacity_headroom_fd);
LOG(ERROR) << "could not open gpu capacity path: " << gpu_freq_file << ": "
<< strerror(errno);
return nullptr;
}
return std::make_unique<GpuCapacityNode>(std::move(fd_interface), capacity_headroom_fd,
frequency_fd, gpu_node_dir);
}
bool GpuCapacityNode::set_gpu_capacity(Cycles capacity) const {
std::lock_guard lk(capacity_mutex_);
auto const capacity_str = std::to_string(static_cast<int>(capacity));
auto const rc =
fd_interface_->write(capacity_headroom_fd_, capacity_str.c_str(), capacity_str.size());
if (!rc) {
LOG(ERROR) << "could not write to capacity node: " << capacity_node_path_ << ": "
<< strerror(errno);
}
return !rc;
}
std::optional<Frequency> GpuCapacityNode::gpu_frequency() const {
std::lock_guard lk(freq_mutex_);
std::array<char, 16> buffer;
buffer.fill('\0');
ssize_t bytes_read_total = 0;
size_t const effective_size = buffer.size() - 1;
do {
auto const bytes_read = fd_interface_->read(frequency_fd_, buffer.data() + bytes_read_total,
effective_size - bytes_read_total);
if (bytes_read == 0) {
break;
}
if (bytes_read < 0) {
LOG(ERROR) << "could not read gpu frequency:" << bytes_read << ": " << strerror(errno);
return {};
}
bytes_read_total += bytes_read;
} while (bytes_read_total < effective_size);
auto const rc = fd_interface_->lseek(frequency_fd_, 0, SEEK_SET);
if (rc < 0) {
LOG(ERROR) << "could not seek gpu frequency file: " << strerror(errno);
return {};
}
int frequency_raw = 0;
auto [ptr, ec] = std::from_chars(buffer.data(), buffer.data() + buffer.size(), frequency_raw);
if (ec != std::errc() || frequency_raw <= 0) {
LOG(ERROR) << "could not parse gpu frequency" << buffer.data();
return {};
}
return Frequency(frequency_raw * 1000);
}
} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl