From 83ebd1882f9e28129d5bc205986979bf1d3dd9e5 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sun, 25 Jun 2023 22:17:28 +0300 Subject: [PATCH] Utilities: Add the memstat utility This small utility is something we probably needed for a very long time - a way to print memory statistics in an elegant manner. This utility opens /sys/kernel/memstat, reads it and decode the values into human readable entries, possibly even into human-readable sizes. --- Base/usr/share/man/man1/memstat.md | 36 +++++++++++++++ Userland/Utilities/memstat.cpp | 70 ++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 Base/usr/share/man/man1/memstat.md create mode 100644 Userland/Utilities/memstat.cpp diff --git a/Base/usr/share/man/man1/memstat.md b/Base/usr/share/man/man1/memstat.md new file mode 100644 index 0000000000..1e930195a5 --- /dev/null +++ b/Base/usr/share/man/man1/memstat.md @@ -0,0 +1,36 @@ +## Name + +memstat - show memory statistics + +## Synopsis + +```**sh +$ memstat +``` + +## Options + +* `-h` , `--human-readable`: Print human-readable sizes + +## Examples + +```sh +$ memstat +Kmalloc allocated: 7894528/10979648 +Physical pages (in use) count: 172249088/1016643584 +Physical pages (committed) count: 125521920 +Physical pages (uncommitted) count: 718872576 +Physical pages (total) count: 248204 +Kmalloc call count: 77475 +Kfree call count: 59575 +Kmalloc/Kfree delta: +17900 +$ memstat -h +Kmalloc allocated: 7.5 MiB (7,908,928 bytes) / 10.4 MiB (10,978,624 bytes) +Physical pages (in use) count: 164.8 MiB (172,838,912 bytes) / 969.5 MiB (1,016,643,584 bytes) +Physical pages (committed) count: 119.6 MiB (125,485,056 bytes) +Physical pages (uncommitted) count: 685.0 MiB (718,319,616 bytes) +Physical pages (total) count: 248204 +Kmalloc call count: 78714 +Kfree call count: 60777 +Kmalloc/Kfree delta: +17937 +``` diff --git a/Userland/Utilities/memstat.cpp b/Userland/Utilities/memstat.cpp new file mode 100644 index 0000000000..5c8e04d0a1 --- /dev/null +++ b/Userland/Utilities/memstat.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline u64 page_count_to_bytes(size_t count) +{ + return count * PAGE_SIZE; +} + +ErrorOr serenity_main(Main::Arguments arguments) +{ + TRY(Core::System::unveil("/sys/kernel/memstat", "r")); + TRY(Core::System::unveil(nullptr, nullptr)); + + TRY(Core::System::pledge("stdio rpath")); + + bool flag_human_readable = false; + Core::ArgsParser args_parser; + args_parser.add_option(flag_human_readable, "Print human-readable sizes", "human-readable", 'h'); + args_parser.parse(arguments); + + auto proc_memstat = TRY(Core::File::open("/sys/kernel/memstat"sv, Core::File::OpenMode::Read)); + auto file_contents = TRY(proc_memstat->read_until_eof()); + auto json_result = TRY(JsonValue::from_string(file_contents)); + auto const& json = json_result.as_object(); + + u32 kmalloc_allocated = json.get_u32("kmalloc_allocated"sv).value_or(0); + u32 kmalloc_available = json.get_u32("kmalloc_available"sv).value_or(0); + u64 physical_allocated = json.get_u64("physical_allocated"sv).value_or(0); + u64 physical_available = json.get_u64("physical_available"sv).value_or(0); + u64 physical_committed = json.get_u64("physical_committed"sv).value_or(0); + u64 physical_uncommitted = json.get_u64("physical_uncommitted"sv).value_or(0); + u32 kmalloc_call_count = json.get_u32("kmalloc_call_count"sv).value_or(0); + u32 kfree_call_count = json.get_u32("kfree_call_count"sv).value_or(0); + + u64 kmalloc_bytes_total = kmalloc_allocated + kmalloc_available; + u64 physical_pages_total = physical_allocated + physical_available; + u64 physical_pages_in_use = physical_allocated; + + if (flag_human_readable) { + outln("Kmalloc allocated: {}", TRY(String::formatted("{} / {}", human_readable_size_long(kmalloc_allocated, UseThousandsSeparator::Yes), human_readable_size_long(kmalloc_bytes_total, UseThousandsSeparator::Yes)))); + outln("Physical pages (in use) count: {}", TRY(String::formatted("{} / {}", human_readable_size_long(page_count_to_bytes(physical_pages_in_use), UseThousandsSeparator::Yes), human_readable_size_long(page_count_to_bytes(physical_pages_total), UseThousandsSeparator::Yes)))); + outln("Physical pages (committed) count: {}", TRY(String::formatted("{}", human_readable_size_long(page_count_to_bytes(physical_committed), UseThousandsSeparator::Yes)))); + outln("Physical pages (uncommitted) count: {}", TRY(String::formatted("{}", human_readable_size_long(page_count_to_bytes(physical_uncommitted), UseThousandsSeparator::Yes)))); + outln("Physical pages (total) count: {:'}", physical_pages_total); + } else { + outln("Kmalloc allocated: {}", TRY(String::formatted("{}/{}", kmalloc_allocated, kmalloc_bytes_total))); + outln("Physical pages (in use) count: {}", TRY(String::formatted("{}/{}", page_count_to_bytes(physical_pages_in_use), page_count_to_bytes(physical_pages_total)))); + outln("Physical pages (committed) count: {}", TRY(String::formatted("{}", page_count_to_bytes(physical_committed)))); + outln("Physical pages (uncommitted) count: {}", TRY(String::formatted("{}", page_count_to_bytes(physical_uncommitted)))); + outln("Physical pages (total) count: {}", physical_pages_total); + } + outln("Kmalloc call count: {}", kmalloc_call_count); + outln("Kfree call count: {}", kfree_call_count); + outln("Kmalloc/Kfree delta: {}", TRY(String::formatted("{:+}", kmalloc_call_count - kfree_call_count))); + return 0; +}