mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:38:11 +00:00
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.
This commit is contained in:
parent
ffbe975ffc
commit
0d5e0e4cad
12 changed files with 51 additions and 0 deletions
|
@ -18,6 +18,7 @@ ProcessMemoryMapWidget::ProcessMemoryMapWidget(GWidget* parent)
|
||||||
});
|
});
|
||||||
pid_vm_fields.empend("size", "Size", TextAlignment::CenterRight);
|
pid_vm_fields.empend("size", "Size", TextAlignment::CenterRight);
|
||||||
pid_vm_fields.empend("amount_resident", "Resident", 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) {
|
pid_vm_fields.empend("Access", TextAlignment::CenterLeft, [](auto& object) {
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
if (!object.get("user_accessible").to_bool())
|
if (!object.get("user_accessible").to_bool())
|
||||||
|
|
|
@ -59,6 +59,8 @@ String ProcessModel::column_name(int column) const
|
||||||
return "Virtual";
|
return "Virtual";
|
||||||
case Column::Physical:
|
case Column::Physical:
|
||||||
return "Physical";
|
return "Physical";
|
||||||
|
case Column::DirtyPrivate:
|
||||||
|
return "DirtyP";
|
||||||
case Column::PurgeableVolatile:
|
case Column::PurgeableVolatile:
|
||||||
return "Purg:V";
|
return "Purg:V";
|
||||||
case Column::PurgeableNonvolatile:
|
case Column::PurgeableNonvolatile:
|
||||||
|
@ -111,6 +113,8 @@ GModel::ColumnMetadata ProcessModel::column_metadata(int column) const
|
||||||
return { 65, TextAlignment::CenterRight };
|
return { 65, TextAlignment::CenterRight };
|
||||||
case Column::Physical:
|
case Column::Physical:
|
||||||
return { 65, TextAlignment::CenterRight };
|
return { 65, TextAlignment::CenterRight };
|
||||||
|
case Column::DirtyPrivate:
|
||||||
|
return { 65, TextAlignment::CenterRight };
|
||||||
case Column::PurgeableVolatile:
|
case Column::PurgeableVolatile:
|
||||||
return { 65, TextAlignment::CenterRight };
|
return { 65, TextAlignment::CenterRight };
|
||||||
case Column::PurgeableNonvolatile:
|
case Column::PurgeableNonvolatile:
|
||||||
|
@ -183,6 +187,8 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
|
||||||
return (int)thread.current_state.amount_virtual;
|
return (int)thread.current_state.amount_virtual;
|
||||||
case Column::Physical:
|
case Column::Physical:
|
||||||
return (int)thread.current_state.amount_resident;
|
return (int)thread.current_state.amount_resident;
|
||||||
|
case Column::DirtyPrivate:
|
||||||
|
return (int)thread.current_state.amount_dirty_private;
|
||||||
case Column::PurgeableVolatile:
|
case Column::PurgeableVolatile:
|
||||||
return (int)thread.current_state.amount_purgeable_volatile;
|
return (int)thread.current_state.amount_purgeable_volatile;
|
||||||
case Column::PurgeableNonvolatile:
|
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);
|
return pretty_byte_size(thread.current_state.amount_virtual);
|
||||||
case Column::Physical:
|
case Column::Physical:
|
||||||
return pretty_byte_size(thread.current_state.amount_resident);
|
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:
|
case Column::PurgeableVolatile:
|
||||||
return pretty_byte_size(thread.current_state.amount_purgeable_volatile);
|
return pretty_byte_size(thread.current_state.amount_purgeable_volatile);
|
||||||
case Column::PurgeableNonvolatile:
|
case Column::PurgeableNonvolatile:
|
||||||
|
@ -311,6 +319,7 @@ void ProcessModel::update()
|
||||||
state.file_write_bytes = thread.file_write_bytes;
|
state.file_write_bytes = thread.file_write_bytes;
|
||||||
state.amount_virtual = it.value.amount_virtual;
|
state.amount_virtual = it.value.amount_virtual;
|
||||||
state.amount_resident = it.value.amount_resident;
|
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_volatile = it.value.amount_purgeable_volatile;
|
||||||
state.amount_purgeable_nonvolatile = it.value.amount_purgeable_nonvolatile;
|
state.amount_purgeable_nonvolatile = it.value.amount_purgeable_nonvolatile;
|
||||||
state.icon_id = it.value.icon_id;
|
state.icon_id = it.value.icon_id;
|
||||||
|
|
|
@ -30,6 +30,7 @@ public:
|
||||||
TID,
|
TID,
|
||||||
Virtual,
|
Virtual,
|
||||||
Physical,
|
Physical,
|
||||||
|
DirtyPrivate,
|
||||||
PurgeableVolatile,
|
PurgeableVolatile,
|
||||||
PurgeableNonvolatile,
|
PurgeableNonvolatile,
|
||||||
Syscalls,
|
Syscalls,
|
||||||
|
@ -72,6 +73,7 @@ private:
|
||||||
String priority;
|
String priority;
|
||||||
size_t amount_virtual;
|
size_t amount_virtual;
|
||||||
size_t amount_resident;
|
size_t amount_resident;
|
||||||
|
size_t amount_dirty_private;
|
||||||
size_t amount_purgeable_volatile;
|
size_t amount_purgeable_volatile;
|
||||||
size_t amount_purgeable_nonvolatile;
|
size_t amount_purgeable_nonvolatile;
|
||||||
unsigned syscall_count;
|
unsigned syscall_count;
|
||||||
|
|
|
@ -275,6 +275,7 @@ Optional<KBuffer> procfs$pid_vm(InodeIdentifier identifier)
|
||||||
region_object.add("address", region.vaddr().get());
|
region_object.add("address", region.vaddr().get());
|
||||||
region_object.add("size", (u32)region.size());
|
region_object.add("size", (u32)region.size());
|
||||||
region_object.add("amount_resident", (u32)region.amount_resident());
|
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("cow_pages", region.cow_pages());
|
||||||
region_object.add("name", region.name());
|
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("tty", process.tty() ? process.tty()->tty_name() : "notty");
|
||||||
process_object.add("amount_virtual", (u32)process.amount_virtual());
|
process_object.add("amount_virtual", (u32)process.amount_virtual());
|
||||||
process_object.add("amount_resident", (u32)process.amount_resident());
|
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_shared", (u32)process.amount_shared());
|
||||||
process_object.add("amount_purgeable_volatile", (u32)process.amount_purgeable_volatile());
|
process_object.add("amount_purgeable_volatile", (u32)process.amount_purgeable_volatile());
|
||||||
process_object.add("amount_purgeable_nonvolatile", (u32)process.amount_purgeable_nonvolatile());
|
process_object.add("amount_purgeable_nonvolatile", (u32)process.amount_purgeable_nonvolatile());
|
||||||
|
|
|
@ -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 Process::amount_virtual() const
|
||||||
{
|
{
|
||||||
size_t amount = 0;
|
size_t amount = 0;
|
||||||
|
|
|
@ -272,6 +272,7 @@ public:
|
||||||
int number_of_open_file_descriptors() const;
|
int number_of_open_file_descriptors() const;
|
||||||
int max_open_file_descriptors() const { return m_max_open_file_descriptors; }
|
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_virtual() const;
|
||||||
size_t amount_resident() const;
|
size_t amount_resident() const;
|
||||||
size_t amount_shared() const;
|
size_t amount_shared() const;
|
||||||
|
|
|
@ -21,6 +21,7 @@ NonnullRefPtr<VMObject> InodeVMObject::clone()
|
||||||
InodeVMObject::InodeVMObject(Inode& inode)
|
InodeVMObject::InodeVMObject(Inode& inode)
|
||||||
: VMObject(inode.size())
|
: VMObject(inode.size())
|
||||||
, m_inode(inode)
|
, m_inode(inode)
|
||||||
|
, m_dirty_pages(page_count(), false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +36,16 @@ InodeVMObject::~InodeVMObject()
|
||||||
ASSERT(inode().vmobject() == this);
|
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)
|
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",
|
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;
|
auto new_page_count = PAGE_ROUND_UP(new_size) / PAGE_SIZE;
|
||||||
m_physical_pages.resize(new_page_count);
|
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.
|
// FIXME: Consolidate with inode_contents_changed() so we only do a single walk.
|
||||||
for_each_region([](auto& region) {
|
for_each_region([](auto& region) {
|
||||||
region.remap();
|
region.remap();
|
||||||
|
|
|
@ -16,6 +16,8 @@ public:
|
||||||
void inode_contents_changed(Badge<Inode>, off_t, ssize_t, const u8*);
|
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);
|
void inode_size_changed(Badge<Inode>, size_t old_size, size_t new_size);
|
||||||
|
|
||||||
|
size_t amount_dirty() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit InodeVMObject(Inode&);
|
explicit InodeVMObject(Inode&);
|
||||||
explicit InodeVMObject(const InodeVMObject&);
|
explicit InodeVMObject(const InodeVMObject&);
|
||||||
|
@ -27,4 +29,5 @@ private:
|
||||||
virtual bool is_inode() const override { return true; }
|
virtual bool is_inode() const override { return true; }
|
||||||
|
|
||||||
NonnullRefPtr<Inode> m_inode;
|
NonnullRefPtr<Inode> m_inode;
|
||||||
|
Bitmap m_dirty_pages;
|
||||||
};
|
};
|
||||||
|
|
|
@ -133,6 +133,13 @@ u32 Region::cow_pages() const
|
||||||
return count;
|
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 Region::amount_resident() const
|
||||||
{
|
{
|
||||||
size_t bytes = 0;
|
size_t bytes = 0;
|
||||||
|
|
|
@ -103,6 +103,7 @@ public:
|
||||||
|
|
||||||
size_t amount_resident() const;
|
size_t amount_resident() const;
|
||||||
size_t amount_shared() const;
|
size_t amount_shared() const;
|
||||||
|
size_t amount_dirty() const;
|
||||||
|
|
||||||
bool should_cow(size_t page_index) const;
|
bool should_cow(size_t page_index) const;
|
||||||
void set_should_cow(size_t page_index, bool);
|
void set_should_cow(size_t page_index, bool);
|
||||||
|
|
|
@ -38,6 +38,7 @@ HashMap<pid_t, CProcessStatistics> CProcessStatisticsReader::get_all()
|
||||||
process.amount_virtual = process_object.get("amount_virtual").to_u32();
|
process.amount_virtual = process_object.get("amount_virtual").to_u32();
|
||||||
process.amount_resident = process_object.get("amount_resident").to_u32();
|
process.amount_resident = process_object.get("amount_resident").to_u32();
|
||||||
process.amount_shared = process_object.get("amount_shared").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_volatile = process_object.get("amount_purgeable_volatile").to_u32();
|
||||||
process.amount_purgeable_nonvolatile = process_object.get("amount_purgeable_nonvolatile").to_u32();
|
process.amount_purgeable_nonvolatile = process_object.get("amount_purgeable_nonvolatile").to_u32();
|
||||||
process.icon_id = process_object.get("icon_id").to_int();
|
process.icon_id = process_object.get("icon_id").to_int();
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct CProcessStatistics {
|
||||||
size_t amount_virtual;
|
size_t amount_virtual;
|
||||||
size_t amount_resident;
|
size_t amount_resident;
|
||||||
size_t amount_shared;
|
size_t amount_shared;
|
||||||
|
size_t amount_dirty_private;
|
||||||
size_t amount_purgeable_volatile;
|
size_t amount_purgeable_volatile;
|
||||||
size_t amount_purgeable_nonvolatile;
|
size_t amount_purgeable_nonvolatile;
|
||||||
int icon_id;
|
int icon_id;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue