[PATCH 4/5] mm, shmem: Add shmem swap memory accounting
From: Jerome Marchand
Date: Tue Jul 01 2014 - 09:02:27 EST
Adds get_mm_shswap() which compute the size of swaped out shmem. It
does so by pagewalking the mm and using the new shmem_locate() function
to get the physical location of shmem pages.
The result is displayed in the new VmShSw line of /proc/<pid>/status.
Use mm_walk an shmem_locate() to account paged out shmem pages.
It significantly slows down /proc/<pid>/status acccess speed when
there is a big shmem mapping. If that is an issue, we can drop this
patch and only display this counter in the inherently slower
/proc/<pid>/smaps file (cf. next patch).
Signed-off-by: Jerome Marchand <jmarchan@xxxxxxxxxx>
---
Documentation/filesystems/proc.txt | 2 +
fs/proc/task_mmu.c | 80 ++++++++++++++++++++++++++++++++++++--
2 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 1c49957..1a15c56 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -172,6 +172,7 @@ read the file /proc/PID/status:
VmPTE: 20 kb
VmSwap: 0 kB
VmShm: 0 kB
+ VmShSw: 0 kB
Threads: 1
SigQ: 0/28578
SigPnd: 0000000000000000
@@ -230,6 +231,7 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7)
VmPTE size of page table entries
VmSwap size of swap usage (the number of referred swapents)
VmShm size of resident shmem memory
+ VmShSw size of paged out shmem memory
Threads number of threads
SigQ number of signals queued/max. number for queue
SigPnd bitmap of pending signals for the thread
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 4e60751..73f0ce4 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -19,9 +19,80 @@
#include <asm/tlbflush.h>
#include "internal.h"
+struct shswap_stats {
+ struct vm_area_struct *vma;
+ unsigned long shswap;
+};
+
+#ifdef CONFIG_SHMEM
+static int shswap_pte(pte_t *pte, unsigned long addr, unsigned long end,
+ struct mm_walk *walk)
+{
+ struct shswap_stats *shss = walk->private;
+ struct vm_area_struct *vma = shss->vma;
+ pgoff_t pgoff = linear_page_index(vma, addr);
+ pte_t ptent = *pte;
+
+ if (pte_none(ptent) &&
+ shmem_locate(vma, pgoff, NULL) == SHMEM_SWAP)
+ shss->shswap += end - addr;
+
+ return 0;
+}
+
+static int shswap_pte_hole(unsigned long addr, unsigned long end,
+ struct mm_walk *walk)
+{
+ struct shswap_stats *shss = walk->private;
+ struct vm_area_struct *vma = shss->vma;
+ pgoff_t pgoff;
+
+ for (; addr != end; addr += PAGE_SIZE) {
+ pgoff = linear_page_index(vma, addr);
+
+ if (shmem_locate(vma, pgoff, NULL) == SHMEM_SWAP)
+ shss->shswap += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static unsigned long get_mm_shswap(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+ struct shswap_stats shss;
+ struct mm_walk shswap_walk = {
+ .pte_entry = shswap_pte,
+ .pte_hole = shswap_pte_hole,
+ .mm = mm,
+ .private = &shss,
+ };
+
+ memset(&shss, 0, sizeof(shss));
+
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ if (shmem_vma(vma)) {
+ shss.vma = vma;
+ walk_page_range(vma->vm_start, vma->vm_end,
+ &shswap_walk);
+ }
+ up_read(&mm->mmap_sem);
+
+ return shss.shswap;
+}
+
+#else
+
+static unsigned long get_mm_shswap(struct mm_struct *mm)
+{
+ return 0;
+}
+#endif
+
void task_mem(struct seq_file *m, struct mm_struct *mm)
{
- unsigned long data, text, lib, swap, shmem;
+ unsigned long data, text, lib, swap, shmem, shswap;
unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss;
/*
@@ -43,6 +114,7 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text;
swap = get_mm_counter(mm, MM_SWAPENTS);
shmem = get_mm_counter(mm, MM_SHMEMPAGES);
+ shswap = get_mm_shswap(mm);
seq_printf(m,
"VmPeak:\t%8lu kB\n"
"VmSize:\t%8lu kB\n"
@@ -56,7 +128,8 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
"VmLib:\t%8lu kB\n"
"VmPTE:\t%8lu kB\n"
"VmSwap:\t%8lu kB\n"
- "VmShm:\t%8lu kB\n",
+ "VmShm:\t%8lu kB\n"
+ "VmShSw:\t%8lu kB\n",
hiwater_vm << (PAGE_SHIFT-10),
total_vm << (PAGE_SHIFT-10),
mm->locked_vm << (PAGE_SHIFT-10),
@@ -68,7 +141,8 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
(PTRS_PER_PTE * sizeof(pte_t) *
atomic_long_read(&mm->nr_ptes)) >> 10,
swap << (PAGE_SHIFT-10),
- shmem << (PAGE_SHIFT-10));
+ shmem << (PAGE_SHIFT-10),
+ shswap >> 10);
}
unsigned long task_vsize(struct mm_struct *mm)
--
1.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/