blob: 0a9109c029ec62492270ec824c5dca41fc169d97 [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/developer/memory/metrics/tests/test_utils.h"
#include <lib/syslog/cpp/macros.h>
#include <zircon/errors.h>
#include <zircon/syscalls/object.h>
#include <algorithm>
#include <memory>
#include <gtest/gtest.h>
#include "src/developer/memory/metrics/capture.h"
namespace memory {
namespace {
zx_info_kmem_stats_extended_t ExtendedStats(const zx_info_kmem_stats_t& stats) {
return zx_info_kmem_stats_extended_t{
.total_bytes = stats.total_bytes,
.free_bytes = stats.free_bytes,
.wired_bytes = stats.wired_bytes,
.total_heap_bytes = stats.total_heap_bytes,
.free_heap_bytes = stats.free_heap_bytes,
.vmo_bytes = stats.vmo_bytes,
.vmo_pager_total_bytes = stats.vmo_reclaim_total_bytes,
.vmo_pager_newest_bytes = stats.vmo_reclaim_newest_bytes,
.vmo_pager_oldest_bytes = stats.vmo_reclaim_oldest_bytes,
.vmo_discardable_locked_bytes = stats.vmo_discardable_locked_bytes,
.vmo_discardable_unlocked_bytes = stats.vmo_discardable_unlocked_bytes,
.mmu_overhead_bytes = stats.mmu_overhead_bytes,
.ipc_bytes = stats.ipc_bytes,
.other_bytes = stats.other_bytes,
.vmo_reclaim_disabled_bytes = stats.vmo_reclaim_disabled_bytes,
};
}
} // namespace
const zx_handle_t TestUtils::kRootHandle = 1;
const zx_handle_t TestUtils::kSelfHandle = 2;
const zx_koid_t TestUtils::kSelfKoid = 3;
MockOS::MockOS(OsResponses responses)
: responses_(std::move(responses)), i_get_property_(0), clock_(0) {}
zx_status_t MockOS::GetKernelStats(fidl::WireSyncClient<fuchsia_kernel::Stats>* stats) {
return ZX_OK;
}
zx_handle_t MockOS::ProcessSelf() { return TestUtils::kSelfHandle; }
zx_instant_boot_t MockOS::GetBoot() { return clock_; }
zx_status_t MockOS::GetProcesses(
fit::function<zx_status_t(int, zx::handle, zx_koid_t, zx_koid_t)> cb) {
const auto& r = responses_.get_processes;
for (const auto& c : r.callbacks) {
auto ret = cb(c.depth, zx::handle(c.handle), c.koid, c.parent_koid);
if (ret != ZX_OK) {
return ret;
}
}
return r.ret;
}
zx_status_t MockOS::GetProperty(zx_handle_t handle, uint32_t property, void* value,
size_t name_len) {
const auto& r = responses_.get_property.at(i_get_property_++);
EXPECT_EQ(r.handle, handle);
EXPECT_EQ(r.property, property);
auto len = std::min(name_len, r.value_len);
memcpy(value, r.value, len);
return r.ret;
}
const GetInfoResponse* MockOS::GetGetInfoResponse(zx_handle_t handle, uint32_t topic) {
for (const auto& resp : responses_.get_info) {
if (resp.handle == handle && resp.topic == topic) {
return &resp;
}
}
FX_LOGS(ERROR) << "This should not be reached: handle " << handle << " topic " << topic;
EXPECT_TRUE(false) << "This should not be reached: handle " << handle << " topic " << topic;
return nullptr;
}
zx_status_t MockOS::GetInfo(zx_handle_t handle, uint32_t topic, void* buffer, size_t buffer_size,
size_t* actual, size_t* avail) {
const GetInfoResponse* r = GetGetInfoResponse(handle, topic);
if (r == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
EXPECT_EQ(r->handle, handle);
EXPECT_EQ(r->topic, topic);
size_t num_copied = 0;
if (buffer != nullptr) {
num_copied = std::min(r->value_count, buffer_size / r->value_size);
memcpy(buffer, r->values, num_copied * r->value_size);
}
if (actual != nullptr) {
*actual = num_copied;
}
// avail is the number of total available elements that can be read.
if (avail != nullptr) {
*avail = r->value_count;
}
return r->ret;
}
zx_status_t MockOS::GetKernelMemoryStats(
const fidl::WireSyncClient<fuchsia_kernel::Stats>& stats_client, zx_info_kmem_stats_t& kmem) {
const GetInfoResponse* r = GetGetInfoResponse(TestUtils::kRootHandle, ZX_INFO_KMEM_STATS);
if (r == nullptr)
return ZX_ERR_INVALID_ARGS;
memcpy(&kmem, r->values, r->value_size);
return r->ret;
}
zx_status_t MockOS::GetKernelMemoryStatsExtended(
const fidl::WireSyncClient<fuchsia_kernel::Stats>& stats_client,
zx_info_kmem_stats_extended_t& kmem_ext, zx_info_kmem_stats_t* kmem) {
const GetInfoResponse* r1 = GetGetInfoResponse(TestUtils::kRootHandle, ZX_INFO_KMEM_STATS);
if (r1 == nullptr)
return ZX_ERR_INVALID_ARGS;
memcpy(kmem, r1->values, r1->value_size);
const GetInfoResponse* r2 = GetGetInfoResponse(TestUtils::kRootHandle, ZX_INFO_KMEM_STATS);
if (r2 == nullptr)
return ZX_ERR_INVALID_ARGS;
zx_info_kmem_stats_t stats;
memcpy(&stats, r2->values, r2->value_size);
kmem_ext = ExtendedStats(stats);
return r2->ret;
}
zx_status_t MockOS::GetKernelMemoryStatsCompression(
const fidl::WireSyncClient<fuchsia_kernel::Stats>& stats_client,
zx_info_kmem_stats_compression_t& kmem_compression) {
const GetInfoResponse* r =
GetGetInfoResponse(TestUtils::kRootHandle, ZX_INFO_KMEM_STATS_COMPRESSION);
if (r == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
memcpy(&kmem_compression, r->values, r->value_size);
return r->ret;
}
void TestUtils::CreateCapture(Capture* capture, const CaptureTemplate& t, CaptureLevel level) {
capture->time_ = t.time;
capture->kmem_ = t.kmem;
if (level == CaptureLevel::KMEM) {
return;
}
capture->kmem_extended_ = t.kmem_extended;
if (level != CaptureLevel::VMO) {
return;
}
for (const auto& vmo : t.vmos) {
capture->koid_to_vmo_.emplace(vmo.koid, vmo);
}
for (const auto& process : t.processes) {
capture->koid_to_process_.emplace(process.koid, process);
}
CaptureMaker::ReallocateDescendants(t.rooted_vmo_names, capture->koid_to_vmo_);
}
std::vector<ProcessSummary> TestUtils::GetProcessSummaries(const Summary& summary) {
std::vector<ProcessSummary> summaries = summary.process_summaries();
std::ranges::sort(summaries, [](const ProcessSummary& a, const ProcessSummary& b) {
return a.koid() < b.koid();
});
return summaries;
}
zx_status_t TestUtils::GetCapture(Capture* capture, CaptureLevel level, const OsResponses& r) {
CaptureMaker capture_maker({}, std::make_unique<MockOS>(r));
return capture_maker.GetCapture(capture, level, Capture::kDefaultRootedVmoNames);
}
zx_status_t CaptureSupplier::GetCapture(Capture* capture, CaptureLevel level,
bool use_capture_supplier_time) {
auto& t = templates_.at(index_);
if (!use_capture_supplier_time) {
t.time = static_cast<int64_t>(index_);
}
index_++;
TestUtils::CreateCapture(capture, t, level);
return ZX_OK;
}
} // namespace memory