diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp index d84b52e59f..88fa965907 100644 --- a/Applications/SystemMonitor/ProcessModel.cpp +++ b/Applications/SystemMonitor/ProcessModel.cpp @@ -61,6 +61,8 @@ String ProcessModel::column_name(int column) const return "Physical"; case Column::DirtyPrivate: return "DirtyP"; + case Column::CleanInode: + return "CleanI"; case Column::PurgeableVolatile: return "Purg:V"; case Column::PurgeableNonvolatile: @@ -115,6 +117,8 @@ GModel::ColumnMetadata ProcessModel::column_metadata(int column) const return { 65, TextAlignment::CenterRight }; case Column::DirtyPrivate: return { 65, TextAlignment::CenterRight }; + case Column::CleanInode: + return { 65, TextAlignment::CenterRight }; case Column::PurgeableVolatile: return { 65, TextAlignment::CenterRight }; case Column::PurgeableNonvolatile: @@ -189,6 +193,8 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const return (int)thread.current_state.amount_resident; case Column::DirtyPrivate: return (int)thread.current_state.amount_dirty_private; + case Column::CleanInode: + return (int)thread.current_state.amount_clean_inode; case Column::PurgeableVolatile: return (int)thread.current_state.amount_purgeable_volatile; case Column::PurgeableNonvolatile: @@ -258,6 +264,8 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const return pretty_byte_size(thread.current_state.amount_resident); case Column::DirtyPrivate: return pretty_byte_size(thread.current_state.amount_dirty_private); + case Column::CleanInode: + return pretty_byte_size(thread.current_state.amount_clean_inode); case Column::PurgeableVolatile: return pretty_byte_size(thread.current_state.amount_purgeable_volatile); case Column::PurgeableNonvolatile: @@ -320,6 +328,7 @@ void ProcessModel::update() 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_clean_inode = it.value.amount_clean_inode; 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 e8a38d5948..cccedbcb3a 100644 --- a/Applications/SystemMonitor/ProcessModel.h +++ b/Applications/SystemMonitor/ProcessModel.h @@ -31,6 +31,7 @@ public: Virtual, Physical, DirtyPrivate, + CleanInode, PurgeableVolatile, PurgeableNonvolatile, Syscalls, @@ -74,6 +75,7 @@ private: size_t amount_virtual; size_t amount_resident; size_t amount_dirty_private; + size_t amount_clean_inode; 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 00aacacfaf..a3ea6c78ae 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -754,6 +754,7 @@ Optional procfs$all(InodeIdentifier) 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_clean_inode", (u32)process.amount_clean_inode()); 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 dd7f6f1f71..91d870fd6d 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2504,6 +2504,9 @@ void Process::die() size_t Process::amount_dirty_private() const { + // FIXME: This gets a bit more complicated for Regions sharing the same underlying VMObject. + // The main issue I'm thinking of is when the VMObject has physical pages that none of the Regions are mapping. + // That's probably a situation that needs to be looked at in general. size_t amount = 0; for (auto& region : m_regions) { if (!region.is_shared()) @@ -2512,6 +2515,19 @@ size_t Process::amount_dirty_private() const return amount; } +size_t Process::amount_clean_inode() const +{ + HashTable vmobjects; + for (auto& region : m_regions) { + if (region.vmobject().is_inode()) + vmobjects.set(&static_cast(region.vmobject())); + } + size_t amount = 0; + for (auto& vmobject : vmobjects) + amount += vmobject->amount_clean(); + return amount; +} + size_t Process::amount_virtual() const { size_t amount = 0; diff --git a/Kernel/Process.h b/Kernel/Process.h index d4ad159dae..40fa865c15 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_clean_inode() const; size_t amount_dirty_private() const; size_t amount_virtual() const; size_t amount_resident() const; diff --git a/Kernel/VM/InodeVMObject.cpp b/Kernel/VM/InodeVMObject.cpp index 5edc9b3c20..65c1177988 100644 --- a/Kernel/VM/InodeVMObject.cpp +++ b/Kernel/VM/InodeVMObject.cpp @@ -36,6 +36,16 @@ InodeVMObject::~InodeVMObject() ASSERT(inode().vmobject() == this); } +size_t InodeVMObject::amount_clean() const +{ + size_t count = 0; + for (int i = 0; i < m_dirty_pages.size(); ++i) { + if (!m_dirty_pages.get(i) && m_physical_pages[i]) + ++count; + } + return count * PAGE_SIZE; +} + size_t InodeVMObject::amount_dirty() const { size_t count = 0; diff --git a/Kernel/VM/InodeVMObject.h b/Kernel/VM/InodeVMObject.h index 56e8b344d6..e4e44cff7f 100644 --- a/Kernel/VM/InodeVMObject.h +++ b/Kernel/VM/InodeVMObject.h @@ -17,6 +17,7 @@ public: void inode_size_changed(Badge, size_t old_size, size_t new_size); size_t amount_dirty() const; + size_t amount_clean() const; private: explicit InodeVMObject(Inode&); diff --git a/Libraries/LibCore/CProcessStatisticsReader.cpp b/Libraries/LibCore/CProcessStatisticsReader.cpp index 4e0adc8e13..cfd8f0b40c 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.cpp +++ b/Libraries/LibCore/CProcessStatisticsReader.cpp @@ -39,6 +39,7 @@ HashMap CProcessStatisticsReader::get_all() 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_clean_inode = process_object.get("amount_clean_inode").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 34b353d85f..a7b740d8f9 100644 --- a/Libraries/LibCore/CProcessStatisticsReader.h +++ b/Libraries/LibCore/CProcessStatisticsReader.h @@ -40,6 +40,7 @@ struct CProcessStatistics { size_t amount_resident; size_t amount_shared; size_t amount_dirty_private; + size_t amount_clean_inode; size_t amount_purgeable_volatile; size_t amount_purgeable_nonvolatile; int icon_id;