From 37388b311f290384e35f7ec82136399e41ac9663 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 10 Mar 2019 12:13:22 +0100 Subject: [PATCH] ProcessManager: Show some basic system memory stats below the process table. This really improves the feeling of "system overview" :^) --- Applications/ProcessManager/Makefile | 1 + .../ProcessManager/MemoryStatsWidget.cpp | 101 ++++++++++++++++++ .../ProcessManager/MemoryStatsWidget.h | 21 ++++ .../ProcessManager/ProcessTableView.cpp | 3 +- .../ProcessManager/ProcessTableView.h | 2 - Applications/ProcessManager/main.cpp | 8 +- Kernel/MemoryManager.cpp | 6 ++ Kernel/MemoryManager.h | 7 ++ Kernel/ProcFS.cpp | 18 ++++ 9 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 Applications/ProcessManager/MemoryStatsWidget.cpp create mode 100644 Applications/ProcessManager/MemoryStatsWidget.h diff --git a/Applications/ProcessManager/Makefile b/Applications/ProcessManager/Makefile index 75c2566320..6ed785ce1e 100644 --- a/Applications/ProcessManager/Makefile +++ b/Applications/ProcessManager/Makefile @@ -1,6 +1,7 @@ OBJS = \ ProcessTableModel.o \ ProcessTableView.o \ + MemoryStatsWidget.o \ main.o APP = ProcessManager diff --git a/Applications/ProcessManager/MemoryStatsWidget.cpp b/Applications/ProcessManager/MemoryStatsWidget.cpp new file mode 100644 index 0000000000..32c37532ab --- /dev/null +++ b/Applications/ProcessManager/MemoryStatsWidget.cpp @@ -0,0 +1,101 @@ +#include "MemoryStatsWidget.h" +#include +#include +#include +#include +#include +#include + +MemoryStatsWidget::MemoryStatsWidget(GWidget* parent) + : GWidget(parent) +{ + set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + set_preferred_size({ 0, 60 }); + + set_layout(make(Orientation::Vertical)); + layout()->set_margins({ 0, 8, 0, 0 }); + layout()->set_spacing(3); + + m_user_physical_pages_label = new GLabel(this); + m_user_physical_pages_label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + m_user_physical_pages_label->set_preferred_size({ 0, 12 }); + m_user_physical_pages_label->set_fill_with_background_color(false); + m_supervisor_physical_pages_label = new GLabel(this); + m_supervisor_physical_pages_label->set_fill_with_background_color(false); + m_supervisor_physical_pages_label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + m_supervisor_physical_pages_label->set_preferred_size({ 0, 12 }); + m_kmalloc_label = new GLabel(this); + m_kmalloc_label->set_fill_with_background_color(false); + m_kmalloc_label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + m_kmalloc_label->set_preferred_size({ 0, 12 }); + + start_timer(1000); + refresh(); +} + +MemoryStatsWidget::~MemoryStatsWidget() +{ +} + +static inline size_t page_count_to_kb(size_t kb) +{ + return (kb * 4096) / 1024; +} + +static inline size_t bytes_to_kb(size_t bytes) +{ + return bytes / 1024; +} + +void MemoryStatsWidget::refresh() +{ + FILE* fp = fopen("/proc/memstat", "r"); + if (!fp) { + perror("failed to open /proc/memstat"); + exit(1); + } + + for (;;) { + char buf[BUFSIZ]; + char* ptr = fgets(buf, sizeof(buf), fp); + if (!ptr) + break; + auto parts = String(buf, Chomp).split(','); + if (parts.size() < 7) + break; + bool ok; + unsigned kmalloc_sum_eternal = parts[0].to_uint(ok); + ASSERT(ok); + unsigned kmalloc_sum_alloc = parts[1].to_uint(ok); + ASSERT(ok); + unsigned kmalloc_sum_free = parts[2].to_uint(ok); + ASSERT(ok); + unsigned user_pages_alloc = parts[3].to_uint(ok); + ASSERT(ok); + unsigned user_pages_free = parts[4].to_uint(ok); + ASSERT(ok); + unsigned supervisor_pages_alloc = parts[5].to_uint(ok); + ASSERT(ok); + unsigned supervisor_pages_free = parts[6].to_uint(ok); + ASSERT(ok); + + m_kmalloc_label->set_text(String::format("Kernel heap: %uK allocated, %uK free\n", bytes_to_kb(kmalloc_sum_alloc), bytes_to_kb(kmalloc_sum_free))); + m_user_physical_pages_label->set_text(String::format("Userspace physical: %uK allocated, %uK free\n", page_count_to_kb(user_pages_alloc), page_count_to_kb(user_pages_free))); + m_supervisor_physical_pages_label->set_text(String::format("Supervisor physical: %uK allocated, %uK free\n", page_count_to_kb(supervisor_pages_alloc), page_count_to_kb(supervisor_pages_free))); + break; + } + + fclose(fp); +} + +void MemoryStatsWidget::timer_event(GTimerEvent&) +{ + refresh(); +} + +void MemoryStatsWidget::paint_event(GPaintEvent& event) +{ + Painter painter(*this); + painter.set_clip_rect(event.rect()); + GStyle::the().paint_surface(painter, rect()); +} diff --git a/Applications/ProcessManager/MemoryStatsWidget.h b/Applications/ProcessManager/MemoryStatsWidget.h new file mode 100644 index 0000000000..497930cb05 --- /dev/null +++ b/Applications/ProcessManager/MemoryStatsWidget.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +class GLabel; + +class MemoryStatsWidget final : public GWidget { +public: + explicit MemoryStatsWidget(GWidget* parent); + virtual ~MemoryStatsWidget() override; + + void refresh(); + +private: + virtual void timer_event(GTimerEvent&) override; + virtual void paint_event(GPaintEvent&) override; + + GLabel* m_user_physical_pages_label { nullptr }; + GLabel* m_supervisor_physical_pages_label { nullptr }; + GLabel* m_kmalloc_label { nullptr }; +}; diff --git a/Applications/ProcessManager/ProcessTableView.cpp b/Applications/ProcessManager/ProcessTableView.cpp index 66b0f9510d..65c33f81dc 100644 --- a/Applications/ProcessManager/ProcessTableView.cpp +++ b/Applications/ProcessManager/ProcessTableView.cpp @@ -24,8 +24,7 @@ void ProcessTableView::timer_event(GTimerEvent&) void ProcessTableView::model_notification(const GModelNotification& notification) { if (notification.type() == GModelNotification::ModelUpdated) { - if (on_status_message) - on_status_message(String::format("%d processes", model()->row_count())); + // Do something? return; } } diff --git a/Applications/ProcessManager/ProcessTableView.h b/Applications/ProcessManager/ProcessTableView.h index 3294ea5d41..3ecd2c1c08 100644 --- a/Applications/ProcessManager/ProcessTableView.h +++ b/Applications/ProcessManager/ProcessTableView.h @@ -13,8 +13,6 @@ public: pid_t selected_pid() const; - Function on_status_message; - protected: virtual void model_notification(const GModelNotification&) override; diff --git a/Applications/ProcessManager/main.cpp b/Applications/ProcessManager/main.cpp index 390af60790..bcb0b9d652 100644 --- a/Applications/ProcessManager/main.cpp +++ b/Applications/ProcessManager/main.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -10,6 +9,7 @@ #include #include #include "ProcessTableView.h" +#include "MemoryStatsWidget.h" int main(int argc, char** argv) { @@ -21,10 +21,8 @@ int main(int argc, char** argv) auto* toolbar = new GToolBar(widget); auto* process_table_view = new ProcessTableView(widget); - auto* statusbar = new GStatusBar(widget); - process_table_view->on_status_message = [statusbar] (String message) { - statusbar->set_text(move(message)); - }; + + new MemoryStatsWidget(widget); auto kill_action = GAction::create("Kill process", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/kill16.rgb", { 16, 16 }), [process_table_view] (const GAction&) { pid_t pid = process_table_view->selected_pid(); diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 05f7083f7d..0141cc4171 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -12,6 +12,8 @@ //#define PAGE_FAULT_DEBUG static MemoryManager* s_the; +unsigned MemoryManager::s_user_physical_pages_in_existence; +unsigned MemoryManager::s_super_physical_pages_in_existence; MemoryManager& MM { @@ -686,6 +688,10 @@ PhysicalPage::PhysicalPage(PhysicalAddress paddr, bool supervisor, bool may_retu , m_supervisor(supervisor) , m_paddr(paddr) { + if (supervisor) + ++MemoryManager::s_super_physical_pages_in_existence; + else + ++MemoryManager::s_user_physical_pages_in_existence; } void PhysicalPage::return_to_freelist() diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index 68ba00259f..da1e350173 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -228,6 +228,7 @@ class MemoryManager { friend class Region; friend class VMObject; friend ByteBuffer procfs$mm(InodeIdentifier); + friend ByteBuffer procfs$memstat(InodeIdentifier); public: [[gnu::pure]] static MemoryManager& the(); @@ -254,6 +255,9 @@ public: size_t ram_size() const { return m_ram_size; } + int user_physical_pages_in_existence() const { return s_user_physical_pages_in_existence; } + int super_physical_pages_in_existence() const { return s_super_physical_pages_in_existence; } + private: MemoryManager(); ~MemoryManager(); @@ -383,6 +387,9 @@ private: dword* m_pte; }; + static unsigned s_user_physical_pages_in_existence; + static unsigned s_super_physical_pages_in_existence; + PageTableEntry ensure_pte(PageDirectory&, LinearAddress); RetainPtr m_kernel_page_directory; diff --git a/Kernel/ProcFS.cpp b/Kernel/ProcFS.cpp index 7919ff9031..e59929ef3d 100644 --- a/Kernel/ProcFS.cpp +++ b/Kernel/ProcFS.cpp @@ -31,6 +31,7 @@ enum ProcFileType { FI_Root_df, FI_Root_kmalloc, FI_Root_all, + FI_Root_memstat, FI_Root_summary, FI_Root_cpuinfo, FI_Root_inodes, @@ -537,6 +538,22 @@ ByteBuffer procfs$summary(InodeIdentifier) return builder.to_byte_buffer(); } +ByteBuffer procfs$memstat(InodeIdentifier) +{ + InterruptDisabler disabler; + StringBuilder builder; + builder.appendf("%u,%u,%u,%u,%u,%u,%u\n", + kmalloc_sum_eternal, + sum_alloc, + sum_free, + MM.user_physical_pages_in_existence() - MM.m_free_physical_pages.size(), + MM.m_free_physical_pages.size(), + MM.super_physical_pages_in_existence() - MM.m_free_supervisor_physical_pages.size(), + MM.m_free_supervisor_physical_pages.size() + ); + return builder.to_byte_buffer(); +} + ByteBuffer procfs$all(InodeIdentifier) { InterruptDisabler disabler; @@ -1112,6 +1129,7 @@ ProcFS::ProcFS() m_entries[FI_Root_df] = { "df", FI_Root_df, procfs$df }; m_entries[FI_Root_kmalloc] = { "kmalloc", FI_Root_kmalloc, procfs$kmalloc }; m_entries[FI_Root_all] = { "all", FI_Root_all, procfs$all }; + m_entries[FI_Root_memstat] = { "memstat", FI_Root_memstat, procfs$memstat }; m_entries[FI_Root_summary] = { "summary", FI_Root_summary, procfs$summary }; m_entries[FI_Root_cpuinfo] = { "cpuinfo", FI_Root_cpuinfo, procfs$cpuinfo}; m_entries[FI_Root_inodes] = { "inodes", FI_Root_inodes, procfs$inodes };