blob: 4e8e95238e4774dee4514b1e34bac59f2abae0e8 [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 <algorithm>
#include <cinttypes>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <errno.h>
#include <fbl/array.h>
#include <fbl/unique_fd.h>
#include <fcntl.h>
#include <getopt.h>
#include <lib/fdio/io.h>
#include <lib/fzl/owned-vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <unistd.h>
#include <utility>
#include <zircon/kernel-counters.h>
#include <zircon/status.h>
#include <unittest/unittest.h>
namespace {
constexpr char kVmoFilePrefix[] = "/boot/kernel/";
bool test_counters() {
BEGIN_TEST;
fzl::OwnedVmoMapper desc_mapper;
const counters::DescriptorVmo* desc;
{
char desc_file_name[sizeof(kVmoFilePrefix) +
sizeof(counters::DescriptorVmo::kVmoName)];
strcpy(desc_file_name, kVmoFilePrefix);
strcat(desc_file_name, counters::DescriptorVmo::kVmoName);
fbl::unique_fd desc_fd(open(desc_file_name, O_RDONLY));
ASSERT_TRUE(desc_fd, "cannot open descriptor VMO file");
zx::vmo vmo;
zx_status_t status = fdio_get_vmo_exact(
desc_fd.get(), vmo.reset_and_get_address());
ASSERT_EQ(status, ZX_OK, "fdio_get_vmo_exact on descriptor VMO");
uint64_t size;
status = vmo.get_size(&size);
ASSERT_EQ(status, ZX_OK, "cannot get descriptor VMO size");
status = desc_mapper.Map(std::move(vmo), size, ZX_VM_PERM_READ);
ASSERT_EQ(status, ZX_OK, "cannot map descriptor VMO");
desc = reinterpret_cast<counters::DescriptorVmo*>(desc_mapper.start());
EXPECT_EQ(desc->magic, counters::DescriptorVmo::kMagic,
"descriptor VMO magic number");
EXPECT_GE(size, sizeof(*desc) + desc->descriptor_table_size,
"descriptor table size");
}
fzl::OwnedVmoMapper arena_mapper;
const volatile int64_t* arena;
{
char arena_file_name[sizeof(kVmoFilePrefix) +
sizeof(counters::kArenaVmoName)];
strcpy(arena_file_name, kVmoFilePrefix);
strcat(arena_file_name, counters::kArenaVmoName);
fbl::unique_fd arena_fd(open(arena_file_name, O_RDONLY));
ASSERT_TRUE(arena_fd, "cannot open arena VMO file");
zx::vmo vmo;
zx_status_t status = fdio_get_vmo_exact(
arena_fd.get(), vmo.reset_and_get_address());
ASSERT_EQ(status, ZX_OK, "fdio_get_vmo_exact on arena VMO");
uint64_t size;
status = vmo.get_size(&size);
ASSERT_EQ(status, ZX_OK, "cannot get arena VMO size");
EXPECT_GE(size,
desc->max_cpus * desc->num_counters() * sizeof(int64_t),
"arena VMO size");
status = arena_mapper.Map(std::move(vmo), size, ZX_VM_PERM_READ);
ASSERT_EQ(status, ZX_OK, "cannot map arena VMO");
arena = reinterpret_cast<int64_t*>(arena_mapper.start());
}
auto find = [desc](const counters::Descriptor& ref) -> const counters::Descriptor* {
auto result = std::equal_range(desc->begin(), desc->end(),
ref, [](const counters::Descriptor& a,
const counters::Descriptor& b) {
return strcmp(a.name, b.name) < 0;
});
return (result.first == result.second) ?
nullptr : &desc->descriptor_table[result.first - desc->begin()];
};
constexpr counters::Descriptor kExpected[] = {
{"kernel.counters.magic", counters::Type::kSum},
{"kernel.handles.duped", counters::Type::kSum},
{"kernel.handles.live", counters::Type::kSum},
{"kernel.handles.made", counters::Type::kSum},
};
for (const auto& ref : kExpected) {
auto found = find(ref);
EXPECT_NONNULL(found, "expected counter name not found");
if (found) {
EXPECT_EQ(found->type, ref.type, "counter has wrong type");
size_t idx = found - desc->begin();
int64_t value = 0;
for (uint64_t cpu = 0; cpu < desc->max_cpus; ++cpu) {
int64_t cpu_value = arena[(cpu * desc->num_counters()) + idx];
switch (ref.type) {
default:
abort();
break;
case counters::Type::kSum:
value += cpu_value;
break;
case counters::Type::kMax: // Not used, see ZX-3337.
value = std::max(value, cpu_value);
break;
}
}
EXPECT_GT(value, 0, ref.name);
if (!strcmp(ref.name, "kernel.counters.magic")) {
EXPECT_EQ(value, counters::DescriptorVmo::kMagic,
"kernel.counters.magic");
}
}
}
END_TEST;
}
} // anonymous namespace
BEGIN_TEST_CASE(counters_test)
RUN_TEST(test_counters)
END_TEST_CASE(counters_test)
int main(int argc, char** argv) {
bool success = unittest_run_all_tests(argc, argv);
return success ? 0 : -1;
}