blob: 067f0648568d7ba7850f04cc8090bd848958fdfc [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 <gtest/gtest.h>
#include <lib/gtest/test_loop_fixture.h>
#include <zircon/types.h>
#include "src/developer/memory/metrics/capture.h"
#include "src/developer/memory/metrics/tests/test_utils.h"
namespace memory {
namespace test {
using CaptureUnitTest = gtest::TestLoopFixture;
const static zx_info_kmem_stats _kmem = {
.total_bytes = 300,
.free_bytes = 100,
.wired_bytes = 10,
.total_heap_bytes = 20,
.free_heap_bytes = 30,
.vmo_bytes = 40,
.mmu_overhead_bytes = 50,
.ipc_bytes = 60,
.other_bytes = 70
};
const static GetInfoResponse kmem_info = {
TestUtils::kRootHandle, ZX_INFO_KMEM_STATS, &_kmem, sizeof(_kmem), 1, ZX_OK
};
const static zx_info_handle_basic_t _self = {.koid = TestUtils::kSelfKoid };
const static GetInfoResponse self_info = {
TestUtils::kSelfHandle, ZX_INFO_HANDLE_BASIC, &_self, sizeof(_self), 1, ZX_OK
};
const zx_koid_t proc_koid = 10;
const zx_handle_t proc_handle = 100;
const char proc_name[] = "P1";
const static zx_info_task_stats _proc = {};
const static GetInfoResponse proc_info =
{proc_handle, ZX_INFO_TASK_STATS, &_proc, sizeof(_proc), 1, ZX_OK};
const static GetPropertyResponse proc_prop =
{proc_handle, ZX_PROP_NAME, proc_name, sizeof(proc_name), ZX_OK};
const static GetProcessesCallback proc_cb =
{1, proc_handle, proc_koid, 0};
const zx_koid_t proc2_koid = 20;
const zx_handle_t proc2_handle = 200;
const char proc2_name[] = "P2";
const static zx_info_task_stats _proc2 = {};
const static GetInfoResponse proc2_info =
{proc2_handle, ZX_INFO_TASK_STATS, &_proc2, sizeof(_proc2), 1, ZX_OK};
const static GetPropertyResponse proc2_prop =
{proc2_handle, ZX_PROP_NAME, proc2_name, sizeof(proc2_name), ZX_OK};
const static GetProcessesCallback proc2_cb =
{1, proc2_handle, proc2_koid, 0};
const zx_koid_t vmo_koid = 1000;
const uint64_t vmo_size = 10000;
const char vmo_name[] = "V1";
const static zx_info_vmo_t _vmo = {
.koid = vmo_koid,
.name = "V1",
.size_bytes = vmo_size,
};
const static GetInfoResponse vmos_info =
{proc_handle, ZX_INFO_PROCESS_VMOS, &_vmo, sizeof(_vmo), 1, ZX_OK};
const zx_koid_t vmo2_koid = 2000;
const uint64_t vmo2_size = 20000;
const char vmo2_name[] = "V2";
const static zx_info_vmo_t _vmo2 = {
.koid = vmo2_koid,
.name = "V2",
.size_bytes = vmo2_size,
};
const static GetInfoResponse vmos2_info =
{proc2_handle, ZX_INFO_PROCESS_VMOS, &_vmo2, sizeof(_vmo2), 1, ZX_OK};
TEST_F(CaptureUnitTest, KMEM) {
Capture c;
auto ret = TestUtils::GetCapture(c, KMEM, {
.get_info = {self_info, kmem_info},
});
EXPECT_EQ(ZX_OK, ret);
auto const& got_kmem = c.kmem();
EXPECT_EQ(_kmem.total_bytes, got_kmem.total_bytes);
}
TEST_F(CaptureUnitTest, PROCESS) {
Capture c;
auto ret = TestUtils::GetCapture(c, PROCESS, {
.get_info = {self_info, kmem_info, proc_info},
.get_processes = {{ZX_OK, {proc_cb}}},
.get_property = {proc_prop}
});
EXPECT_EQ(ZX_OK, ret);
EXPECT_EQ(1U, c.koid_to_process().size());
auto const& process = c.process_for_koid(proc_koid);
EXPECT_EQ(proc_koid, process.koid);
EXPECT_STREQ(proc_name, process.name);
}
TEST_F(CaptureUnitTest, VMO) {
Capture c;
auto ret = TestUtils::GetCapture(c, VMO, {
.get_info = {self_info, kmem_info, proc_info, vmos_info, vmos_info},
.get_processes = {{ZX_OK, {proc_cb}}},
.get_property = {proc_prop}
});
EXPECT_EQ(ZX_OK, ret);
EXPECT_EQ(1U, c.koid_to_process().size());
auto const& process = c.process_for_koid(proc_koid);
EXPECT_EQ(proc_koid, process.koid);
EXPECT_STREQ(proc_name, process.name);
EXPECT_EQ(1U, process.vmos.size());
EXPECT_EQ(1U, c.koid_to_vmo().size());
EXPECT_EQ(vmo_koid, process.vmos[0]);
auto const& vmo = c.vmo_for_koid(vmo_koid);
EXPECT_EQ(vmo_koid, vmo.koid);
EXPECT_EQ(vmo_size, vmo.size_bytes);
EXPECT_STREQ(vmo_name, vmo.name);
}
TEST_F(CaptureUnitTest, VMODouble) {
Capture c;
auto ret = TestUtils::GetCapture(c, VMO, {
.get_info = {
self_info,
kmem_info,
proc_info,
vmos_info,
vmos_info,
proc2_info,
vmos2_info,
vmos2_info,
},
.get_processes = {{ZX_OK, {proc_cb, proc2_cb}}},
.get_property = {proc_prop, proc2_prop}
});
EXPECT_EQ(ZX_OK, ret);
EXPECT_EQ(2U, c.koid_to_process().size());
EXPECT_EQ(2U, c.koid_to_vmo().size());
auto const& process = c.process_for_koid(proc_koid);
EXPECT_EQ(proc_koid, process.koid);
EXPECT_STREQ(proc_name, process.name);
EXPECT_EQ(1U, process.vmos.size());
EXPECT_EQ(vmo_koid, process.vmos[0]);
auto const& vmo = c.vmo_for_koid(vmo_koid);
EXPECT_EQ(vmo_koid, vmo.koid);
EXPECT_EQ(vmo_size, vmo.size_bytes);
EXPECT_STREQ(vmo_name, vmo.name);
auto const& process2 = c.process_for_koid(proc2_koid);
EXPECT_EQ(proc2_koid, process2.koid);
EXPECT_STREQ(proc2_name, process2.name);
EXPECT_EQ(1U, process2.vmos.size());
EXPECT_EQ(vmo2_koid, process2.vmos[0]);
auto const& vmo2 = c.vmo_for_koid(vmo2_koid);
EXPECT_EQ(vmo2_koid, vmo2.koid);
EXPECT_EQ(vmo2_size, vmo2.size_bytes);
EXPECT_STREQ(vmo2_name, vmo2.name);
}
TEST_F(CaptureUnitTest, ProcessPropBadState) {
// If the process disappears we should ignore it and continue.
Capture c;
auto ret = TestUtils::GetCapture(c, PROCESS, {
.get_info = {self_info, kmem_info, proc2_info},
.get_processes = {{ZX_OK, {proc_cb, proc2_cb}}},
.get_property = {
{proc_handle, ZX_PROP_NAME, nullptr, 0, ZX_ERR_BAD_STATE},
proc2_prop
}
});
EXPECT_EQ(ZX_OK, ret);
EXPECT_EQ(1U, c.koid_to_process().size());
auto const& process = c.process_for_koid(proc2_koid);
EXPECT_EQ(proc2_koid, process.koid);
EXPECT_STREQ(proc2_name, process.name);
}
TEST_F(CaptureUnitTest, ProcessInfoBadState) {
// If the process disappears we should ignore it and continue.
Capture c;
auto ret = TestUtils::GetCapture(c, PROCESS, {
.get_info = {
self_info,
kmem_info,
{proc_handle, ZX_INFO_TASK_STATS,
&_proc, sizeof(_proc), 1, ZX_ERR_BAD_STATE},
proc2_info
},
.get_processes = {{ZX_OK, {proc_cb, proc2_cb}}},
.get_property = {proc_prop, proc2_prop},
});
EXPECT_EQ(ZX_OK, ret);
EXPECT_EQ(1U, c.koid_to_process().size());
auto const& process = c.process_for_koid(proc2_koid);
EXPECT_EQ(proc2_koid, process.koid);
EXPECT_STREQ(proc2_name, process.name);
}
TEST_F(CaptureUnitTest, VMOCountBadState) {
// If the process disappears we should ignore it and continue.
Capture c;
auto ret = TestUtils::GetCapture(c, VMO, {
.get_info = {
self_info,
kmem_info,
proc_info,
{proc_handle, ZX_INFO_PROCESS_VMOS,
&_vmo, sizeof(_vmo), 1, ZX_ERR_BAD_STATE},
proc2_info,
vmos2_info,
vmos2_info
},
.get_processes = {{ZX_OK, {proc_cb, proc2_cb}}},
.get_property = {proc_prop, proc2_prop}
});
EXPECT_EQ(ZX_OK, ret);
EXPECT_EQ(1U, c.koid_to_process().size());
auto const& process = c.process_for_koid(proc2_koid);
EXPECT_EQ(proc2_koid, process.koid);
EXPECT_STREQ(proc2_name, process.name);
EXPECT_EQ(1U, process.vmos.size());
EXPECT_EQ(1U, c.koid_to_vmo().size());
EXPECT_EQ(vmo2_koid, process.vmos[0]);
auto const& vmo = c.vmo_for_koid(vmo2_koid);
EXPECT_EQ(vmo2_koid, vmo.koid);
EXPECT_EQ(vmo2_size, vmo.size_bytes);
EXPECT_STREQ(vmo2_name, vmo.name);
}
TEST_F(CaptureUnitTest, VMOGetBadState) {
// If the process disappears we should ignore it and continue.
Capture c;
auto ret = TestUtils::GetCapture(c, VMO, {
.get_info = {
self_info,
kmem_info,
proc_info,
vmos_info,
{proc_handle, ZX_INFO_PROCESS_VMOS,
&_vmo, sizeof(_vmo), 1, ZX_ERR_BAD_STATE},
proc2_info,
vmos2_info,
vmos2_info
},
.get_processes = {{ZX_OK, {proc_cb, proc2_cb}}},
.get_property = {proc_prop, proc2_prop}
});
EXPECT_EQ(ZX_OK, ret);
EXPECT_EQ(1U, c.koid_to_process().size());
auto const& process = c.process_for_koid(proc2_koid);
EXPECT_EQ(proc2_koid, process.koid);
EXPECT_STREQ(proc2_name, process.name);
EXPECT_EQ(1U, process.vmos.size());
EXPECT_EQ(1U, c.koid_to_vmo().size());
EXPECT_EQ(vmo2_koid, process.vmos[0]);
auto const& vmo = c.vmo_for_koid(vmo2_koid);
EXPECT_EQ(vmo2_koid, vmo.koid);
EXPECT_EQ(vmo2_size, vmo.size_bytes);
EXPECT_STREQ(vmo2_name, vmo.name);
}
} // namespace test
} // namespace memory