summaryrefslogtreecommitdiffstats
path: root/mm/swapfile.c
diff options
context:
space:
mode:
authorMinchan Kim <minchan@kernel.org>2015-09-08 18:00:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-08 18:35:28 -0400
commit8334b96221ff0dcbde4873d31eb4d84774ed8ed4 (patch)
tree35c6f7a7ab427834a10c3e74ccedcac9911e588a /mm/swapfile.c
parent3115aec4513e5bcb399235cac98a5637fe641c13 (diff)
mm: /proc/pid/smaps:: show proportional swap share of the mapping
We want to know per-process workingset size for smart memory management on userland and we use swap(ex, zram) heavily to maximize memory efficiency so workingset includes swap as well as RSS. On such system, if there are lots of shared anonymous pages, it's really hard to figure out exactly how many each process consumes memory(ie, rss + wap) if the system has lots of shared anonymous memory(e.g, android). This patch introduces SwapPss field on /proc/<pid>/smaps so we can get more exact workingset size per process. Bongkyu tested it. Result is below. 1. 50M used swap SwapTotal: 461976 kB SwapFree: 411192 kB $ adb shell cat /proc/*/smaps | grep "SwapPss:" | awk '{sum += $2} END {print sum}'; 48236 $ adb shell cat /proc/*/smaps | grep "Swap:" | awk '{sum += $2} END {print sum}'; 141184 2. 240M used swap SwapTotal: 461976 kB SwapFree: 216808 kB $ adb shell cat /proc/*/smaps | grep "SwapPss:" | awk '{sum += $2} END {print sum}'; 230315 $ adb shell cat /proc/*/smaps | grep "Swap:" | awk '{sum += $2} END {print sum}'; 1387744 [akpm@linux-foundation.org: simplify kunmap_atomic() call] Signed-off-by: Minchan Kim <minchan@kernel.org> Reported-by: Bongkyu Kim <bongkyu.kim@lge.com> Tested-by: Bongkyu Kim <bongkyu.kim@lge.com> Cc: Hugh Dickins <hughd@google.com> Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Jerome Marchand <jmarchan@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/swapfile.c')
-rw-r--r--mm/swapfile.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c
index aebc2dd6e649..58877312cf6b 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -875,6 +875,48 @@ int page_swapcount(struct page *page)
875} 875}
876 876
877/* 877/*
878 * How many references to @entry are currently swapped out?
879 * This considers COUNT_CONTINUED so it returns exact answer.
880 */
881int swp_swapcount(swp_entry_t entry)
882{
883 int count, tmp_count, n;
884 struct swap_info_struct *p;
885 struct page *page;
886 pgoff_t offset;
887 unsigned char *map;
888
889 p = swap_info_get(entry);
890 if (!p)
891 return 0;
892
893 count = swap_count(p->swap_map[swp_offset(entry)]);
894 if (!(count & COUNT_CONTINUED))
895 goto out;
896
897 count &= ~COUNT_CONTINUED;
898 n = SWAP_MAP_MAX + 1;
899
900 offset = swp_offset(entry);
901 page = vmalloc_to_page(p->swap_map + offset);
902 offset &= ~PAGE_MASK;
903 VM_BUG_ON(page_private(page) != SWP_CONTINUED);
904
905 do {
906 page = list_entry(page->lru.next, struct page, lru);
907 map = kmap_atomic(page);
908 tmp_count = map[offset];
909 kunmap_atomic(map);
910
911 count += (tmp_count & ~COUNT_CONTINUED) * n;
912 n *= (SWAP_CONT_MAX + 1);
913 } while (tmp_count & COUNT_CONTINUED);
914out:
915 spin_unlock(&p->lock);
916 return count;
917}
918
919/*
878 * We can write to an anon page without COW if there are no other references 920 * We can write to an anon page without COW if there are no other references
879 * to it. And as a side-effect, free up its swap: because the old content 921 * to it. And as a side-effect, free up its swap: because the old content
880 * on disk will never be read, and seeking back there to write new content 922 * on disk will never be read, and seeking back there to write new content