diff --git a/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp b/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp index 2a7955e13c..b6e1b7a6d5 100644 --- a/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp +++ b/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp @@ -18,6 +18,7 @@ ProcessMemoryMapWidget::ProcessMemoryMapWidget(GWidget* parent) }); pid_vm_fields.empend("size", "Size", TextAlignment::CenterRight); pid_vm_fields.empend("amount_resident", "Resident", TextAlignment::CenterRight); + pid_vm_fields.empend("amount_dirty", "Dirty", TextAlignment::CenterRight); pid_vm_fields.empend("Access", TextAlignment::CenterLeft, [](auto& object) { StringBuilder builder; if (!object.get("user_accessible").to_bool()) diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp index 8d7f75e525..d84b52e59f 100644 --- a/Applications/SystemMonitor/ProcessModel.cpp +++ b/Applications/SystemMonitor/ProcessModel.cpp @@ -59,6 +59,8 @@ String ProcessModel::column_name(int column) const return "Virtual"; case Column::Physical: return "Physical"; + case Column::DirtyPrivate: + return "DirtyP"; case Column::PurgeableVolatile: return "Purg:V"; case Column::PurgeableNonvolatile: @@ -111,6 +113,8 @@ GModel::ColumnMetadata ProcessModel::column_metadata(int column) const return { 65, TextAlignment::CenterRight }; case Column::Physical: return { 65, TextAlignment::CenterRight }; + case Column::DirtyPrivate: + return { 65, TextAlignment::CenterRight }; case Column::PurgeableVolatile: return { 65, TextAlignment::CenterRight }; case Column::PurgeableNonvolatile: @@ -183,6 +187,8 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const return (int)thread.current_state.amount_virtual; case Column::Physical: return (int)thread.current_state.amount_resident; + case Column::DirtyPrivate: + return (int)thread.current_state.amount_dirty_private; case Column::PurgeableVolatile: return (int)thread.current_state.amount_purgeable_volatile; case Column::PurgeableNonvolatile: @@ -250,6 +256,8 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const return pretty_byte_size(thread.current_state.amount_virtual); case Column::Physical: return pretty_byte_size(thread.current_state.amount_resident); + case Column::DirtyPrivate: + return pretty_byte_size(thread.current_state.amount_dirty_private); case Column::PurgeableVolatile: return pretty_byte_size(thread.current_state.amount_purgeable_volatile); case Column::PurgeableNonvolatile: @@ -311,6 +319,7 @@ void ProcessModel::update() state.file_write_bytes = thread.file_write_bytes; state.amount_virtual = it.value.amount_virtual; state.amount_resident = it.value.amount_resident; + state.amount_dirty_private = it.value.amount_dirty_private; state.amount_purgeable_volatile = it.value.amount_purgeable_volatile; state.amount_purgeable_nonvolatile = it.value.amount_purgeable_nonvolatile; state.icon_id = it.value.icon_id; diff --git a/Applications/SystemMonitor/ProcessModel.h b/Applications/SystemMonitor/ProcessModel.h index 15d734e246..e8a38d5948 100644 --- a/Applications/SystemMonitor/ProcessModel.h +++ b/Applications/SystemMonitor/ProcessModel.h @@ -30,6 +30,7 @@ public: TID, Virtual, Physical, + DirtyPrivate, PurgeableVolatile, PurgeableNonvolatile, Syscalls, @@ -72,6 +73,7 @@ private: String priority; size_t amount_virtual; size_t amount_resident; + size_t amount_dirty_private; size_t amount_purgeable_volatile; size_t amount_purgeable_nonvolatile; unsigned syscall_count; diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 8740b44943..00aacacfaf 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -275,6 +275,7 @@ Optional procfs$pid_vm(InodeIdentifier identifier) region_object.add("address", region.vaddr().get()); region_object.add("size", (u32)region.size()); region_object.add("amount_resident", (u32)region.amount_resident()); + region_object.add("amount_dirty", (u32)region.amount_dirty()); region_object.add("cow_pages", region.cow_pages()); region_object.add("name", region.name()); } @@ -752,6 +753,7 @@ Optional procfs$all(InodeIdentifier) process_object.add("tty", process.tty() ? process.tty()->tty_name() : "notty"); process_object.add("amount_virtual", (u32)process.amount_virtual()); process_object.add("amount_resident", (u32)process.amount_resident()); + process_object.add("amount_dirty_private", (u32)process.amount_dirty_private()); process_object.add("amount_shared", (u32)process.amount_shared()); process_object.add("amount_purgeable_volatile", (u32)process.amount_purgeable_volatile()); process_object.add("amount_purgeable_nonvolatile", (u32)process.amount_purgeable_nonvolatile()); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 34aa556800..dd7f6f1f71 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2502,6 +2502,16 @@ void Process::die() } } +size_t Process::amount_dirty_private() const +{ + size_t amount = 0; + for (auto& region : m_regions) { + if (!region.is_shared()) + amount += region.amount_dirty(); + } + return amount; +} + size_t Process::amount_virtual() const { size_t amount = 0; diff --git a/Kernel/Process.h b/Kernel/Process.h index e4ceb9e823..d4ad159dae 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -272,6 +272,7 @@ public: int number_of_open_file_descriptors() const; int max_open_file_descriptors() const { return m_max_open_file_descriptors; } + size_t amount_dirty_private() const; size_t amount_virtual() const; size_t amount_resident() const; size_t amount_shared() const; diff --git a/Kernel/VM/InodeVMObject.cpp b/Kernel/VM/InodeVMObject.cpp index 874b3ccc1b..5edc9b3c20 100644 --- a/Kernel/VM/InodeVMObject.cpp +++ b/Kernel/VM/InodeVMObject.cpp @@ -21,6 +21,7 @@ NonnullRefPtr InodeVMObject::clone() InodeVMObject::InodeVMObject(Inode& inode) : VMObject(inode.size()) , m_inode(inode) + , m_dirty_pages(page_count(), false) { } @@ -35,6 +36,16 @@ InodeVMObject::~InodeVMObject() ASSERT(inode().vmobject() == this); } +size_t InodeVMObject::amount_dirty() const +{ + size_t count = 0; + for (int i = 0; i < m_dirty_pages.size(); ++i) { + if (m_dirty_pages.get(i)) + ++count; + } + return count * PAGE_SIZE; +} + void InodeVMObject::inode_size_changed(Badge, size_t old_size, size_t new_size) { dbgprintf("VMObject::inode_size_changed: {%u:%u} %u -> %u\n", @@ -46,6 +57,8 @@ void InodeVMObject::inode_size_changed(Badge, size_t old_size, size_t new auto new_page_count = PAGE_ROUND_UP(new_size) / PAGE_SIZE; m_physical_pages.resize(new_page_count); + m_dirty_pages.grow(new_page_count, false); + // FIXME: Consolidate with inode_contents_changed() so we only do a single walk. for_each_region([](auto& region) { region.remap(); diff --git a/Kernel/VM/InodeVMObject.h b/Kernel/VM/InodeVMObject.h index f8c797a602..56e8b344d6 100644 --- a/Kernel/VM/InodeVMObject.h +++ b/Kernel/VM/InodeVMObject.h @@ -16,6 +16,8 @@ public: void inode_contents_changed(Badge, off_t, ssize_t, const u8*); void inode_size_changed(Badge, size_t old_size, size_t new_size); + size_t amount_dirty() const; + private: explicit InodeVMObject(Inode&); explicit InodeVMObject(const InodeVMObject&); @@ -27,4 +29,5 @@ private: virtual bool is_inode() const override { return true; } NonnullRefPtr m_inode; + Bitmap m_dirty_pages; }; diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp index c2a21e89bf..2e905fe7cd 100644 --- a/Kernel/VM/Region.cpp +++ b/Kernel/VM/Region.cpp @@ -133,6 +133,13 @@ u32 Region::cow_pages() const return count; } +size_t Region::amount_dirty() const +{ + if (!vmobject().is_inode()) + return amount_resident(); + return static_cast(vmobject()).amount_dirty(); +} + size_t Region::amount_resident() const { size_t bytes = 0; diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h index f9879c84c2..428e29feb3 100644 --- a/Kernel/VM/Region.h +++ b/Kernel/VM/Region.h @@ -103,6 +103,7 @@ public: size_t amount_resident() const; size_t amount_shared() const; + size_t amount_dirty() const; bool should_cow(size_t page_index) const; void set_should_cow(size_t page_index, bool); diff --git a/Libraries/LibCore/CProcessStatisticsReader.cpp b/Libraries/LibCore/CProcessStatisticsReader.cpp index 07ba35f875..4e0adc8e13 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.cpp +++ b/Libraries/LibCore/CProcessStatisticsReader.cpp @@ -38,6 +38,7 @@ HashMap CProcessStatisticsReader::get_all() process.amount_virtual = process_object.get("amount_virtual").to_u32(); process.amount_resident = process_object.get("amount_resident").to_u32(); process.amount_shared = process_object.get("amount_shared").to_u32(); + process.amount_dirty_private = process_object.get("amount_dirty_private").to_u32(); process.amount_purgeable_volatile = process_object.get("amount_purgeable_volatile").to_u32(); process.amount_purgeable_nonvolatile = process_object.get("amount_purgeable_nonvolatile").to_u32(); process.icon_id = process_object.get("icon_id").to_int(); diff --git a/Libraries/LibCore/CProcessStatisticsReader.h b/Libraries/LibCore/CProcessStatisticsReader.h index 4fa3806782..34b353d85f 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.h +++ b/Libraries/LibCore/CProcessStatisticsReader.h @@ -39,6 +39,7 @@ struct CProcessStatistics { size_t amount_virtual; size_t amount_resident; size_t amount_shared; + size_t amount_dirty_private; size_t amount_purgeable_volatile; size_t amount_purgeable_nonvolatile; int icon_id;