blob: 25008fd5ec3fc8652e45b21331285d532b4171fd [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 "gather_cpu.h"
#include <zircon/status.h>
#include "harvester.h"
#include "sample_bundle.h"
#include "src/lib/syslog/cpp/logger.h"
namespace harvester {
namespace {
// Utility function to label and append a cpu sample to the |list|. |cpu| is the
// index returned from the kernel. |path| is the kind of sample, e.g.
// "interrupt_count".
void AddCpuValue(SampleBundle* samples, size_t cpu, const std::string& path,
dockyard::SampleValue value) {
samples->AddIntSample("cpu", cpu, path, value);
}
} // namespace
void AddGlobalCpuSamples(SampleBundle* samples, zx_handle_t root_resource) {
// TODO(fxb/34): Determine the array size at runtime (32 is arbitrary).
zx_info_cpu_stats_t stats[32];
size_t actual, avail;
zx_status_t err = zx_object_get_info(root_resource, ZX_INFO_CPU_STATS, &stats,
sizeof(stats), &actual, &avail);
if (err != ZX_OK) {
FX_LOGS(ERROR) << ZxErrorString("ZX_INFO_CPU_STATS", err);
return;
}
auto now = std::chrono::high_resolution_clock::now();
auto cpu_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
now.time_since_epoch())
.count();
for (size_t i = 0; i < actual; ++i) {
// Note: stats[i].flags are not currently recorded.
// Kernel scheduler counters.
AddCpuValue(samples, i, "reschedules", stats[i].reschedules);
AddCpuValue(samples, i, "context_switches", stats[i].context_switches);
AddCpuValue(samples, i, "meaningful_irq_preempts", stats[i].irq_preempts);
AddCpuValue(samples, i, "preempts", stats[i].preempts);
AddCpuValue(samples, i, "yields", stats[i].yields);
// CPU level interrupts and exceptions.
uint64_t busy_time =
cpu_time > stats[i].idle_time ? cpu_time - stats[i].idle_time : 0ull;
AddCpuValue(samples, i, "busy_time", busy_time);
AddCpuValue(samples, i, "idle_time", stats[i].idle_time);
AddCpuValue(samples, i, "external_hardware_interrupts", stats[i].ints);
AddCpuValue(samples, i, "timer_interrupts", stats[i].timer_ints);
AddCpuValue(samples, i, "timer_callbacks", stats[i].timers);
AddCpuValue(samples, i, "syscalls", stats[i].syscalls);
// Inter-processor interrupts.
AddCpuValue(samples, i, "reschedule_ipis", stats[i].reschedule_ipis);
AddCpuValue(samples, i, "generic_ipis", stats[i].generic_ipis);
}
}
void GatherCpu::GatherDeviceProperties() {
const std::string CPU_COUNT = "cpu:count";
zx_info_cpu_stats_t stats[1];
size_t actual, avail;
zx_status_t err = zx_object_get_info(RootResource(), ZX_INFO_CPU_STATS,
&stats, sizeof(stats), &actual, &avail);
if (err != ZX_OK) {
FX_LOGS(ERROR) << ZxErrorString("ZX_INFO_CPU_STATS", err);
return;
}
SampleList list;
list.emplace_back(CPU_COUNT, avail);
DockyardProxyStatus status = Dockyard().SendSampleList(list);
if (status != DockyardProxyStatus::OK) {
FX_LOGS(ERROR) << DockyardErrorString("SendSampleList", status)
<< " The cpu_count value will be missing";
}
}
void GatherCpu::Gather() {
SampleBundle samples;
AddGlobalCpuSamples(&samples, RootResource());
samples.Upload(DockyardPtr());
}
} // namespace harvester