mm/swap: Add cluster lock
Subsystems (2)
PATCH 2/8 mm/swap: Add cluster lock
From: "Huang, Ying" <[email protected]>
This patch is to reduce the lock contention of swap_info_struct->lock via using a more fine grained lock in swap_cluster_info for some swap operations. swap_info_struct->lock is heavily contended if multiple processes reclaim pages simultaneously. Because there is only one lock for each swap device. While in common configuration, there is only one or several swap devices in the system. The lock protects almost all swap related operations.
In fact, many swap operations only access one element of swap_info_struct->swap_map array. And there is no dependency between different elements of swap_info_struct->swap_map. So a fine grained lock can be used to allow parallel access to the different elements of swap_info_struct->swap_map.
In this patch, one bit of swap_cluster_info is used as the bin spinlock to protect the elements of swap_info_struct->swap_map in the swap cluster and the fields of swap_cluster_info. This reduced locking contention for swap_info_struct->swap_map access greatly.
To use the bin spinlock, the size of swap_cluster_info needs to increase from 4 bytes to 8 bytes on the 64bit system. This will use 4k more memory for every 1G swap space.
Because the size of swap_cluster_info is much smaller than the size of the cache line (8 vs 64 on x86_64 architecture), there may be false cache line sharing between swap_cluster_info bit spinlocks. To avoid the false sharing in the first round of the swap cluster allocation, the order of the swap clusters in the free clusters list is changed. So that, the swap_cluster_info sharing the same cache line will be placed as far as possible. After the first round of allocation, the order of the clusters in free clusters list is expected to be random. So the false sharing should be not noticeable.
On top of Mel Gorman's batching removing mapping patch and Huang Ying's patch to avoid to update the writeback tags for the swap cache pages. With the patch, the swap out throughput further improved 30.7% (from about 1.61GB/s to about 2.11GB/s) in the vm-scalability swap-w-seq 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 the sequential swapping out, the test case uses 16 processes, which sequentially allocate and write to the anonymous pages until the RAM and part of the swap device is used up.
--- include/linux/swap.h | 13 ++- mm/swapfile.c | 239 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 194 insertions(+), 58 deletions(-)
include/linux/swap.h +9 -4
@@ -175,11 +175,16 @@ enum {* protected by swap_info_struct.lock. */ struct swap_cluster_info { -unsigned int data:24 ; -unsigned int flags:8 ; +unsigned long data; }; -#define CLUSTER_FLAG_FREE 1/* This cluster is free */ -#define CLUSTER_FLAG_NEXT_NULL 2/* This cluster has no next cluster */ +#define CLUSTER_COUNT_SHIFT 8 +#define CLUSTER_FLAG_MASK ((1UL << CLUSTER_COUNT_SHIFT) - 1) +#define CLUSTER_COUNT_MASK (~CLUSTER_FLAG_MASK) +#define CLUSTER_FLAG_FREE 1/* This cluster is free */ +#define CLUSTER_FLAG_NEXT_NULL 2/* This cluster has no next cluster */ +/* cluster lock, protect cluster_info contents and sis->swap_map */ +#define CLUSTER_FLAG_LOCK_BIT 2 +#define CLUSTER_FLAG_LOCK (1 << CLUSTER_FLAG_LOCK_BIT)/* * We assign a cluster to each CPU, so each CPU can allocate swap entry from
mm/swapfile.c +185 -54
524 lines not on this page · raw message
Signature · 7 lines
2.5.5 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
On Wednesday, September 28, 2016 1:18 AM Tim Chen wrote
Quoted 13 lines
mm/swapfile.c +2
-1@@ -447,8 +505,9 @@ static void scan_swap_map_try_ssd_cluster(struct swap_info_struct *si, unsigned long *offset, unsigned long *scan_base) { struct percpu_cluster *cluster; +struct swap_cluster_info *ci;bool found_free; -unsigned long tmp; +unsigned long tmp, max; new_cluster: cluster =this_cpu_ptr (si->percpu_cluster);
mm/swapfile.c new_cluster: · line 480
Quoted 5 lines
mm/swapfile.c +0
-2@@ -476,14 +535,21 @@ new_cluster:* check if there is still free entry in the cluster */ tmp = cluster->next; -while (tmp < si->max && tmp < (cluster_next (&cluster->index) +1 ) * -SWAPFILE_CLUSTER ) {
Currently tmp is checked to be less than both values.
mm/swapfile.c new_cluster: · line 545
Quoted 8 lines
mm/swapfile.c +8
-0+ max = max_t(unsigned long, si->max, + (cluster_next (&cluster->index) +1 ) *SWAPFILE_CLUSTER ); +if (tmp >= max) { +cluster_set_null (&cluster->index); + goto new_cluster; + } + ci =lock_cluster (si, tmp); +while (tmp < max) {
In this work tmp is checked to be less than the max value. Semantic change hoped?
mm/swapfile.c new_cluster: · line 555
Quoted 11 lines
mm/swapfile.c +1
-0if (!si->swap_map[tmp]) { found_free = true;break ; } tmp++; } +unlock_cluster (ci);if (!found_free) {cluster_set_null (&cluster->index); goto new_cluster;
thanks
Hillf
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 22 lines · Hillf Danton
On Wednesday, September 28, 2016 1:18 AM Tim Chen wrote
Quoted 13 lines
mm/swapfile.c +2
-1@@ -447,8 +505,9 @@ static void scan_swap_map_try_ssd_cluster(struct swap_info_struct *si, unsigned long *offset, unsigned long *scan_base) { struct percpu_cluster *cluster; +struct swap_cluster_info *ci;bool found_free; -unsigned long tmp; +unsigned long tmp, max; new_cluster: cluster =this_cpu_ptr (si->percpu_cluster);mm/swapfile.c new_cluster: · line 480
Quoted 5 lines
mm/swapfile.c +0
-2@@ -476,14 +535,21 @@ new_cluster:* check if there is still free entry in the cluster */ tmp = cluster->next; -while (tmp < si->max && tmp < (cluster_next (&cluster->index) +1 ) * -SWAPFILE_CLUSTER ) {Currently tmp is checked to be less than both values.
Quoted 11 lines
mm/swapfile.c new_cluster: · line 545
Quoted 8 lines
mm/swapfile.c +8
-0+ max = max_t(unsigned long, si->max, + (cluster_next (&cluster->index) +1 ) *SWAPFILE_CLUSTER ); +if (tmp >= max) { +cluster_set_null (&cluster->index); + goto new_cluster; + } + ci =lock_cluster (si, tmp); +while (tmp < max) {In this work tmp is checked to be less than the max value. Semantic change hoped?
Oops! tmp should be checked to be more than the min value. Will fix it in the next version. Thanks for pointing out this!
Best Regards,
Huang, Ying
Quoted 5 lines
Quoted 5 lines
mm/swapfile.c +0
-0if (!si->swap_map[tmp]) { found_free = true;break ; } tmp++;
Quoted 8 lines
mm/swapfile.c new_cluster: · line 555
Quoted 6 lines
mm/swapfile.c +1
-0} +unlock_cluster (ci);if (!found_free) {cluster_set_null (&cluster->index); goto new_cluster;thanks
Hillf
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>