Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1641570 > unrolled thread
| Started by | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| First post | 2017-05-15 13:30 +0200 |
| Last post | 2017-05-15 13:30 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH -mm -v11 0/5] THP swap: Delay splitting THP during swapping out "Huang, Ying" <ying.huang@intel.com> - 2017-05-15 13:30 +0200
[PATCH -mm -v11 2/5] mm, THP, swap: Unify swap slot free functions to put_swap_page "Huang, Ying" <ying.huang@intel.com> - 2017-05-15 13:30 +0200
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2017-05-15 13:30 +0200 |
| Subject | [PATCH -mm -v11 0/5] THP swap: Delay splitting THP during swapping out |
| Message-ID | <tHmmm-7sA-3@gated-at.bofh.it> |
From: Huang Ying <ying.huang@intel.com> This patchset is to optimize the performance of Transparent Huge Page (THP) swap. Recently, the performance of the storage devices improved so fast that we cannot saturate the disk bandwidth with single logical CPU when do page swap out even on a high-end server machine. Because the performance of the storage device improved faster than that of single logical CPU. And it seems that the trend will not change in the near future. On the other hand, the THP becomes more and more popular because of increased memory size. So it becomes necessary to optimize THP swap performance. The advantages of the THP swap support include: - Batch the swap operations for the THP to reduce lock acquiring/releasing, including allocating/freeing the swap space, adding/deleting to/from the swap cache, and writing/reading the swap space, etc. This will help improve the performance of the THP swap. - The THP swap space read/write will be 2M sequential IO. It is particularly helpful for the swap read, which are usually 4k random IO. This will improve the performance of the THP swap too. - It will help the memory fragmentation, especially when the THP is heavily used by the applications. The 2M continuous pages will be free up after THP swapping out. - It will improve the THP utilization on the system with the swap turned on. Because the speed for khugepaged to collapse the normal pages into the THP is quite slow. After the THP is split during the swapping out, it will take quite long time for the normal pages to collapse back into the THP after being swapped in. The high THP utilization helps the efficiency of the page based memory management too. There are some concerns regarding THP swap in, mainly because possible enlarged read/write IO size (for swap in/out) may put more overhead on the storage device. To deal with that, the THP swap in should be turned on only when necessary. For example, it can be selected via "always/never/madvise" logic, to be turned on globally, turned off globally, or turned on only for VMA with MADV_HUGEPAGE, etc. This patchset is based on 04/13 head of mmotm/master. This patchset is the first step for the THP swap support. The plan is to delay splitting THP step by step, finally avoid splitting THP during the THP swapping out and swap out/in the THP as a whole. As the first step, in this patchset, the splitting huge page is delayed from almost the first step of swapping out to after allocating the swap space for the THP and adding the THP into the swap cache. This will reduce lock acquiring/releasing for the locks used for the swap cache management. With the patchset, the swap out throughput improves 15.5% (from about 3.73GB/s to about 4.31GB/s) in the vm-scalability swap-w-seq test case with 8 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 creates 8 processes, which sequentially allocate and write to the anonymous pages until the RAM and part of the swap device is used up. Changelog: v11: - Rebased on latest -mm tree - Integrate Minchan's patches to clean up swapcache_free() and add_to_swap() interface. - Revise condition for huge allocation in get_swap_page() to avoid to turn on THP swap optimization unintentionally. - Move can_split_huge_page() and compount_mapcount() checking into shrink_page_list(). v10: - Remove unlikely() in add_to_swap() per Johannes' comments - Improve code comments in add_to_swap() and mem_cgroup_try_charge_swap() v9: - Rebased on latest -mm tree - Johannes done extensive cleanups and simplifications - Johannes resolved the code size increases - Update the test results v8: - Rebased on latest -mm tree - Reorganize the patchset per Johannes' comments - Merge add_to_swap_trans_huge() and add_to_swap() per Johannes' comments v7: - Rebased on latest -mm tree - Revise get_swap_pages() THP support per Tim's comments v6: - Rebased on latest -mm tree (cluster lock, etc). - Fix a potential uninitialized variable bug in __swap_entry_free() - Revise the swap read-ahead changes to avoid a potential race condition between swap off and swap out in theory. v5: - Per Hillf's comments, fix a locking bug in error path of __add_to_swap_cache(). And merge the code to calculate extra_pins into can_split_huge_page(). v4: - Per Johannes' comments, simplified swap cgroup array accessing code. - Per Kirill and Dave Hansen's comments, used HPAGE_PMD_NR instead of HPAGE_SIZE/PAGE_SIZE. - Per Anshuman's comments, used HPAGE_PMD_NR instead of 512 in patch description. v3: - Per Andrew's suggestion, used a more systematical way to determine whether to enable THP swap optimization - Per Andrew's comments, moved as much as possible code into #ifdef CONFIG_TRANSPARENT_HUGE_PAGE/#endif or "if (PageTransHuge())" - Fixed some coding style warning. v2: - Original [1/11] sent separately and merged - Use switch in 10/10 per Hiff's suggestion Best Regards, Huang, Ying
[toc] | [next] | [standalone]
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2017-05-15 13:30 +0200 |
| Subject | [PATCH -mm -v11 2/5] mm, THP, swap: Unify swap slot free functions to put_swap_page |
| Message-ID | <tHmmn-7sA-25@gated-at.bofh.it> |
| In reply to | #1641570 |
From: Minchan Kim <minchan@kernel.org>
Now, get_swap_page takes struct page and allocates swap space
according to page size(ie, normal or THP) so it would be more
cleaner to introduce put_swap_page which is a counter function
of get_swap_page. Then, it calls right swap slot free function
depending on page's size.
[ying.huang@intel.com: minor cleanup and fix]
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Minchan Kim <minchan@kernel.org>
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
---
include/linux/swap.h | 12 ++----------
mm/shmem.c | 2 +-
mm/swap_state.c | 13 +++----------
mm/swapfile.c | 16 ++++++++++++++--
mm/vmscan.c | 2 +-
5 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d18876384de0..ead6fd7966b4 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -387,6 +387,7 @@ static inline long get_nr_swap_pages(void)
extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(struct page *page);
+extern void put_swap_page(struct page *page, swp_entry_t entry);
extern swp_entry_t get_swap_page_of_type(int);
extern int get_swap_pages(int n, bool cluster, swp_entry_t swp_entries[]);
extern int add_swap_count_continuation(swp_entry_t, gfp_t);
@@ -394,7 +395,6 @@ extern void swap_shmem_alloc(swp_entry_t);
extern int swap_duplicate(swp_entry_t);
extern int swapcache_prepare(swp_entry_t);
extern void swap_free(swp_entry_t);
-extern void swapcache_free(swp_entry_t);
extern void swapcache_free_entries(swp_entry_t *entries, int n);
extern int free_swap_and_cache(swp_entry_t);
extern int swap_type_of(dev_t, sector_t, struct block_device **);
@@ -453,7 +453,7 @@ static inline void swap_free(swp_entry_t swp)
{
}
-static inline void swapcache_free(swp_entry_t swp)
+static inline void put_swap_page(struct page *page, swp_entry_t swp)
{
}
@@ -578,13 +578,5 @@ static inline bool mem_cgroup_swap_full(struct page *page)
}
#endif
-#ifdef CONFIG_THP_SWAP
-extern void swapcache_free_cluster(swp_entry_t entry);
-#else
-static inline void swapcache_free_cluster(swp_entry_t entry)
-{
-}
-#endif
-
#endif /* __KERNEL__*/
#endif /* _LINUX_SWAP_H */
diff --git a/mm/shmem.c b/mm/shmem.c
index 29948d7da172..82158edaefdb 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1326,7 +1326,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
mutex_unlock(&shmem_swaplist_mutex);
free_swap:
- swapcache_free(swap);
+ put_swap_page(page, swap);
redirty:
set_page_dirty(page);
if (wbc->for_reclaim)
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 16ff89d058f4..0ad214d7a7ad 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -231,10 +231,7 @@ int add_to_swap(struct page *page, struct list_head *list)
return 1;
fail_free:
- if (PageTransHuge(page))
- swapcache_free_cluster(entry);
- else
- swapcache_free(entry);
+ put_swap_page(page, entry);
fail:
if (PageTransHuge(page) && !split_huge_page_to_list(page, list))
goto retry;
@@ -259,11 +256,7 @@ void delete_from_swap_cache(struct page *page)
__delete_from_swap_cache(page);
spin_unlock_irq(&address_space->tree_lock);
- if (PageTransHuge(page))
- swapcache_free_cluster(entry);
- else
- swapcache_free(entry);
-
+ put_swap_page(page, entry);
page_ref_sub(page, hpage_nr_pages(page));
}
@@ -415,7 +408,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
* add_to_swap_cache() doesn't return -EEXIST, so we can safely
* clear SWAP_HAS_CACHE flag.
*/
- swapcache_free(entry);
+ put_swap_page(new_page, entry);
} while (err != -ENOMEM);
if (new_page)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f4c0f2a92bf0..90b91f48d401 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1148,7 +1148,7 @@ void swap_free(swp_entry_t entry)
/*
* Called after dropping swapcache to decrease refcnt to swap entries.
*/
-void swapcache_free(swp_entry_t entry)
+static void swapcache_free(swp_entry_t entry)
{
struct swap_info_struct *p;
@@ -1160,7 +1160,7 @@ void swapcache_free(swp_entry_t entry)
}
#ifdef CONFIG_THP_SWAP
-void swapcache_free_cluster(swp_entry_t entry)
+static void swapcache_free_cluster(swp_entry_t entry)
{
unsigned long offset = swp_offset(entry);
unsigned long idx = offset / SWAPFILE_CLUSTER;
@@ -1184,8 +1184,20 @@ void swapcache_free_cluster(swp_entry_t entry)
swap_free_cluster(si, idx);
spin_unlock(&si->lock);
}
+#else
+static inline void swapcache_free_cluster(swp_entry_t entry)
+{
+}
#endif /* CONFIG_THP_SWAP */
+void put_swap_page(struct page *page, swp_entry_t entry)
+{
+ if (!PageTransHuge(page))
+ swapcache_free(entry);
+ else
+ swapcache_free_cluster(entry);
+}
+
void swapcache_free_entries(swp_entry_t *entries, int n)
{
struct swap_info_struct *p, *prev;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9f6c7ae5857f..b39ccabbe2dc 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -708,7 +708,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
mem_cgroup_swapout(page, swap);
__delete_from_swap_cache(page);
spin_unlock_irqrestore(&mapping->tree_lock, flags);
- swapcache_free(swap);
+ put_swap_page(page, swap);
} else {
void (*freepage)(struct page *);
void *shadow = NULL;
--
2.11.0
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web