summaryrefslogtreecommitdiffstats
path: root/mm/swapfile.c
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2017-07-06 18:40:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 19:24:35 -0400
commit155b5f88e734e56997b3fe89e176571c53754fed (patch)
treed41283e002f63f1c8aa2b08e9151a47f9ff310ca /mm/swapfile.c
parent8e675f7af50747e1e9e96538e8706767e4f80e2c (diff)
mm/swapfile.c: sort swap entries before free
To reduce the lock contention of swap_info_struct->lock when freeing swap entry. The freed swap entries will be collected in a per-CPU buffer firstly, and be really freed later in batch. During the batch freeing, if the consecutive swap entries in the per-CPU buffer belongs to same swap device, the swap_info_struct->lock needs to be acquired/released only once, so that the lock contention could be reduced greatly. But if there are multiple swap devices, it is possible that the lock may be unnecessarily released/acquired because the swap entries belong to the same swap device are non-consecutive in the per-CPU buffer. To solve the issue, the per-CPU buffer is sorted according to the swap device before freeing the swap entries. With the patch, the memory (some swapped out) free time reduced 11.6% (from 2.65s to 2.35s) in the vm-scalability swap-w-rand test case with 16 processes. The test is done on a Xeon E5 v3 system. The swap device used is a RAM simulated PMEM (persistent memory) device. To test swapping, the test case creates 16 processes, which allocate and write to the anonymous pages until the RAM and part of the swap device is used up, finally the memory (some swapped out) is freed before exit. [akpm@linux-foundation.org: tweak comment] Link: http://lkml.kernel.org/r/20170525005916.25249-1-ying.huang@intel.com Signed-off-by: Huang Ying <ying.huang@intel.com> Acked-by: Tim Chen <tim.c.chen@intel.com> Cc: Hugh Dickins <hughd@google.com> Cc: Shaohua Li <shli@kernel.org> Cc: Minchan Kim <minchan@kernel.org> Cc: Rik van Riel <riel@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.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 8a6cdf9e55f9..811d90e1c929 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -37,6 +37,7 @@
37#include <linux/swapfile.h> 37#include <linux/swapfile.h>
38#include <linux/export.h> 38#include <linux/export.h>
39#include <linux/swap_slots.h> 39#include <linux/swap_slots.h>
40#include <linux/sort.h>
40 41
41#include <asm/pgtable.h> 42#include <asm/pgtable.h>
42#include <asm/tlbflush.h> 43#include <asm/tlbflush.h>
@@ -1198,6 +1199,13 @@ void put_swap_page(struct page *page, swp_entry_t entry)
1198 swapcache_free_cluster(entry); 1199 swapcache_free_cluster(entry);
1199} 1200}
1200 1201
1202static int swp_entry_cmp(const void *ent1, const void *ent2)
1203{
1204 const swp_entry_t *e1 = ent1, *e2 = ent2;
1205
1206 return (int)swp_type(*e1) - (int)swp_type(*e2);
1207}
1208
1201void swapcache_free_entries(swp_entry_t *entries, int n) 1209void swapcache_free_entries(swp_entry_t *entries, int n)
1202{ 1210{
1203 struct swap_info_struct *p, *prev; 1211 struct swap_info_struct *p, *prev;
@@ -1208,6 +1216,14 @@ void swapcache_free_entries(swp_entry_t *entries, int n)
1208 1216
1209 prev = NULL; 1217 prev = NULL;
1210 p = NULL; 1218 p = NULL;
1219
1220 /*
1221 * Sort swap entries by swap device, so each lock is only taken once.
1222 * nr_swapfiles isn't absolutely correct, but the overhead of sort() is
1223 * so low that it isn't necessary to optimize further.
1224 */
1225 if (nr_swapfiles > 1)
1226 sort(entries, n, sizeof(entries[0]), swp_entry_cmp, NULL);
1211 for (i = 0; i < n; ++i) { 1227 for (i = 0; i < n; ++i) {
1212 p = swap_info_get_cont(entries[i], prev); 1228 p = swap_info_get_cont(entries[i], prev);
1213 if (p) 1229 if (p)