blob: 404fc2058978d3d258c63208f6bc8e84a55d5ebf [file] [log] [blame]
// Copyright 2019 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 "src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.h"
#include <fcntl.h>
#include <fuchsia/cobalt/cpp/fidl.h>
#include <fuchsia/sysinfo/c/fidl.h>
#include <lib/fdio/fdio.h>
#include <lib/zx/resource.h>
#include <trace/event.h>
#include <zircon/status.h>
#include "src/lib/fxl/logging.h"
namespace cobalt {
CpuStatsFetcherImpl::CpuStatsFetcherImpl() { InitializeRootResourceHandle(); }
bool CpuStatsFetcherImpl::FetchCpuPercentage(double *cpu_percentage) {
TRACE_DURATION("system_metrics", "CpuStatsFetcherImpl::FetchCpuPercentage");
if (FetchCpuStats() == false) {
return false;
}
bool success = CalculateCpuPercentage(cpu_percentage);
last_cpu_stats_.swap(cpu_stats_);
last_cpu_fetch_time_ = cpu_fetch_time_;
return success;
}
bool CpuStatsFetcherImpl::FetchCpuStats() {
if (root_resource_handle_ == ZX_HANDLE_INVALID) {
FXL_LOG(ERROR) << "CpuStatsFetcherImpl: No root resource "
<< "present. Reconnecting...";
InitializeRootResourceHandle();
return false;
}
size_t actual, available;
cpu_fetch_time_ = std::chrono::high_resolution_clock::now();
zx_status_t err = zx_object_get_info(
root_resource_handle_, ZX_INFO_CPU_STATS, &cpu_stats_[0],
cpu_stats_.size() * sizeof(zx_info_cpu_stats_t), &actual, &available);
if (err != ZX_OK) {
FXL_LOG(ERROR) << "CpuStatsFetcherImpl: Fetching "
<< "ZX_INFO_CPU_STATS through syscall returns "
<< zx_status_get_string(err);
return false;
}
if (actual < available) {
FXL_LOG(WARNING) << "CpuStatsFetcherImpl: actual CPUs reported " << actual
<< " is less than available CPUs " << available
<< ". Please increase zx_info_cpu_stats_t vector size!"
<< sizeof(cpu_stats_);
return false;
}
if (num_cpu_cores_ == 0) {
num_cpu_cores_ = actual;
}
return true;
}
bool CpuStatsFetcherImpl::CalculateCpuPercentage(double *cpu_percentage) {
if (last_cpu_stats_.empty()) {
return false;
}
auto elapsed_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
cpu_fetch_time_ - last_cpu_fetch_time_)
.count();
double cpu_percentage_sum = 0;
for (size_t i = 0; i < num_cpu_cores_; i++) {
zx_duration_t delta_idle_time = zx_duration_sub_duration(
cpu_stats_[i].idle_time, last_cpu_stats_[i].idle_time);
zx_duration_t delta_busy_time =
(delta_idle_time > elapsed_time ? 0 : elapsed_time - delta_idle_time);
cpu_percentage_sum += static_cast<double>(delta_busy_time) * 100 /
static_cast<double>(elapsed_time);
}
*cpu_percentage = cpu_percentage_sum / static_cast<double>(num_cpu_cores_);
TRACE_COUNTER("system_metrics", "cpu_usage", 0, "average_cpu_percentage",
*cpu_percentage);
return true;
}
// TODO(CF-691) When Component Stats (CS) supports cpu metrics,
// switch to Component Stats / iquery, by creating a new class with the
// interface CpuStatsFetcher.
void CpuStatsFetcherImpl::InitializeRootResourceHandle() {
static const char kSysInfo[] = "/dev/misc/sysinfo";
int fd = open(kSysInfo, O_RDWR);
if (fd < 0) {
FXL_LOG(ERROR)
<< "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. "
<< "Cannot open sysinfo: " << strerror(errno);
return;
}
zx::channel channel;
zx_status_t status =
fdio_get_service_handle(fd, channel.reset_and_get_address());
if (status != ZX_OK) {
FXL_LOG(ERROR)
<< "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. "
<< "Cannot obtain sysinfo channel: " << zx_status_get_string(status);
return;
}
zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootResource(
channel.get(), &status, &root_resource_handle_);
if (fidl_status != ZX_OK) {
FXL_LOG(ERROR)
<< "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. "
<< zx_status_get_string(fidl_status);
return;
} else if (status != ZX_OK) {
FXL_LOG(ERROR)
<< "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. "
<< zx_status_get_string(status);
return;
} else if (root_resource_handle_ == ZX_HANDLE_INVALID) {
FXL_LOG(ERROR)
<< "Cobalt SystemMetricsDaemon: Failed to get root_resource_handle_.";
return;
}
}
} // namespace cobalt