summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-12-29 12:28:32 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-12-29 12:28:32 +0100
commit0d5e0e4cad512ebdcebc1c9a9171c412fcabbd3b (patch)
treea2de0fd9c829c96cd564413cae634319fb227ff8
parentffbe975ffc0e1a442247c5ff0a62b89aad9ac0a5 (diff)
downloadserenity-0d5e0e4cad512ebdcebc1c9a9171c412fcabbd3b.zip
Kernel+SystemMonitor: Expose amount of per-process dirty private memory
Dirty private memory is all memory in non-inode-backed mappings that's process-private, meaning it's not shared with any other process. This patch exposes that number via SystemMonitor, giving us an idea of how much memory each process is responsible for all on its own.
-rw-r--r--Applications/SystemMonitor/ProcessMemoryMapWidget.cpp1
-rw-r--r--Applications/SystemMonitor/ProcessModel.cpp9
-rw-r--r--Applications/SystemMonitor/ProcessModel.h2
-rw-r--r--Kernel/FileSystem/ProcFS.cpp2
-rw-r--r--Kernel/Process.cpp10
-rw-r--r--Kernel/Process.h1
-rw-r--r--Kernel/VM/InodeVMObject.cpp13
-rw-r--r--Kernel/VM/InodeVMObject.h3
-rw-r--r--Kernel/VM/Region.cpp7
-rw-r--r--Kernel/VM/Region.h1
-rw-r--r--Libraries/LibCore/CProcessStatisticsReader.cpp1
-rw-r--r--Libraries/LibCore/CProcessStatisticsReader.h1
12 files changed, 51 insertions, 0 deletions
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<KBuffer> 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<KBuffer> 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<VMObject> 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<Inode>, 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<Inode>, 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<Inode>, off_t, ssize_t, const u8*);
void inode_size_changed(Badge<Inode>, 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<Inode> 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<const InodeVMObject&>(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<pid_t, CProcessStatistics> 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;