Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1478488 > unrolled thread
| Started by | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| First post | 2016-09-07 18:50 +0200 |
| Last post | 2016-09-09 07:50 +0200 |
| Articles | 20 on this page of 30 — 5 participants |
Back to article view | Back to linux.kernel
[PATCH -v3 00/10] THP swap: Delay splitting THP during swapping out "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
[PATCH -v3 02/10] mm, memcg: Add swap_cgroup_iter iterator "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
[PATCH -v3 08/10] mm, THP: Add can_split_huge_page() "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
Re: [PATCH -v3 08/10] mm, THP: Add can_split_huge_page() "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-09-08 13:20 +0200
Re: [PATCH -v3 08/10] mm, THP: Add can_split_huge_page() "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 19:10 +0200
[PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 Anshuman Khandual <khandual@linux.vnet.ibm.com> - 2016-09-08 10:30 +0200
Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 Anshuman Khandual <khandual@linux.vnet.ibm.com> - 2016-09-08 11:20 +0200
Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 20:10 +0200
Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-09-08 13:10 +0200
Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 19:40 +0200
Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-09-08 13:10 +0200
Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 19:30 +0200
[PATCH -v3 05/10] mm, THP, swap: Add get_huge_swap_page() "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
Re: [PATCH -v3 05/10] mm, THP, swap: Add get_huge_swap_page() "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-09-08 13:20 +0200
Re: [PATCH -v3 05/10] mm, THP, swap: Add get_huge_swap_page() "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 19:30 +0200
[PATCH -v3 09/10] mm, THP, swap: Support to split THP in swap cache "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
[PATCH -v3 06/10] mm, THP, swap: Support to clear SWAP_HAS_CACHE for huge page "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
[PATCH -v3 03/10] mm, memcg: Support to charge/uncharge multiple swap entries "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
Re: [PATCH -v3 03/10] mm, memcg: Support to charge/uncharge multiple swap entries Anshuman Khandual <khandual@linux.vnet.ibm.com> - 2016-09-08 10:30 +0200
Re: [PATCH -v3 03/10] mm, memcg: Support to charge/uncharge multiple swap entries "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 20:20 +0200
Re: [PATCH -v3 03/10] mm, memcg: Support to charge/uncharge multiple swap entries Anshuman Khandual <khandual@linux.vnet.ibm.com> - 2016-09-08 10:40 +0200
[PATCH -v3 04/10] mm, THP, swap: Add swap cluster allocate/free functions "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
Re: [PATCH -v3 04/10] mm, THP, swap: Add swap cluster allocate/free functions Anshuman Khandual <khandual@linux.vnet.ibm.com> - 2016-09-08 10:40 +0200
Re: [PATCH -v3 04/10] mm, THP, swap: Add swap cluster allocate/free functions "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 20:20 +0200
Re: [PATCH -v3 04/10] mm, THP, swap: Add swap cluster allocate/free functions Anshuman Khandual <khandual@linux.vnet.ibm.com> - 2016-09-08 11:00 +0200
[PATCH -v3 07/10] mm, THP, swap: Support to add/delete THP to/from swap cache "Huang, Ying" <ying.huang@intel.com> - 2016-09-07 18:50 +0200
Re: [PATCH -v3 07/10] mm, THP, swap: Support to add/delete THP to/from swap cache Anshuman Khandual <khandual@linux.vnet.ibm.com> - 2016-09-08 11:10 +0200
Re: [PATCH -v3 07/10] mm, THP, swap: Support to add/delete THP to/from swap cache "Huang\, Ying" <ying.huang@intel.com> - 2016-09-08 20:20 +0200
Re: [PATCH -v3 00/10] THP swap: Delay splitting THP during swapping out Minchan Kim <minchan@kernel.org> - 2016-09-09 07:50 +0200
Page 1 of 2 [1] 2 Next page →
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 00/10] THP swap: Delay splitting THP during swapping out |
| Message-ID | <seOcV-2cL-5@gated-at.bofh.it> |
From: Huang Ying <ying.huang@intel.com>
This patchset is to optimize the performance of Transparent Huge Page
(THP) swap.
Hi, Andrew, could you help me to check whether the overall design is
reasonable?
Hi, Hugh, Shaohua, Minchan and Rik, could you help me to review the
swap part of the patchset? Especially [01/10], [04/10], [05/10],
[06/10], [07/10], [10/10].
Hi, Andrea and Kirill, could you help me to review the THP part of the
patchset? Especially [02/10], [03/10], [09/10] and [10/10].
Hi, Johannes, Michal and Vladimir, I am not very confident about the
memory cgroup part, especially [02/10] and [03/10]. Could you help me
to review it?
And for all, Any comment is welcome!
Recently, the performance of the storage devices improved so fast that
we cannot saturate the disk bandwidth when do page swap out even on a
high-end server machine. Because the performance of the storage
device improved faster than that of 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 usually are 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.
This patchset is based on 8/31 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 12.1% (from about
1.12GB/s to about 1.25GB/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.
The detailed compare result is as follow,
base base+patchset
---------------- --------------------------
%stddev %change %stddev
\ | \
1118821 ± 0% +12.1% 1254241 ± 1% vmstat.swap.so
2460636 ± 1% +10.6% 2720983 ± 1% vm-scalability.throughput
308.79 ± 1% -7.9% 284.53 ± 1% vm-scalability.time.elapsed_time
1639 ± 4% +232.3% 5446 ± 1% meminfo.SwapCached
0.70 ± 3% +8.7% 0.77 ± 5% perf-stat.ipc
9.82 ± 8% -31.6% 6.72 ± 2% perf-profile.cycles-pp._raw_spin_lock_irq.__add_to_swap_cache.add_to_swap_cache.add_to_swap.shrink_page_list
From the swap out throughput number, we can find, even tested on a RAM
simulated PMEM (Persistent Memory) device, the swap out throughput can
reach only about 1.1GB/s. While, in the file IO test, the sequential
write throughput of an Intel P3700 SSD can reach about 1.8GB/s
steadily. And according the following URL,
https://www-ssl.intel.com/content/www/us/en/solid-state-drives/intel-ssd-dc-family-for-pcie.html
The sequential write throughput of Intel P3608 SSD can reach about
3.0GB/s, while the random read IOPS can reach about 850k. It is clear
that the bottleneck has moved from the disk to the kernel swap
component itself.
The improved storage device performance should have made the swap
becomes a better feature than before with better performance. But
because of the issues of kernel swap component itself, the swap
performance is still kept at the low level. That prevents the swap
feature to be used by more users. And this in turn causes few kernel
developers think it is necessary to optimize kernel swap component.
To break the loop, we need to optimize the performance of kernel swap
component. Optimize the THP swap performance is part of it.
Changelog:
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 | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 02/10] mm, memcg: Add swap_cgroup_iter iterator |
| Message-ID | <seOcW-2cL-19@gated-at.bofh.it> |
| In reply to | #1478488 |
From: Huang Ying <ying.huang@intel.com>
The swap cgroup uses a kind of discontinuous array to record the
information for the swap entries. lookup_swap_cgroup() provides a good
encapsulation to access one element of the discontinuous array. To make
it easier to access multiple elements of the discontinuous array, an
iterator for the swap cgroup named swap_cgroup_iter is added in this
patch.
This will be used for transparent huge page (THP) swap support. Where
the swap_cgroup for multiple swap entries will be changed together.
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Vladimir Davydov <vdavydov@virtuozzo.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: cgroups@vger.kernel.org
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
---
mm/swap_cgroup.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 47 insertions(+), 16 deletions(-)
diff --git a/mm/swap_cgroup.c b/mm/swap_cgroup.c
index 310ac0b..4ae3e7b 100644
--- a/mm/swap_cgroup.c
+++ b/mm/swap_cgroup.c
@@ -18,6 +18,13 @@ struct swap_cgroup {
};
#define SC_PER_PAGE (PAGE_SIZE/sizeof(struct swap_cgroup))
+struct swap_cgroup_iter {
+ struct swap_cgroup_ctrl *ctrl;
+ struct swap_cgroup *sc;
+ swp_entry_t entry;
+ unsigned long flags;
+};
+
/*
* SwapCgroup implements "lookup" and "exchange" operations.
* In typical usage, this swap_cgroup is accessed via memcg's charge/uncharge
@@ -75,6 +82,35 @@ static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
return sc + offset % SC_PER_PAGE;
}
+static void swap_cgroup_iter_init(struct swap_cgroup_iter *iter,
+ swp_entry_t ent)
+{
+ iter->entry = ent;
+ iter->sc = lookup_swap_cgroup(ent, &iter->ctrl);
+ spin_lock_irqsave(&iter->ctrl->lock, iter->flags);
+}
+
+static void swap_cgroup_iter_exit(struct swap_cgroup_iter *iter)
+{
+ spin_unlock_irqrestore(&iter->ctrl->lock, iter->flags);
+}
+
+/*
+ * swap_cgroup is stored in a kind of discontinuous array. That is,
+ * they are continuous in one page, but not across page boundary. And
+ * there is one lock for each page.
+ */
+static void swap_cgroup_iter_advance(struct swap_cgroup_iter *iter)
+{
+ iter->sc++;
+ iter->entry.val++;
+ if (!(((unsigned long)iter->sc) & PAGE_MASK)) {
+ spin_unlock_irqrestore(&iter->ctrl->lock, iter->flags);
+ iter->sc = lookup_swap_cgroup(iter->entry, &iter->ctrl);
+ spin_lock_irqsave(&iter->ctrl->lock, iter->flags);
+ }
+}
+
/**
* swap_cgroup_cmpxchg - cmpxchg mem_cgroup's id for this swp_entry.
* @ent: swap entry to be cmpxchged
@@ -87,20 +123,18 @@ static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
unsigned short old, unsigned short new)
{
- struct swap_cgroup_ctrl *ctrl;
- struct swap_cgroup *sc;
- unsigned long flags;
+ struct swap_cgroup_iter iter;
unsigned short retval;
- sc = lookup_swap_cgroup(ent, &ctrl);
+ swap_cgroup_iter_init(&iter, ent);
- spin_lock_irqsave(&ctrl->lock, flags);
- retval = sc->id;
+ retval = iter.sc->id;
if (retval == old)
- sc->id = new;
+ iter.sc->id = new;
else
retval = 0;
- spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ swap_cgroup_iter_exit(&iter);
return retval;
}
@@ -114,18 +148,15 @@ unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
*/
unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
{
- struct swap_cgroup_ctrl *ctrl;
- struct swap_cgroup *sc;
+ struct swap_cgroup_iter iter;
unsigned short old;
- unsigned long flags;
- sc = lookup_swap_cgroup(ent, &ctrl);
+ swap_cgroup_iter_init(&iter, ent);
- spin_lock_irqsave(&ctrl->lock, flags);
- old = sc->id;
- sc->id = id;
- spin_unlock_irqrestore(&ctrl->lock, flags);
+ old = iter.sc->id;
+ iter.sc->id = id;
+ swap_cgroup_iter_exit(&iter);
return old;
}
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 08/10] mm, THP: Add can_split_huge_page() |
| Message-ID | <seOcW-2cL-23@gated-at.bofh.it> |
| In reply to | #1478488 |
From: Huang Ying <ying.huang@intel.com>
Separates checking whether we can split the huge page from
split_huge_page_to_list() into a function. This will help to check that
before splitting the THP (Transparent Huge Page) really.
This will be used for delaying splitting THP during swapping out. Where
for a THP, we will allocate a swap cluster, add the THP into the swap
cache, then split the THP. To avoid the unnecessary operations for the
un-splittable THP, we will check that firstly.
There is no functionality change in this patch.
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Ebru Akagunduz <ebru.akagunduz@gmail.com>
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
---
include/linux/huge_mm.h | 6 ++++++
mm/huge_memory.c | 13 ++++++++++++-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index 9b9f65d..a0073e7 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -94,6 +94,7 @@ extern unsigned long thp_get_unmapped_area(struct file *filp,
extern void prep_transhuge_page(struct page *page);
extern void free_transhuge_page(struct page *page);
+bool can_split_huge_page(struct page *page);
int split_huge_page_to_list(struct page *page, struct list_head *list);
static inline int split_huge_page(struct page *page)
{
@@ -176,6 +177,11 @@ static inline void prep_transhuge_page(struct page *page) {}
#define thp_get_unmapped_area NULL
+static inline bool
+can_split_huge_page(struct page *page)
+{
+ return false;
+}
static inline int
split_huge_page_to_list(struct page *page, struct list_head *list)
{
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index fc0d37e..3be5abe 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2016,6 +2016,17 @@ int page_trans_huge_mapcount(struct page *page, int *total_mapcount)
return ret;
}
+/* Racy check whether the huge page can be split */
+bool can_split_huge_page(struct page *page)
+{
+ int extra_pins = 0;
+
+ /* Additional pins from radix tree */
+ if (!PageAnon(page))
+ extra_pins = HPAGE_PMD_NR;
+ return total_mapcount(page) == page_count(page) - extra_pins - 1;
+}
+
/*
* This function splits huge page into normal pages. @page can point to any
* subpage of huge page to split. Split doesn't change the position of @page.
@@ -2086,7 +2097,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
* Racy check if we can split the page, before freeze_page() will
* split PMDs
*/
- if (total_mapcount(head) != page_count(head) - extra_pins - 1) {
+ if (!can_split_huge_page(head)) {
ret = -EBUSY;
goto out_unlock;
}
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-09-08 13:20 +0200 |
| Subject | Re: [PATCH -v3 08/10] mm, THP: Add can_split_huge_page() |
| Message-ID | <sf5x8-56T-23@gated-at.bofh.it> |
| In reply to | #1478491 |
On Wed, Sep 07, 2016 at 09:46:07AM -0700, Huang, Ying wrote:
> From: Huang Ying <ying.huang@intel.com>
>
> Separates checking whether we can split the huge page from
> split_huge_page_to_list() into a function. This will help to check that
> before splitting the THP (Transparent Huge Page) really.
>
> This will be used for delaying splitting THP during swapping out. Where
> for a THP, we will allocate a swap cluster, add the THP into the swap
> cache, then split the THP. To avoid the unnecessary operations for the
> un-splittable THP, we will check that firstly.
>
> There is no functionality change in this patch.
>
> Cc: Andrea Arcangeli <aarcange@redhat.com>
> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
> Cc: Ebru Akagunduz <ebru.akagunduz@gmail.com>
> Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
> ---
> include/linux/huge_mm.h | 6 ++++++
> mm/huge_memory.c | 13 ++++++++++++-
> 2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
> index 9b9f65d..a0073e7 100644
> --- a/include/linux/huge_mm.h
> +++ b/include/linux/huge_mm.h
> @@ -94,6 +94,7 @@ extern unsigned long thp_get_unmapped_area(struct file *filp,
> extern void prep_transhuge_page(struct page *page);
> extern void free_transhuge_page(struct page *page);
>
> +bool can_split_huge_page(struct page *page);
> int split_huge_page_to_list(struct page *page, struct list_head *list);
> static inline int split_huge_page(struct page *page)
> {
> @@ -176,6 +177,11 @@ static inline void prep_transhuge_page(struct page *page) {}
>
> #define thp_get_unmapped_area NULL
>
> +static inline bool
> +can_split_huge_page(struct page *page)
> +{
BUILD_BUG() should be appropriate here.
> + return false;
> +}
> static inline int
> split_huge_page_to_list(struct page *page, struct list_head *list)
> {
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index fc0d37e..3be5abe 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2016,6 +2016,17 @@ int page_trans_huge_mapcount(struct page *page, int *total_mapcount)
> return ret;
> }
>
> +/* Racy check whether the huge page can be split */
> +bool can_split_huge_page(struct page *page)
> +{
> + int extra_pins = 0;
> +
> + /* Additional pins from radix tree */
> + if (!PageAnon(page))
> + extra_pins = HPAGE_PMD_NR;
> + return total_mapcount(page) == page_count(page) - extra_pins - 1;
> +}
> +
> /*
> * This function splits huge page into normal pages. @page can point to any
> * subpage of huge page to split. Split doesn't change the position of @page.
> @@ -2086,7 +2097,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
> * Racy check if we can split the page, before freeze_page() will
> * split PMDs
> */
> - if (total_mapcount(head) != page_count(head) - extra_pins - 1) {
> + if (!can_split_huge_page(head)) {
> ret = -EBUSY;
> goto out_unlock;
> }
> --
> 2.8.1
>
--
Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | "Huang\, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-08 19:10 +0200 |
| Subject | Re: [PATCH -v3 08/10] mm, THP: Add can_split_huge_page() |
| Message-ID | <sfaZP-8c-15@gated-at.bofh.it> |
| In reply to | #1479113 |
Hi, Kirill,
Thanks for your comments!
"Kirill A. Shutemov" <kirill@shutemov.name> writes:
> On Wed, Sep 07, 2016 at 09:46:07AM -0700, Huang, Ying wrote:
>> From: Huang Ying <ying.huang@intel.com>
>>
>> Separates checking whether we can split the huge page from
>> split_huge_page_to_list() into a function. This will help to check that
>> before splitting the THP (Transparent Huge Page) really.
>>
>> This will be used for delaying splitting THP during swapping out. Where
>> for a THP, we will allocate a swap cluster, add the THP into the swap
>> cache, then split the THP. To avoid the unnecessary operations for the
>> un-splittable THP, we will check that firstly.
>>
>> There is no functionality change in this patch.
>>
>> Cc: Andrea Arcangeli <aarcange@redhat.com>
>> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
>> Cc: Ebru Akagunduz <ebru.akagunduz@gmail.com>
>> Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
>> ---
>> include/linux/huge_mm.h | 6 ++++++
>> mm/huge_memory.c | 13 ++++++++++++-
>> 2 files changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
>> index 9b9f65d..a0073e7 100644
>> --- a/include/linux/huge_mm.h
>> +++ b/include/linux/huge_mm.h
>> @@ -94,6 +94,7 @@ extern unsigned long thp_get_unmapped_area(struct file *filp,
>> extern void prep_transhuge_page(struct page *page);
>> extern void free_transhuge_page(struct page *page);
>>
>> +bool can_split_huge_page(struct page *page);
>> int split_huge_page_to_list(struct page *page, struct list_head *list);
>> static inline int split_huge_page(struct page *page)
>> {
>> @@ -176,6 +177,11 @@ static inline void prep_transhuge_page(struct page *page) {}
>>
>> #define thp_get_unmapped_area NULL
>>
>> +static inline bool
>> +can_split_huge_page(struct page *page)
>> +{
>
> BUILD_BUG() should be appropriate here.
Yes. Will add it.
>> + return false;
>> +}
Best Regards,
Huang, Ying
[toc] | [prev] | [next] | [standalone]
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <seOcW-2cL-33@gated-at.bofh.it> |
| In reply to | #1478488 |
From: Huang Ying <ying.huang@intel.com> In this patch, the size of the swap cluster is changed to that of the THP (Transparent Huge Page) on x86_64 architecture (512). This is for the THP swap support on x86_64. Where one swap cluster will be used to hold the contents of each THP swapped out. And some information of the swapped out THP (such as compound map count) will be recorded in the swap_cluster_info data structure. For other architectures which want THP swap support, THP_SWAP_CLUSTER need to be selected in the Kconfig file for the architecture. In effect, this will enlarge swap cluster size by 2 times on x86_64. Which may make it harder to find a free cluster when the swap space becomes fragmented. So that, this may reduce the continuous swap space allocation and sequential write in theory. The performance test in 0day shows no regressions caused by this. 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> Suggested-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: "Huang, Ying" <ying.huang@intel.com> --- arch/x86/Kconfig | 1 + mm/Kconfig | 13 +++++++++++++ mm/swapfile.c | 4 ++++ 3 files changed, 18 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4c39728..421d862 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -164,6 +164,7 @@ config X86 select HAVE_STACK_VALIDATION if X86_64 select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS + select ARCH_USES_THP_SWAP_CLUSTER if X86_64 config INSTRUCTION_DECODER def_bool y diff --git a/mm/Kconfig b/mm/Kconfig index be0ee11..2da8128 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -503,6 +503,19 @@ config FRONTSWAP If unsure, say Y to enable frontswap. +config ARCH_USES_THP_SWAP_CLUSTER + bool + default n + +config THP_SWAP_CLUSTER + bool + depends on SWAP && TRANSPARENT_HUGEPAGE && ARCH_USES_THP_SWAP_CLUSTER + default y + help + Use one swap cluster to hold the contents of the THP + (Transparent Huge Page) swapped out. The size of the swap + cluster will be same as that of THP. + config CMA bool "Contiguous Memory Allocator" depends on HAVE_MEMBLOCK && MMU diff --git a/mm/swapfile.c b/mm/swapfile.c index 8f1b97d..4b78402 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -196,7 +196,11 @@ static void discard_swap_cluster(struct swap_info_struct *si, } } +#ifdef CONFIG_THP_SWAP_CLUSTER +#define SWAPFILE_CLUSTER (HPAGE_SIZE / PAGE_SIZE) +#else #define SWAPFILE_CLUSTER 256 +#endif #define LATENCY_LIMIT 256 static inline void cluster_set_flag(struct swap_cluster_info *info, -- 2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Anshuman Khandual <khandual@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-09-08 10:30 +0200 |
| Subject | Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <sf2SC-3oQ-5@gated-at.bofh.it> |
| In reply to | #1478495 |
On 09/07/2016 10:16 PM, Huang, Ying wrote: > From: Huang Ying <ying.huang@intel.com> > > In this patch, the size of the swap cluster is changed to that of the > THP (Transparent Huge Page) on x86_64 architecture (512). This is for > the THP swap support on x86_64. Where one swap cluster will be used to > hold the contents of each THP swapped out. And some information of the > swapped out THP (such as compound map count) will be recorded in the > swap_cluster_info data structure. > > For other architectures which want THP swap support, THP_SWAP_CLUSTER > need to be selected in the Kconfig file for the architecture. > > In effect, this will enlarge swap cluster size by 2 times on x86_64. > Which may make it harder to find a free cluster when the swap space > becomes fragmented. So that, this may reduce the continuous swap space > allocation and sequential write in theory. The performance test in 0day > shows no regressions caused by this. This patch needs to be split into two separate ones (1) Add THP_SWAP_CLUSTER config option (2) Enable CONFIG_THP_SWAP_CLUSTER for X86_64 The first patch should explain the proposal and the second patch should have 86_64 arch specific details, regressions etc as already been explained in the commit message.
[toc] | [prev] | [next] | [standalone]
| From | Anshuman Khandual <khandual@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-09-08 11:20 +0200 |
| Subject | Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <sf3F0-3UY-29@gated-at.bofh.it> |
| In reply to | #1478495 |
On 09/07/2016 10:16 PM, Huang, Ying wrote: > From: Huang Ying <ying.huang@intel.com> > > In this patch, the size of the swap cluster is changed to that of the > THP (Transparent Huge Page) on x86_64 architecture (512). This is for > the THP swap support on x86_64. Where one swap cluster will be used to > hold the contents of each THP swapped out. And some information of the > swapped out THP (such as compound map count) will be recorded in the > swap_cluster_info data structure. > > For other architectures which want THP swap support, THP_SWAP_CLUSTER > need to be selected in the Kconfig file for the architecture. > > In effect, this will enlarge swap cluster size by 2 times on x86_64. > Which may make it harder to find a free cluster when the swap space > becomes fragmented. So that, this may reduce the continuous swap space > allocation and sequential write in theory. The performance test in 0day > shows no regressions caused by this. This patch needs to be split into two separate ones (1) Add THP_SWAP_CLUSTER config option (2) Enable CONFIG_THP_SWAP_CLUSTER for X86_64 The first patch should explain the proposal and the second patch should have 86_64 arch specific details, regressions etc as already been explained in the commit message.
[toc] | [prev] | [next] | [standalone]
| From | "Huang\, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-08 20:10 +0200 |
| Subject | Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <sfbVT-HP-7@gated-at.bofh.it> |
| In reply to | #1478955 |
Anshuman Khandual <khandual@linux.vnet.ibm.com> writes: > On 09/07/2016 10:16 PM, Huang, Ying wrote: >> From: Huang Ying <ying.huang@intel.com> >> >> In this patch, the size of the swap cluster is changed to that of the >> THP (Transparent Huge Page) on x86_64 architecture (512). This is for >> the THP swap support on x86_64. Where one swap cluster will be used to >> hold the contents of each THP swapped out. And some information of the >> swapped out THP (such as compound map count) will be recorded in the >> swap_cluster_info data structure. >> >> For other architectures which want THP swap support, THP_SWAP_CLUSTER >> need to be selected in the Kconfig file for the architecture. >> >> In effect, this will enlarge swap cluster size by 2 times on x86_64. >> Which may make it harder to find a free cluster when the swap space >> becomes fragmented. So that, this may reduce the continuous swap space >> allocation and sequential write in theory. The performance test in 0day >> shows no regressions caused by this. > > This patch needs to be split into two separate ones > > (1) Add THP_SWAP_CLUSTER config option > (2) Enable CONFIG_THP_SWAP_CLUSTER for X86_64 > > The first patch should explain the proposal and the second patch > should have 86_64 arch specific details, regressions etc as already > been explained in the commit message. The code change and possible issues is not x86_64 specific, but general for all architectures where the config option is enabled. If so, the second patch becomes 1 line kconfig change and no much to be said in patch description. Does it deserve a separate patch? Best Regards, Huang, Ying
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-09-08 13:10 +0200 |
| Subject | Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <sf5ns-53y-7@gated-at.bofh.it> |
| In reply to | #1478495 |
On Wed, Sep 07, 2016 at 09:46:00AM -0700, Huang, Ying wrote: > From: Huang Ying <ying.huang@intel.com> > > In this patch, the size of the swap cluster is changed to that of the > THP (Transparent Huge Page) on x86_64 architecture (512). This is for > the THP swap support on x86_64. Where one swap cluster will be used to > hold the contents of each THP swapped out. And some information of the > swapped out THP (such as compound map count) will be recorded in the > swap_cluster_info data structure. > > For other architectures which want THP swap support, THP_SWAP_CLUSTER > need to be selected in the Kconfig file for the architecture. > > In effect, this will enlarge swap cluster size by 2 times on x86_64. > Which may make it harder to find a free cluster when the swap space > becomes fragmented. So that, this may reduce the continuous swap space > allocation and sequential write in theory. The performance test in 0day > shows no regressions caused by this. > > 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> > Suggested-by: Andrew Morton <akpm@linux-foundation.org> > Signed-off-by: "Huang, Ying" <ying.huang@intel.com> > --- > arch/x86/Kconfig | 1 + > mm/Kconfig | 13 +++++++++++++ > mm/swapfile.c | 4 ++++ > 3 files changed, 18 insertions(+) > > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index 4c39728..421d862 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -164,6 +164,7 @@ config X86 > select HAVE_STACK_VALIDATION if X86_64 > select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS > select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS > + select ARCH_USES_THP_SWAP_CLUSTER if X86_64 > > config INSTRUCTION_DECODER > def_bool y > diff --git a/mm/Kconfig b/mm/Kconfig > index be0ee11..2da8128 100644 > --- a/mm/Kconfig > +++ b/mm/Kconfig > @@ -503,6 +503,19 @@ config FRONTSWAP > > If unsure, say Y to enable frontswap. > > +config ARCH_USES_THP_SWAP_CLUSTER > + bool > + default n > + > +config THP_SWAP_CLUSTER > + bool > + depends on SWAP && TRANSPARENT_HUGEPAGE && ARCH_USES_THP_SWAP_CLUSTER > + default y > + help > + Use one swap cluster to hold the contents of the THP > + (Transparent Huge Page) swapped out. The size of the swap > + cluster will be same as that of THP. > + Why do we need to ask user about it? I don't think most users qualified to make this decision. > config CMA > bool "Contiguous Memory Allocator" > depends on HAVE_MEMBLOCK && MMU > diff --git a/mm/swapfile.c b/mm/swapfile.c > index 8f1b97d..4b78402 100644 > --- a/mm/swapfile.c > +++ b/mm/swapfile.c > @@ -196,7 +196,11 @@ static void discard_swap_cluster(struct swap_info_struct *si, > } > } > > +#ifdef CONFIG_THP_SWAP_CLUSTER Just #if defined(CONFIG_ARCH_USES_THP_SWAP_CLUSTER) && defined(CONFIG_TRANSPARENT_HUGEPAGE) would be enough from my POV. > +#define SWAPFILE_CLUSTER (HPAGE_SIZE / PAGE_SIZE) > +#else > #define SWAPFILE_CLUSTER 256 > +#endif > #define LATENCY_LIMIT 256 > > static inline void cluster_set_flag(struct swap_cluster_info *info, > -- > 2.8.1 > -- Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | "Huang\, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-08 19:40 +0200 |
| Subject | Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <sfbsR-hA-1@gated-at.bofh.it> |
| In reply to | #1479094 |
"Kirill A. Shutemov" <kirill@shutemov.name> writes: > On Wed, Sep 07, 2016 at 09:46:00AM -0700, Huang, Ying wrote: >> From: Huang Ying <ying.huang@intel.com> >> >> In this patch, the size of the swap cluster is changed to that of the >> THP (Transparent Huge Page) on x86_64 architecture (512). This is for >> the THP swap support on x86_64. Where one swap cluster will be used to >> hold the contents of each THP swapped out. And some information of the >> swapped out THP (such as compound map count) will be recorded in the >> swap_cluster_info data structure. >> >> For other architectures which want THP swap support, THP_SWAP_CLUSTER >> need to be selected in the Kconfig file for the architecture. >> >> In effect, this will enlarge swap cluster size by 2 times on x86_64. >> Which may make it harder to find a free cluster when the swap space >> becomes fragmented. So that, this may reduce the continuous swap space >> allocation and sequential write in theory. The performance test in 0day >> shows no regressions caused by this. >> >> 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> >> Suggested-by: Andrew Morton <akpm@linux-foundation.org> >> Signed-off-by: "Huang, Ying" <ying.huang@intel.com> >> --- >> arch/x86/Kconfig | 1 + >> mm/Kconfig | 13 +++++++++++++ >> mm/swapfile.c | 4 ++++ >> 3 files changed, 18 insertions(+) >> >> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig >> index 4c39728..421d862 100644 >> --- a/arch/x86/Kconfig >> +++ b/arch/x86/Kconfig >> @@ -164,6 +164,7 @@ config X86 >> select HAVE_STACK_VALIDATION if X86_64 >> select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS >> select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS >> + select ARCH_USES_THP_SWAP_CLUSTER if X86_64 >> >> config INSTRUCTION_DECODER >> def_bool y >> diff --git a/mm/Kconfig b/mm/Kconfig >> index be0ee11..2da8128 100644 >> --- a/mm/Kconfig >> +++ b/mm/Kconfig >> @@ -503,6 +503,19 @@ config FRONTSWAP >> >> If unsure, say Y to enable frontswap. >> >> +config ARCH_USES_THP_SWAP_CLUSTER >> + bool >> + default n >> + >> +config THP_SWAP_CLUSTER >> + bool >> + depends on SWAP && TRANSPARENT_HUGEPAGE && ARCH_USES_THP_SWAP_CLUSTER >> + default y >> + help >> + Use one swap cluster to hold the contents of the THP >> + (Transparent Huge Page) swapped out. The size of the swap >> + cluster will be same as that of THP. >> + > > Why do we need to ask user about it? I don't think most users qualified to > make this decision. Users need not to choose this. If the dependencies is true, it will be turned on. I added the help here not for users, but for developers to know what it is for. >> config CMA >> bool "Contiguous Memory Allocator" >> depends on HAVE_MEMBLOCK && MMU >> diff --git a/mm/swapfile.c b/mm/swapfile.c >> index 8f1b97d..4b78402 100644 >> --- a/mm/swapfile.c >> +++ b/mm/swapfile.c >> @@ -196,7 +196,11 @@ static void discard_swap_cluster(struct swap_info_struct *si, >> } >> } >> >> +#ifdef CONFIG_THP_SWAP_CLUSTER > > Just > > #if defined(CONFIG_ARCH_USES_THP_SWAP_CLUSTER) && defined(CONFIG_TRANSPARENT_HUGEPAGE) > > would be enough from my POV. That works. I added a new configuration option just to save some typing and make it a little easier to read. If other people think it is not necessary to add a new configuration option for that too. I will use change it in this way. Best Regards, Huang, Ying >> +#define SWAPFILE_CLUSTER (HPAGE_SIZE / PAGE_SIZE) >> +#else >> #define SWAPFILE_CLUSTER 256 >> +#endif >> #define LATENCY_LIMIT 256 >> >> static inline void cluster_set_flag(struct swap_cluster_info *info, >> -- >> 2.8.1 >>
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-09-08 13:10 +0200 |
| Subject | Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <sf5ns-53y-29@gated-at.bofh.it> |
| In reply to | #1478495 |
On Wed, Sep 07, 2016 at 09:46:00AM -0700, Huang, Ying wrote: > From: Huang Ying <ying.huang@intel.com> > > In this patch, the size of the swap cluster is changed to that of the > THP (Transparent Huge Page) on x86_64 architecture (512). This is for > the THP swap support on x86_64. Where one swap cluster will be used to > hold the contents of each THP swapped out. And some information of the > swapped out THP (such as compound map count) will be recorded in the > swap_cluster_info data structure. > > For other architectures which want THP swap support, THP_SWAP_CLUSTER > need to be selected in the Kconfig file for the architecture. > > In effect, this will enlarge swap cluster size by 2 times on x86_64. > Which may make it harder to find a free cluster when the swap space > becomes fragmented. So that, this may reduce the continuous swap space > allocation and sequential write in theory. The performance test in 0day > shows no regressions caused by this. > > 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> > Suggested-by: Andrew Morton <akpm@linux-foundation.org> > Signed-off-by: "Huang, Ying" <ying.huang@intel.com> > --- > arch/x86/Kconfig | 1 + > mm/Kconfig | 13 +++++++++++++ > mm/swapfile.c | 4 ++++ > 3 files changed, 18 insertions(+) > > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index 4c39728..421d862 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -164,6 +164,7 @@ config X86 > select HAVE_STACK_VALIDATION if X86_64 > select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS > select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS > + select ARCH_USES_THP_SWAP_CLUSTER if X86_64 > > config INSTRUCTION_DECODER > def_bool y > diff --git a/mm/Kconfig b/mm/Kconfig > index be0ee11..2da8128 100644 > --- a/mm/Kconfig > +++ b/mm/Kconfig > @@ -503,6 +503,19 @@ config FRONTSWAP > > If unsure, say Y to enable frontswap. > > +config ARCH_USES_THP_SWAP_CLUSTER > + bool > + default n > + > +config THP_SWAP_CLUSTER > + bool > + depends on SWAP && TRANSPARENT_HUGEPAGE && ARCH_USES_THP_SWAP_CLUSTER > + default y > + help > + Use one swap cluster to hold the contents of the THP > + (Transparent Huge Page) swapped out. The size of the swap > + cluster will be same as that of THP. > + > config CMA > bool "Contiguous Memory Allocator" > depends on HAVE_MEMBLOCK && MMU > diff --git a/mm/swapfile.c b/mm/swapfile.c > index 8f1b97d..4b78402 100644 > --- a/mm/swapfile.c > +++ b/mm/swapfile.c > @@ -196,7 +196,11 @@ static void discard_swap_cluster(struct swap_info_struct *si, > } > } > > +#ifdef CONFIG_THP_SWAP_CLUSTER > +#define SWAPFILE_CLUSTER (HPAGE_SIZE / PAGE_SIZE) #define SWAPFILE_CLUSTER HPAGE_PMD_NR Note, HPAGE_SIZE is not nessesary HPAGE_PMD_SIZE. I can imagine an arch with multiple huge page sizes where HPAGE_SIZE differs from what is used for THP. > +#else > #define SWAPFILE_CLUSTER 256 > +#endif > #define LATENCY_LIMIT 256 > > static inline void cluster_set_flag(struct swap_cluster_info *info, > -- > 2.8.1 > -- Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | "Huang\, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-08 19:30 +0200 |
| Subject | Re: [PATCH -v3 01/10] mm, swap: Make swap cluster size same of THP size on x86_64 |
| Message-ID | <sfbjc-eq-35@gated-at.bofh.it> |
| In reply to | #1479104 |
"Kirill A. Shutemov" <kirill@shutemov.name> writes: > On Wed, Sep 07, 2016 at 09:46:00AM -0700, Huang, Ying wrote: >> From: Huang Ying <ying.huang@intel.com> >> >> In this patch, the size of the swap cluster is changed to that of the >> THP (Transparent Huge Page) on x86_64 architecture (512). This is for >> the THP swap support on x86_64. Where one swap cluster will be used to >> hold the contents of each THP swapped out. And some information of the >> swapped out THP (such as compound map count) will be recorded in the >> swap_cluster_info data structure. >> >> For other architectures which want THP swap support, THP_SWAP_CLUSTER >> need to be selected in the Kconfig file for the architecture. >> >> In effect, this will enlarge swap cluster size by 2 times on x86_64. >> Which may make it harder to find a free cluster when the swap space >> becomes fragmented. So that, this may reduce the continuous swap space >> allocation and sequential write in theory. The performance test in 0day >> shows no regressions caused by this. >> >> 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> >> Suggested-by: Andrew Morton <akpm@linux-foundation.org> >> Signed-off-by: "Huang, Ying" <ying.huang@intel.com> >> --- >> arch/x86/Kconfig | 1 + >> mm/Kconfig | 13 +++++++++++++ >> mm/swapfile.c | 4 ++++ >> 3 files changed, 18 insertions(+) >> >> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig >> index 4c39728..421d862 100644 >> --- a/arch/x86/Kconfig >> +++ b/arch/x86/Kconfig >> @@ -164,6 +164,7 @@ config X86 >> select HAVE_STACK_VALIDATION if X86_64 >> select ARCH_USES_HIGH_VMA_FLAGS if X86_INTEL_MEMORY_PROTECTION_KEYS >> select ARCH_HAS_PKEYS if X86_INTEL_MEMORY_PROTECTION_KEYS >> + select ARCH_USES_THP_SWAP_CLUSTER if X86_64 >> >> config INSTRUCTION_DECODER >> def_bool y >> diff --git a/mm/Kconfig b/mm/Kconfig >> index be0ee11..2da8128 100644 >> --- a/mm/Kconfig >> +++ b/mm/Kconfig >> @@ -503,6 +503,19 @@ config FRONTSWAP >> >> If unsure, say Y to enable frontswap. >> >> +config ARCH_USES_THP_SWAP_CLUSTER >> + bool >> + default n >> + >> +config THP_SWAP_CLUSTER >> + bool >> + depends on SWAP && TRANSPARENT_HUGEPAGE && ARCH_USES_THP_SWAP_CLUSTER >> + default y >> + help >> + Use one swap cluster to hold the contents of the THP >> + (Transparent Huge Page) swapped out. The size of the swap >> + cluster will be same as that of THP. >> + >> config CMA >> bool "Contiguous Memory Allocator" >> depends on HAVE_MEMBLOCK && MMU >> diff --git a/mm/swapfile.c b/mm/swapfile.c >> index 8f1b97d..4b78402 100644 >> --- a/mm/swapfile.c >> +++ b/mm/swapfile.c >> @@ -196,7 +196,11 @@ static void discard_swap_cluster(struct swap_info_struct *si, >> } >> } >> >> +#ifdef CONFIG_THP_SWAP_CLUSTER >> +#define SWAPFILE_CLUSTER (HPAGE_SIZE / PAGE_SIZE) > > #define SWAPFILE_CLUSTER HPAGE_PMD_NR Yes. Will change it. > Note, HPAGE_SIZE is not nessesary HPAGE_PMD_SIZE. I can imagine an arch > with multiple huge page sizes where HPAGE_SIZE differs from what is used > for THP. Thanks for pointing out that! Best Regards, Huang, Ying
[toc] | [prev] | [next] | [standalone]
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 05/10] mm, THP, swap: Add get_huge_swap_page() |
| Message-ID | <seOcW-2cL-35@gated-at.bofh.it> |
| In reply to | #1478488 |
From: Huang Ying <ying.huang@intel.com>
A variation of get_swap_page(), get_huge_swap_page(), is added to
allocate a swap cluster (512 swap slots) based on the swap cluster
allocation function. A fair simple algorithm is used, that is, only the
first swap device in priority list will be tried to allocate the swap
cluster. The function will fail if the trying is not successful, and
the caller will fallback to allocate a single swap slot instead. This
works good enough for normal cases.
This will be used for the THP (Transparent Huge Page) swap support.
Where get_huge_swap_page() will be used to allocate one swap cluster for
each THP swapped out.
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.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: "Huang, Ying" <ying.huang@intel.com>
---
include/linux/swap.h | 24 +++++++++++++++++++++++-
mm/swapfile.c | 18 ++++++++++++------
2 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 75aad24..bc0a84d 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -399,7 +399,7 @@ static inline long get_nr_swap_pages(void)
}
extern void si_swapinfo(struct sysinfo *);
-extern swp_entry_t get_swap_page(void);
+extern swp_entry_t __get_swap_page(bool huge);
extern swp_entry_t get_swap_page_of_type(int);
extern int add_swap_count_continuation(swp_entry_t, gfp_t);
extern void swap_shmem_alloc(swp_entry_t);
@@ -419,6 +419,23 @@ extern bool reuse_swap_page(struct page *, int *);
extern int try_to_free_swap(struct page *);
struct backing_dev_info;
+static inline swp_entry_t get_swap_page(void)
+{
+ return __get_swap_page(false);
+}
+
+#ifdef CONFIG_THP_SWAP_CLUSTER
+static inline swp_entry_t get_huge_swap_page(void)
+{
+ return __get_swap_page(true);
+}
+#else
+static inline swp_entry_t get_huge_swap_page(void)
+{
+ return (swp_entry_t) {0};
+}
+#endif
+
#else /* CONFIG_SWAP */
#define swap_address_space(entry) (NULL)
@@ -525,6 +542,11 @@ static inline swp_entry_t get_swap_page(void)
return entry;
}
+static inline swp_entry_t get_huge_swap_page(void)
+{
+ return (swp_entry_t) {0};
+}
+
#endif /* CONFIG_SWAP */
#ifdef CONFIG_MEMCG
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 0132e8c..3d2bd1f 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -760,14 +760,15 @@ static inline unsigned long swap_alloc_huge_cluster(struct swap_info_struct *si)
}
#endif
-swp_entry_t get_swap_page(void)
+swp_entry_t __get_swap_page(bool huge)
{
struct swap_info_struct *si, *next;
pgoff_t offset;
+ int nr_pages = huge_cluster_nr_entries(huge);
- if (atomic_long_read(&nr_swap_pages) <= 0)
+ if (atomic_long_read(&nr_swap_pages) < nr_pages)
goto noswap;
- atomic_long_dec(&nr_swap_pages);
+ atomic_long_sub(nr_pages, &nr_swap_pages);
spin_lock(&swap_avail_lock);
@@ -795,10 +796,15 @@ start_over:
}
/* This is called for allocating swap entry for cache */
- offset = scan_swap_map(si, SWAP_HAS_CACHE);
+ if (likely(nr_pages == 1))
+ offset = scan_swap_map(si, SWAP_HAS_CACHE);
+ else
+ offset = swap_alloc_huge_cluster(si);
spin_unlock(&si->lock);
if (offset)
return swp_entry(si->type, offset);
+ else if (unlikely(nr_pages != 1))
+ goto fail_alloc;
pr_debug("scan_swap_map of si %d failed to find offset\n",
si->type);
spin_lock(&swap_avail_lock);
@@ -818,8 +824,8 @@ nextsi:
}
spin_unlock(&swap_avail_lock);
-
- atomic_long_inc(&nr_swap_pages);
+fail_alloc:
+ atomic_long_add(nr_pages, &nr_swap_pages);
noswap:
return (swp_entry_t) {0};
}
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-09-08 13:20 +0200 |
| Subject | Re: [PATCH -v3 05/10] mm, THP, swap: Add get_huge_swap_page() |
| Message-ID | <sf5x8-56T-7@gated-at.bofh.it> |
| In reply to | #1478496 |
On Wed, Sep 07, 2016 at 09:46:04AM -0700, Huang, Ying wrote:
> From: Huang Ying <ying.huang@intel.com>
>
> A variation of get_swap_page(), get_huge_swap_page(), is added to
> allocate a swap cluster (512 swap slots) based on the swap cluster
> allocation function. A fair simple algorithm is used, that is, only the
> first swap device in priority list will be tried to allocate the swap
> cluster. The function will fail if the trying is not successful, and
> the caller will fallback to allocate a single swap slot instead. This
> works good enough for normal cases.
For normal cases, yes. But the limitation is not obvious for users and
performance difference after small change in configuration could be
puzzling.
At least this must be documented somewhere.
>
> This will be used for the THP (Transparent Huge Page) swap support.
> Where get_huge_swap_page() will be used to allocate one swap cluster for
> each THP swapped out.
>
> Cc: Andrea Arcangeli <aarcange@redhat.com>
> Cc: Kirill A. Shutemov <kirill.shutemov@linux.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: "Huang, Ying" <ying.huang@intel.com>
> ---
> include/linux/swap.h | 24 +++++++++++++++++++++++-
> mm/swapfile.c | 18 ++++++++++++------
> 2 files changed, 35 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/swap.h b/include/linux/swap.h
> index 75aad24..bc0a84d 100644
> --- a/include/linux/swap.h
> +++ b/include/linux/swap.h
> @@ -399,7 +399,7 @@ static inline long get_nr_swap_pages(void)
> }
>
> extern void si_swapinfo(struct sysinfo *);
> -extern swp_entry_t get_swap_page(void);
> +extern swp_entry_t __get_swap_page(bool huge);
> extern swp_entry_t get_swap_page_of_type(int);
> extern int add_swap_count_continuation(swp_entry_t, gfp_t);
> extern void swap_shmem_alloc(swp_entry_t);
> @@ -419,6 +419,23 @@ extern bool reuse_swap_page(struct page *, int *);
> extern int try_to_free_swap(struct page *);
> struct backing_dev_info;
>
> +static inline swp_entry_t get_swap_page(void)
> +{
> + return __get_swap_page(false);
> +}
> +
> +#ifdef CONFIG_THP_SWAP_CLUSTER
> +static inline swp_entry_t get_huge_swap_page(void)
> +{
> + return __get_swap_page(true);
> +}
> +#else
> +static inline swp_entry_t get_huge_swap_page(void)
> +{
> + return (swp_entry_t) {0};
> +}
> +#endif
> +
> #else /* CONFIG_SWAP */
>
> #define swap_address_space(entry) (NULL)
> @@ -525,6 +542,11 @@ static inline swp_entry_t get_swap_page(void)
> return entry;
> }
>
> +static inline swp_entry_t get_huge_swap_page(void)
> +{
> + return (swp_entry_t) {0};
> +}
> +
> #endif /* CONFIG_SWAP */
>
> #ifdef CONFIG_MEMCG
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 0132e8c..3d2bd1f 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -760,14 +760,15 @@ static inline unsigned long swap_alloc_huge_cluster(struct swap_info_struct *si)
> }
> #endif
>
> -swp_entry_t get_swap_page(void)
> +swp_entry_t __get_swap_page(bool huge)
> {
> struct swap_info_struct *si, *next;
> pgoff_t offset;
> + int nr_pages = huge_cluster_nr_entries(huge);
>
> - if (atomic_long_read(&nr_swap_pages) <= 0)
> + if (atomic_long_read(&nr_swap_pages) < nr_pages)
> goto noswap;
> - atomic_long_dec(&nr_swap_pages);
> + atomic_long_sub(nr_pages, &nr_swap_pages);
>
> spin_lock(&swap_avail_lock);
>
> @@ -795,10 +796,15 @@ start_over:
> }
>
> /* This is called for allocating swap entry for cache */
> - offset = scan_swap_map(si, SWAP_HAS_CACHE);
> + if (likely(nr_pages == 1))
> + offset = scan_swap_map(si, SWAP_HAS_CACHE);
> + else
> + offset = swap_alloc_huge_cluster(si);
> spin_unlock(&si->lock);
> if (offset)
> return swp_entry(si->type, offset);
> + else if (unlikely(nr_pages != 1))
> + goto fail_alloc;
> pr_debug("scan_swap_map of si %d failed to find offset\n",
> si->type);
> spin_lock(&swap_avail_lock);
> @@ -818,8 +824,8 @@ nextsi:
> }
>
> spin_unlock(&swap_avail_lock);
> -
> - atomic_long_inc(&nr_swap_pages);
> +fail_alloc:
> + atomic_long_add(nr_pages, &nr_swap_pages);
> noswap:
> return (swp_entry_t) {0};
> }
> --
> 2.8.1
>
--
Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | "Huang\, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-08 19:30 +0200 |
| Subject | Re: [PATCH -v3 05/10] mm, THP, swap: Add get_huge_swap_page() |
| Message-ID | <sfbjb-eq-21@gated-at.bofh.it> |
| In reply to | #1479108 |
"Kirill A. Shutemov" <kirill@shutemov.name> writes: > On Wed, Sep 07, 2016 at 09:46:04AM -0700, Huang, Ying wrote: >> From: Huang Ying <ying.huang@intel.com> >> >> A variation of get_swap_page(), get_huge_swap_page(), is added to >> allocate a swap cluster (512 swap slots) based on the swap cluster >> allocation function. A fair simple algorithm is used, that is, only the >> first swap device in priority list will be tried to allocate the swap >> cluster. The function will fail if the trying is not successful, and >> the caller will fallback to allocate a single swap slot instead. This >> works good enough for normal cases. > > For normal cases, yes. But the limitation is not obvious for users and > performance difference after small change in configuration could be > puzzling. If the difference of the number of the free swap clusters among multiple swap devices is significant, it is possible that some THP are split earlier than necessary because we fail to allocate the swap clusters for them. For example, this could be caused by big size difference among multiple swap devices. > At least this must be documented somewhere. I can add the above description in the patch description. Any other places do you suggest? Best Regards, Huang, Ying [snip]
[toc] | [prev] | [next] | [standalone]
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 09/10] mm, THP, swap: Support to split THP in swap cache |
| Message-ID | <seOcW-2cL-39@gated-at.bofh.it> |
| In reply to | #1478488 |
From: Huang Ying <ying.huang@intel.com>
This patch enhanced the split_huge_page_to_list() to work properly for
the THP (Transparent Huge Page) in the swap cache during swapping out.
This is used for delaying splitting the THP during swapping out. Where
for a THP to be swapped out, we will allocate a swap cluster, add the
THP into the swap cache, then split the THP. The page lock will be held
during this process. So in the code path other than swapping out, if
the THP need to be split, the PageSwapCache(THP) will be always false.
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Ebru Akagunduz <ebru.akagunduz@gmail.com>
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
---
mm/huge_memory.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 3be5abe..3bb4976 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1834,7 +1834,7 @@ static void __split_huge_page_tail(struct page *head, int tail,
* atomic_set() here would be safe on all archs (and not only on x86),
* it's safer to use atomic_inc()/atomic_add().
*/
- if (PageAnon(head)) {
+ if (PageAnon(head) && !PageSwapCache(head)) {
page_ref_inc(page_tail);
} else {
/* Additional pin to radix tree */
@@ -1845,6 +1845,7 @@ static void __split_huge_page_tail(struct page *head, int tail,
page_tail->flags |= (head->flags &
((1L << PG_referenced) |
(1L << PG_swapbacked) |
+ (1L << PG_swapcache) |
(1L << PG_mlocked) |
(1L << PG_uptodate) |
(1L << PG_active) |
@@ -1907,7 +1908,11 @@ static void __split_huge_page(struct page *page, struct list_head *list,
ClearPageCompound(head);
/* See comment in __split_huge_page_tail() */
if (PageAnon(head)) {
- page_ref_inc(head);
+ /* Additional pin to radix tree of swap cache */
+ if (PageSwapCache(head))
+ page_ref_add(head, 2);
+ else
+ page_ref_inc(head);
} else {
/* Additional pin to radix tree */
page_ref_add(head, 2);
@@ -2019,10 +2024,12 @@ int page_trans_huge_mapcount(struct page *page, int *total_mapcount)
/* Racy check whether the huge page can be split */
bool can_split_huge_page(struct page *page)
{
- int extra_pins = 0;
+ int extra_pins;
/* Additional pins from radix tree */
- if (!PageAnon(page))
+ if (PageAnon(page))
+ extra_pins = PageSwapCache(page) ? HPAGE_PMD_NR : 0;
+ else
extra_pins = HPAGE_PMD_NR;
return total_mapcount(page) == page_count(page) - extra_pins - 1;
}
@@ -2075,7 +2082,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
ret = -EBUSY;
goto out;
}
- extra_pins = 0;
+ extra_pins = PageSwapCache(head) ? HPAGE_PMD_NR : 0;
mapping = NULL;
anon_vma_lock_write(anon_vma);
} else {
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 06/10] mm, THP, swap: Support to clear SWAP_HAS_CACHE for huge page |
| Message-ID | <seOcW-2cL-37@gated-at.bofh.it> |
| In reply to | #1478488 |
From: Huang Ying <ying.huang@intel.com>
__swapcache_free() is added to support to clear the SWAP_HAS_CACHE flag
for the huge page. This will free the specified swap cluster now.
Because now this function will be called only in the error path to free
the swap cluster just allocated. So the corresponding swap_map[i] ==
SWAP_HAS_CACHE, that is, the swap count is 0. This makes the
implementation simpler than that of the ordinary swap entry.
This will be used for delaying splitting THP (Transparent Huge Page)
during swapping out. Where for one THP to swap out, we will allocate a
swap cluster, add the THP into the swap cache, then split the THP. If
anything fails after allocating the swap cluster and before splitting
the THP successfully, the swapcache_free_trans_huge() will be used to
free the swap space allocated.
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.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: "Huang, Ying" <ying.huang@intel.com>
---
include/linux/swap.h | 9 +++++++--
mm/swapfile.c | 32 ++++++++++++++++++++++++++++++--
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index bc0a84d..7be7599 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -406,7 +406,7 @@ 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(swp_entry_t, bool);
extern int free_swap_and_cache(swp_entry_t);
extern int swap_type_of(dev_t, sector_t, struct block_device **);
extern unsigned int count_swap_pages(int, int);
@@ -478,7 +478,7 @@ static inline void swap_free(swp_entry_t swp)
{
}
-static inline void swapcache_free(swp_entry_t swp)
+static inline void __swapcache_free(swp_entry_t swp, bool huge)
{
}
@@ -549,6 +549,11 @@ static inline swp_entry_t get_huge_swap_page(void)
#endif /* CONFIG_SWAP */
+static inline void swapcache_free(swp_entry_t entry)
+{
+ __swapcache_free(entry, false);
+}
+
#ifdef CONFIG_MEMCG
static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
{
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 3d2bd1f..26b75fa 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -732,6 +732,26 @@ static void swap_free_huge_cluster(struct swap_info_struct *si,
__swap_entry_free(si, offset, true);
}
+/*
+ * Caller should hold si->lock.
+ */
+static void swapcache_free_trans_huge(struct swap_info_struct *si,
+ swp_entry_t entry)
+{
+ unsigned long offset = swp_offset(entry);
+ unsigned long idx = offset / SWAPFILE_CLUSTER;
+ unsigned char *map;
+ unsigned int i;
+
+ map = si->swap_map + offset;
+ for (i = 0; i < SWAPFILE_CLUSTER; i++) {
+ VM_BUG_ON(map[i] != SWAP_HAS_CACHE);
+ map[i] &= ~SWAP_HAS_CACHE;
+ }
+ mem_cgroup_uncharge_swap(entry, SWAPFILE_CLUSTER);
+ swap_free_huge_cluster(si, idx);
+}
+
static unsigned long swap_alloc_huge_cluster(struct swap_info_struct *si)
{
unsigned long idx;
@@ -758,6 +778,11 @@ static inline unsigned long swap_alloc_huge_cluster(struct swap_info_struct *si)
{
return 0;
}
+
+static inline void swapcache_free_trans_huge(struct swap_info_struct *si,
+ swp_entry_t entry)
+{
+}
#endif
swp_entry_t __get_swap_page(bool huge)
@@ -949,13 +974,16 @@ void swap_free(swp_entry_t entry)
/*
* Called after dropping swapcache to decrease refcnt to swap entries.
*/
-void swapcache_free(swp_entry_t entry)
+void __swapcache_free(swp_entry_t entry, bool huge)
{
struct swap_info_struct *p;
p = swap_info_get(entry);
if (p) {
- swap_entry_free(p, entry, SWAP_HAS_CACHE);
+ if (unlikely(huge))
+ swapcache_free_trans_huge(p, entry);
+ else
+ swap_entry_free(p, entry, SWAP_HAS_CACHE);
spin_unlock(&p->lock);
}
}
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | "Huang, Ying" <ying.huang@intel.com> |
|---|---|
| Date | 2016-09-07 18:50 +0200 |
| Subject | [PATCH -v3 03/10] mm, memcg: Support to charge/uncharge multiple swap entries |
| Message-ID | <seOcW-2cL-41@gated-at.bofh.it> |
| In reply to | #1478488 |
From: Huang Ying <ying.huang@intel.com>
This patch make it possible to charge or uncharge a set of continuous
swap entries in the swap cgroup. The number of swap entries is
specified via an added parameter.
This will be used for the THP (Transparent Huge Page) swap support.
Where a swap cluster backing a THP may be allocated and freed as a
whole. So a set of continuous swap entries (512 on x86_64) backing one
THP need to be charged or uncharged together. This will batch the
cgroup operations for the THP swap too.
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Vladimir Davydov <vdavydov@virtuozzo.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: cgroups@vger.kernel.org
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
---
include/linux/swap.h | 12 ++++++----
include/linux/swap_cgroup.h | 6 +++--
mm/memcontrol.c | 55 +++++++++++++++++++++++++--------------------
mm/shmem.c | 2 +-
mm/swap_cgroup.c | 17 ++++++++++----
mm/swap_state.c | 2 +-
mm/swapfile.c | 2 +-
7 files changed, 59 insertions(+), 37 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index ed41bec..75aad24 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -550,8 +550,10 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup *mem)
#ifdef CONFIG_MEMCG_SWAP
extern void mem_cgroup_swapout(struct page *page, swp_entry_t entry);
-extern int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry);
-extern void mem_cgroup_uncharge_swap(swp_entry_t entry);
+extern int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry,
+ unsigned int nr_entries);
+extern void mem_cgroup_uncharge_swap(swp_entry_t entry,
+ unsigned int nr_entries);
extern long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg);
extern bool mem_cgroup_swap_full(struct page *page);
#else
@@ -560,12 +562,14 @@ static inline void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
}
static inline int mem_cgroup_try_charge_swap(struct page *page,
- swp_entry_t entry)
+ swp_entry_t entry,
+ unsigned int nr_entries)
{
return 0;
}
-static inline void mem_cgroup_uncharge_swap(swp_entry_t entry)
+static inline void mem_cgroup_uncharge_swap(swp_entry_t entry,
+ unsigned int nr_entries)
{
}
diff --git a/include/linux/swap_cgroup.h b/include/linux/swap_cgroup.h
index 145306b..b2b8ec7 100644
--- a/include/linux/swap_cgroup.h
+++ b/include/linux/swap_cgroup.h
@@ -7,7 +7,8 @@
extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
unsigned short old, unsigned short new);
-extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
+extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id,
+ unsigned int nr_ents);
extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
extern int swap_cgroup_swapon(int type, unsigned long max_pages);
extern void swap_cgroup_swapoff(int type);
@@ -15,7 +16,8 @@ extern void swap_cgroup_swapoff(int type);
#else
static inline
-unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id,
+ unsigned int nr_ents)
{
return 0;
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index bdb796f..9662fcf 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2370,10 +2370,9 @@ void mem_cgroup_split_huge_fixup(struct page *head)
#ifdef CONFIG_MEMCG_SWAP
static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
- bool charge)
+ int nr_entries)
{
- int val = (charge) ? 1 : -1;
- this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAP], val);
+ this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAP], nr_entries);
}
/**
@@ -2399,8 +2398,8 @@ static int mem_cgroup_move_swap_account(swp_entry_t entry,
new_id = mem_cgroup_id(to);
if (swap_cgroup_cmpxchg(entry, old_id, new_id) == old_id) {
- mem_cgroup_swap_statistics(from, false);
- mem_cgroup_swap_statistics(to, true);
+ mem_cgroup_swap_statistics(from, -1);
+ mem_cgroup_swap_statistics(to, 1);
return 0;
}
return -EINVAL;
@@ -5417,7 +5416,7 @@ void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
* let's not wait for it. The page already received a
* memory+swap charge, drop the swap entry duplicate.
*/
- mem_cgroup_uncharge_swap(entry);
+ mem_cgroup_uncharge_swap(entry, nr_pages);
}
}
@@ -5825,9 +5824,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
* ancestor for the swap instead and transfer the memory+swap charge.
*/
swap_memcg = mem_cgroup_id_get_online(memcg);
- oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg));
+ oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg), 1);
VM_BUG_ON_PAGE(oldid, page);
- mem_cgroup_swap_statistics(swap_memcg, true);
+ mem_cgroup_swap_statistics(swap_memcg, 1);
page->mem_cgroup = NULL;
@@ -5854,16 +5853,19 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
css_put(&memcg->css);
}
-/*
- * mem_cgroup_try_charge_swap - try charging a swap entry
+/**
+ * mem_cgroup_try_charge_swap - try charging a set of swap entries
* @page: page being added to swap
- * @entry: swap entry to charge
+ * @entry: the first swap entry to charge
+ * @nr_entries: the number of swap entries to charge
*
- * Try to charge @entry to the memcg that @page belongs to.
+ * Try to charge @nr_entries swap entries starting from @entry to the
+ * memcg that @page belongs to.
*
* Returns 0 on success, -ENOMEM on failure.
*/
-int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
+int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry,
+ unsigned int nr_entries)
{
struct mem_cgroup *memcg;
struct page_counter *counter;
@@ -5881,25 +5883,29 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
memcg = mem_cgroup_id_get_online(memcg);
if (!mem_cgroup_is_root(memcg) &&
- !page_counter_try_charge(&memcg->swap, 1, &counter)) {
+ !page_counter_try_charge(&memcg->swap, nr_entries, &counter)) {
mem_cgroup_id_put(memcg);
return -ENOMEM;
}
- oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
+ if (nr_entries > 1)
+ mem_cgroup_id_get_many(memcg, nr_entries - 1);
+ oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg), nr_entries);
VM_BUG_ON_PAGE(oldid, page);
- mem_cgroup_swap_statistics(memcg, true);
+ mem_cgroup_swap_statistics(memcg, nr_entries);
return 0;
}
/**
- * mem_cgroup_uncharge_swap - uncharge a swap entry
- * @entry: swap entry to uncharge
+ * mem_cgroup_uncharge_swap - uncharge a set of swap entries
+ * @entry: the first swap entry to uncharge
+ * @nr_entries: the number of swap entries to uncharge
*
- * Drop the swap charge associated with @entry.
+ * Drop the swap charge associated with @nr_entries swap entries
+ * starting from @entry.
*/
-void mem_cgroup_uncharge_swap(swp_entry_t entry)
+void mem_cgroup_uncharge_swap(swp_entry_t entry, unsigned int nr_entries)
{
struct mem_cgroup *memcg;
unsigned short id;
@@ -5907,17 +5913,18 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry)
if (!do_swap_account)
return;
- id = swap_cgroup_record(entry, 0);
+ id = swap_cgroup_record(entry, 0, nr_entries);
rcu_read_lock();
memcg = mem_cgroup_from_id(id);
if (memcg) {
if (!mem_cgroup_is_root(memcg)) {
if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
- page_counter_uncharge(&memcg->swap, 1);
+ page_counter_uncharge(&memcg->swap, nr_entries);
else
- page_counter_uncharge(&memcg->memsw, 1);
+ page_counter_uncharge(&memcg->memsw,
+ nr_entries);
}
- mem_cgroup_swap_statistics(memcg, false);
+ mem_cgroup_swap_statistics(memcg, -nr_entries);
mem_cgroup_id_put(memcg);
}
rcu_read_unlock();
diff --git a/mm/shmem.c b/mm/shmem.c
index ac35ebd..baeb2f9 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1248,7 +1248,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
if (!swap.val)
goto redirty;
- if (mem_cgroup_try_charge_swap(page, swap))
+ if (mem_cgroup_try_charge_swap(page, swap, 1))
goto free_swap;
/*
diff --git a/mm/swap_cgroup.c b/mm/swap_cgroup.c
index 4ae3e7b..4d3484f 100644
--- a/mm/swap_cgroup.c
+++ b/mm/swap_cgroup.c
@@ -139,14 +139,16 @@ unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
}
/**
- * swap_cgroup_record - record mem_cgroup for this swp_entry.
- * @ent: swap entry to be recorded into
+ * swap_cgroup_record - record mem_cgroup for a set of swap entries
+ * @ent: the first swap entry to be recorded into
* @id: mem_cgroup to be recorded
+ * @nr_ents: number of swap entries to be recorded
*
* Returns old value at success, 0 at failure.
* (Of course, old value can be 0.)
*/
-unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id,
+ unsigned int nr_ents)
{
struct swap_cgroup_iter iter;
unsigned short old;
@@ -154,7 +156,14 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
swap_cgroup_iter_init(&iter, ent);
old = iter.sc->id;
- iter.sc->id = id;
+ for (;;) {
+ VM_BUG_ON(iter.sc->id != old);
+ iter.sc->id = id;
+ nr_ents--;
+ if (!nr_ents)
+ break;
+ swap_cgroup_iter_advance(&iter);
+ }
swap_cgroup_iter_exit(&iter);
return old;
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 8679c99..c335251 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -172,7 +172,7 @@ int add_to_swap(struct page *page, struct list_head *list)
if (!entry.val)
return 0;
- if (mem_cgroup_try_charge_swap(page, entry)) {
+ if (mem_cgroup_try_charge_swap(page, entry, 1)) {
swapcache_free(entry);
return 0;
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 4b78402..17f25e2 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -806,7 +806,7 @@ static unsigned char swap_entry_free(struct swap_info_struct *p,
/* free if no reference */
if (!usage) {
- mem_cgroup_uncharge_swap(entry);
+ mem_cgroup_uncharge_swap(entry, 1);
dec_cluster_info_page(p, p->cluster_info, offset);
if (offset < p->lowest_bit)
p->lowest_bit = offset;
--
2.8.1
[toc] | [prev] | [next] | [standalone]
| From | Anshuman Khandual <khandual@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-09-08 10:30 +0200 |
| Subject | Re: [PATCH -v3 03/10] mm, memcg: Support to charge/uncharge multiple swap entries |
| Message-ID | <sf2SC-3oQ-13@gated-at.bofh.it> |
| In reply to | #1478499 |
On 09/07/2016 10:16 PM, Huang, Ying wrote: > From: Huang Ying <ying.huang@intel.com> > > This patch make it possible to charge or uncharge a set of continuous > swap entries in the swap cgroup. The number of swap entries is > specified via an added parameter. > > This will be used for the THP (Transparent Huge Page) swap support. > Where a swap cluster backing a THP may be allocated and freed as a > whole. So a set of continuous swap entries (512 on x86_64) backing one Please use HPAGE_SIZE / PAGE_SIZE instead of hard coded number like 512.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web