blob: 498c01af75f9c5cc6229341fa25beaa0dd9254c9 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "performance-domain.h"
#include <fidl/fuchsia.device/cpp/wire.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <iostream>
namespace {
const std::string kDeviceSuffix = "device_protocol";
} // namespace
zx::result<CpuPerformanceDomain> CpuPerformanceDomain::CreateFromPath(const std::string& path) {
std::string device_protocol_path = path + "/" + kDeviceSuffix;
zx::result cpu = component::Connect<cpuctrl::Device>(device_protocol_path);
if (cpu.is_error()) {
return cpu.take_error();
}
return zx::ok(CpuPerformanceDomain(std::move(cpu.value())));
}
std::pair<zx_status_t, uint32_t> CpuPerformanceDomain::GetOperatingPointCount() {
auto resp = cpu_client_->GetOperatingPointCount();
return std::make_pair(resp.status(), resp.status() == ZX_OK ? resp.value()->count : 0);
}
std::pair<zx_status_t, uint64_t> CpuPerformanceDomain::GetNumLogicalCores() {
auto resp = cpu_client_->GetNumLogicalCores();
return std::make_pair(resp.status(), resp.status() == ZX_OK ? resp.value().count : 0);
}
std::tuple<zx_status_t, uint64_t, cpuctrl::wire::CpuOperatingPointInfo>
CpuPerformanceDomain::GetCurrentOperatingPoint() {
constexpr cpuctrl::wire::CpuOperatingPointInfo kEmptyOpp = {
.frequency_hz = cpuctrl::wire::kFrequencyUnknown,
.voltage_uv = cpuctrl::wire::kVoltageUnknown,
};
auto resp = cpu_client_->GetCurrentOperatingPoint();
if (resp.status() != ZX_OK) {
return std::make_tuple(resp.status(), 0, kEmptyOpp);
}
const auto [status, opps] = GetOperatingPoints();
if (status != ZX_OK) {
return std::make_tuple(status, 0, kEmptyOpp);
}
uint64_t current_opp = resp.value().out_opp;
cpuctrl::wire::CpuOperatingPointInfo opp_result = kEmptyOpp;
if (current_opp >= opps.size()) {
std::cerr << "No description for current opp." << std::endl;
} else {
opp_result = opps[current_opp];
}
return std::make_tuple(ZX_OK, current_opp, opp_result);
}
std::tuple<zx_status_t, const std::vector<cpuctrl::wire::CpuOperatingPointInfo>&>
CpuPerformanceDomain::GetOperatingPoints() {
// If we've already fetched this in the past, there's no need to fetch again.
if (!cached_opps_.empty()) {
return std::make_tuple(ZX_OK, std::ref(cached_opps_));
}
auto opp_count_resp = cpu_client_->GetOperatingPointCount();
if (opp_count_resp.status() != ZX_OK) {
std::cerr << "GetOperatingPointCount failed with error: " << opp_count_resp.status()
<< std::endl;
return std::make_tuple(opp_count_resp.status(), std::ref(cached_opps_));
}
if (opp_count_resp->is_error()) {
std::cerr << "GetOperatingPointCount failed with error: " << opp_count_resp->error_value()
<< std::endl;
return std::make_tuple(opp_count_resp->error_value(), std::ref(cached_opps_));
}
for (uint32_t i = 0; i < opp_count_resp->value()->count; i++) {
auto resp = cpu_client_->GetOperatingPointInfo(i);
if (resp.status() != ZX_OK || resp->is_error()) {
continue;
}
cached_opps_.push_back(resp->value()->info);
}
return std::make_tuple(ZX_OK, std::ref(cached_opps_));
}
zx_status_t CpuPerformanceDomain::SetCurrentOperatingPoint(uint32_t new_opp) {
auto result = cpu_client_->SetCurrentOperatingPoint(new_opp);
if (result.status() != ZX_OK) {
return result.status();
}
if (result->is_error()) {
return result->error_value();
}
if (result->value()->out_opp != new_opp) {
return ZX_ERR_INTERNAL;
}
return ZX_OK;
}