Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1636499 > unrolled thread
| Started by | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| First post | 2017-05-05 19:10 +0200 |
| Last post | 2017-05-16 10:40 +0200 |
| Articles | 20 on this page of 32 — 7 participants |
Back to article view | Back to linux.kernel
[v3 0/9] parallelized "struct page" zeroing Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-05-05 19:10 +0200
[v3 8/9] powerpc: teach platforms not to zero struct pages memory Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-05-05 19:10 +0200
[v3 9/9] s390: teach platforms not to zero struct pages memory Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-05-05 19:10 +0200
Re: [v3 9/9] s390: teach platforms not to zero struct pages memory Heiko Carstens <heiko.carstens@de.ibm.com> - 2017-05-08 13:40 +0200
Re: [v3 9/9] s390: teach platforms not to zero struct pages memory Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-15 20:30 +0200
Re: [v3 9/9] s390: teach platforms not to zero struct pages memory Heiko Carstens <heiko.carstens@de.ibm.com> - 2017-05-16 01:20 +0200
Re: [v3 9/9] s390: teach platforms not to zero struct pages memory Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-16 02:40 +0200
[v3 1/9] sparc64: simplify vmemmap_populate Pavel Tatashin <pasha.tatashin@oracle.com> - 2017-05-05 19:10 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Michal Hocko <mhocko@kernel.org> - 2017-05-09 20:20 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-09 21:00 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Michal Hocko <mhocko@kernel.org> - 2017-05-10 09:30 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-10 15:50 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Michal Hocko <mhocko@kernel.org> - 2017-05-10 17:00 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-10 17:10 +0200
Re: [v3 0/9] parallelized "struct page" zeroing David Miller <davem@davemloft.net> - 2017-05-10 17:30 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-11 22:50 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-11 23:10 +0200
Re: [v3 0/9] parallelized "struct page" zeroing David Miller <davem@davemloft.net> - 2017-05-12 19:00 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-12 19:30 +0200
Re: [v3 0/9] parallelized "struct page" zeroing David Miller <davem@davemloft.net> - 2017-05-12 19:40 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Benjamin Herrenschmidt <benh@au1.ibm.com> - 2017-05-17 02:00 +0200
Re: [v3 0/9] parallelized "struct page" zeroing David Miller <davem@davemloft.net> - 2017-05-12 19:00 +0200
Re: [v3 0/9] parallelized "struct page" zeroing David Miller <davem@davemloft.net> - 2017-05-10 17:20 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Matthew Wilcox <willy@infradead.org> - 2017-05-10 19:20 +0200
Re: [v3 0/9] parallelized "struct page" zeroing David Miller <davem@davemloft.net> - 2017-05-10 20:10 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Matthew Wilcox <willy@infradead.org> - 2017-05-10 23:20 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Michal Hocko <mhocko@kernel.org> - 2017-05-11 10:10 +0200
Re: [v3 0/9] parallelized "struct page" zeroing David Miller <davem@davemloft.net> - 2017-05-11 16:40 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-15 20:20 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Michal Hocko <mhocko@kernel.org> - 2017-05-15 21:40 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Pasha Tatashin <pasha.tatashin@oracle.com> - 2017-05-15 22:50 +0200
Re: [v3 0/9] parallelized "struct page" zeroing Michal Hocko <mhocko@kernel.org> - 2017-05-16 10:40 +0200
Page 1 of 2 [1] 2 Next page →
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-05 19:10 +0200 |
| Subject | [v3 0/9] parallelized "struct page" zeroing |
| Message-ID | <tDOTT-4Dx-3@gated-at.bofh.it> |
Changelog: v2 - v3 - Addressed David's comments about one change per patch: * Splited changes to platforms into 4 patches * Made "do not zero vmemmap_buf" as a separate patch v1 - v2 - Per request, added s390 to deferred "struct page" zeroing - Collected performance data on x86 which proofs the importance to keep memset() as prefetch (see below). When deferred struct page initialization feature is enabled, we get a performance gain of initializing vmemmap in parallel after other CPUs are started. However, we still zero the memory for vmemmap using one boot CPU. This patch-set fixes the memset-zeroing limitation by deferring it as well. Performance gain on SPARC with 32T: base: https://hastebin.com/ozanelatat.go fix: https://hastebin.com/utonawukof.go As you can see without the fix it takes: 97.89s to boot With the fix it takes: 46.91 to boot. Performance gain on x86 with 1T: base: https://hastebin.com/uvifasohon.pas fix: https://hastebin.com/anodiqaguj.pas On Intel we save 10.66s/T while on SPARC we save 1.59s/T. Intel has twice as many pages, and also fewer nodes than SPARC (sparc 32 nodes, vs. intel 8 nodes). It takes one thread 11.25s to zero vmemmap on Intel for 1T, so it should take additional 11.25 / 8 = 1.4s (this machine has 8 nodes) per node to initialize the memory, but it takes only additional 0.456s per node, which means on Intel we also benefit from having memset() and initializing all other fields in one place. Pavel Tatashin (9): sparc64: simplify vmemmap_populate mm: defining memblock_virt_alloc_try_nid_raw mm: add "zero" argument to vmemmap allocators mm: do not zero vmemmap_buf mm: zero struct pages during initialization sparc64: teach sparc not to zero struct pages memory x86: teach x86 not to zero struct pages memory powerpc: teach platforms not to zero struct pages memory s390: teach platforms not to zero struct pages memory arch/powerpc/mm/init_64.c | 4 +- arch/s390/mm/vmem.c | 5 ++- arch/sparc/mm/init_64.c | 26 +++++++---------------- arch/x86/mm/init_64.c | 3 +- include/linux/bootmem.h | 3 ++ include/linux/mm.h | 15 +++++++++++-- mm/memblock.c | 46 ++++++++++++++++++++++++++++++++++++------ mm/page_alloc.c | 3 ++ mm/sparse-vmemmap.c | 48 +++++++++++++++++++++++++++++--------------- 9 files changed, 103 insertions(+), 50 deletions(-)
[toc] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-05 19:10 +0200 |
| Subject | [v3 8/9] powerpc: teach platforms not to zero struct pages memory |
| Message-ID | <tDOTU-4Dx-25@gated-at.bofh.it> |
| In reply to | #1636499 |
If we are using deferred struct page initialization feature, most of "struct page"es are getting initialized after other CPUs are started, and hence we are benefiting from doing this job in parallel. However, we are still zeroing all the memory that is allocated for "struct pages" using the boot CPU. This patch solves this problem, by deferring zeroing "struct pages" to only when they are initialized on PowerPC platforms. Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com> Reviewed-by: Shannon Nelson <shannon.nelson@oracle.com> --- arch/powerpc/mm/init_64.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index d42c6b3..c381bd7 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -181,7 +181,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) if (vmemmap_populated(start, page_size)) continue; - p = vmemmap_alloc_block(page_size, node, true); + p = vmemmap_alloc_block(page_size, node, VMEMMAP_ZERO); if (!p) return -ENOMEM; -- 1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-05 19:10 +0200 |
| Subject | [v3 9/9] s390: teach platforms not to zero struct pages memory |
| Message-ID | <tDOTV-4Dx-29@gated-at.bofh.it> |
| In reply to | #1636499 |
If we are using deferred struct page initialization feature, most of "struct page"es are getting initialized after other CPUs are started, and hence we are benefiting from doing this job in parallel. However, we are still zeroing all the memory that is allocated for "struct pages" using the boot CPU. This patch solves this problem, by deferring zeroing "struct pages" to only when they are initialized on s390 platforms. Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com> Reviewed-by: Shannon Nelson <shannon.nelson@oracle.com> --- arch/s390/mm/vmem.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 9c75214..ffe9ba1 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -252,7 +252,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) void *new_page; new_page = vmemmap_alloc_block(PMD_SIZE, node, - true); + VMEMMAP_ZERO); if (!new_page) goto out; pmd_val(*pm_dir) = __pa(new_page) | sgt_prot; -- 1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Heiko Carstens <heiko.carstens@de.ibm.com> |
|---|---|
| Date | 2017-05-08 13:40 +0200 |
| Subject | Re: [v3 9/9] s390: teach platforms not to zero struct pages memory |
| Message-ID | <tEPbb-3lD-5@gated-at.bofh.it> |
| In reply to | #1636502 |
On Fri, May 05, 2017 at 01:03:16PM -0400, Pavel Tatashin wrote:
> If we are using deferred struct page initialization feature, most of
> "struct page"es are getting initialized after other CPUs are started, and
> hence we are benefiting from doing this job in parallel. However, we are
> still zeroing all the memory that is allocated for "struct pages" using the
> boot CPU. This patch solves this problem, by deferring zeroing "struct
> pages" to only when they are initialized on s390 platforms.
>
> Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
> Reviewed-by: Shannon Nelson <shannon.nelson@oracle.com>
> ---
> arch/s390/mm/vmem.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
> index 9c75214..ffe9ba1 100644
> --- a/arch/s390/mm/vmem.c
> +++ b/arch/s390/mm/vmem.c
> @@ -252,7 +252,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
> void *new_page;
>
> new_page = vmemmap_alloc_block(PMD_SIZE, node,
> - true);
> + VMEMMAP_ZERO);
> if (!new_page)
> goto out;
> pmd_val(*pm_dir) = __pa(new_page) | sgt_prot;
If you add the hunk below then this is
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index ffe9ba1aec8b..bf88a8b9c24d 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -272,7 +272,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
if (pte_none(*pt_dir)) {
void *new_page;
- new_page = vmemmap_alloc_block(PAGE_SIZE, node, true);
+ new_page = vmemmap_alloc_block(PAGE_SIZE, node, VMEMMAP_ZERO);
if (!new_page)
goto out;
pte_val(*pt_dir) = __pa(new_page) | pgt_prot;
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-15 20:30 +0200 |
| Subject | Re: [v3 9/9] s390: teach platforms not to zero struct pages memory |
| Message-ID | <tHsUN-3dA-13@gated-at.bofh.it> |
| In reply to | #1637394 |
Hi Heiko,
Thank you for looking at this patch. I am worried to make the proposed
change, because, as I understand in this case we allocate memory not for
"struct page"s but for table that hold them. So, we will change the
behavior from the current one, where this table is allocated zeroed, but
now it won't be zeroed.
Pasha
>
> If you add the hunk below then this is
>
> Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
>
> diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
> index ffe9ba1aec8b..bf88a8b9c24d 100644
> --- a/arch/s390/mm/vmem.c
> +++ b/arch/s390/mm/vmem.c
> @@ -272,7 +272,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
> if (pte_none(*pt_dir)) {
> void *new_page;
>
> - new_page = vmemmap_alloc_block(PAGE_SIZE, node, true);
> + new_page = vmemmap_alloc_block(PAGE_SIZE, node, VMEMMAP_ZERO);
> if (!new_page)
> goto out;
> pte_val(*pt_dir) = __pa(new_page) | pgt_prot;
>
[toc] | [prev] | [next] | [standalone]
| From | Heiko Carstens <heiko.carstens@de.ibm.com> |
|---|---|
| Date | 2017-05-16 01:20 +0200 |
| Subject | Re: [v3 9/9] s390: teach platforms not to zero struct pages memory |
| Message-ID | <tHxrr-6b0-7@gated-at.bofh.it> |
| In reply to | #1641962 |
Hello Pasha,
> Thank you for looking at this patch. I am worried to make the proposed
> change, because, as I understand in this case we allocate memory not for
> "struct page"s but for table that hold them. So, we will change the behavior
> from the current one, where this table is allocated zeroed, but now it won't
> be zeroed.
The page table, if needed, is allocated and populated a couple of lines
above. See the vmem_pte_alloc() call. So my request to include the hunk
below is still valid ;)
> >If you add the hunk below then this is
> >
> >Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
> >
> >diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
> >index ffe9ba1aec8b..bf88a8b9c24d 100644
> >--- a/arch/s390/mm/vmem.c
> >+++ b/arch/s390/mm/vmem.c
> >@@ -272,7 +272,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
> > if (pte_none(*pt_dir)) {
> > void *new_page;
> >- new_page = vmemmap_alloc_block(PAGE_SIZE, node, true);
> >+ new_page = vmemmap_alloc_block(PAGE_SIZE, node, VMEMMAP_ZERO);
> > if (!new_page)
> > goto out;
> > pte_val(*pt_dir) = __pa(new_page) | pgt_prot;
> >
>
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-16 02:40 +0200 |
| Subject | Re: [v3 9/9] s390: teach platforms not to zero struct pages memory |
| Message-ID | <tHyGR-6OV-1@gated-at.bofh.it> |
| In reply to | #1642118 |
Ah OK, I will include the change.
Thank you,
Pasha
On 05/15/2017 07:17 PM, Heiko Carstens wrote:
> Hello Pasha,
>
>> Thank you for looking at this patch. I am worried to make the proposed
>> change, because, as I understand in this case we allocate memory not for
>> "struct page"s but for table that hold them. So, we will change the behavior
>> from the current one, where this table is allocated zeroed, but now it won't
>> be zeroed.
>
> The page table, if needed, is allocated and populated a couple of lines
> above. See the vmem_pte_alloc() call. So my request to include the hunk
> below is still valid ;)
>
>>> If you add the hunk below then this is
>>>
>>> Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
>>>
>>> diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
>>> index ffe9ba1aec8b..bf88a8b9c24d 100644
>>> --- a/arch/s390/mm/vmem.c
>>> +++ b/arch/s390/mm/vmem.c
>>> @@ -272,7 +272,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
>>> if (pte_none(*pt_dir)) {
>>> void *new_page;
>>> - new_page = vmemmap_alloc_block(PAGE_SIZE, node, true);
>>> + new_page = vmemmap_alloc_block(PAGE_SIZE, node, VMEMMAP_ZERO);
>>> if (!new_page)
>>> goto out;
>>> pte_val(*pt_dir) = __pa(new_page) | pgt_prot;
>>>
>>
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo@kvack.org. For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
>
[toc] | [prev] | [next] | [standalone]
| From | Pavel Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-05 19:10 +0200 |
| Subject | [v3 1/9] sparc64: simplify vmemmap_populate |
| Message-ID | <tDOTV-4Dx-31@gated-at.bofh.it> |
| In reply to | #1636499 |
Remove duplicating code, by using common functions
vmemmap_pud_populate and vmemmap_pgd_populate functions.
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Reviewed-by: Shannon Nelson <shannon.nelson@oracle.com>
---
arch/sparc/mm/init_64.c | 23 ++++++-----------------
1 files changed, 6 insertions(+), 17 deletions(-)
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 0cda653..14cc1fc 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -2530,30 +2530,19 @@ int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,
vstart = vstart & PMD_MASK;
vend = ALIGN(vend, PMD_SIZE);
for (; vstart < vend; vstart += PMD_SIZE) {
- pgd_t *pgd = pgd_offset_k(vstart);
+ pgd_t *pgd = vmemmap_pgd_populate(vstart, node);
unsigned long pte;
pud_t *pud;
pmd_t *pmd;
- if (pgd_none(*pgd)) {
- pud_t *new = vmemmap_alloc_block(PAGE_SIZE, node);
+ if (!pgd)
+ return -ENOMEM;
- if (!new)
- return -ENOMEM;
- pgd_populate(&init_mm, pgd, new);
- }
-
- pud = pud_offset(pgd, vstart);
- if (pud_none(*pud)) {
- pmd_t *new = vmemmap_alloc_block(PAGE_SIZE, node);
-
- if (!new)
- return -ENOMEM;
- pud_populate(&init_mm, pud, new);
- }
+ pud = vmemmap_pud_populate(pgd, vstart, node);
+ if (!pud)
+ return -ENOMEM;
pmd = pmd_offset(pud, vstart);
-
pte = pmd_val(*pmd);
if (!(pte & _PAGE_VALID)) {
void *block = vmemmap_alloc_block(PMD_SIZE, node);
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-05-09 20:20 +0200 |
| Message-ID | <tFhTP-5nA-11@gated-at.bofh.it> |
| In reply to | #1636499 |
On Fri 05-05-17 13:03:07, Pavel Tatashin wrote:
> Changelog:
> v2 - v3
> - Addressed David's comments about one change per patch:
> * Splited changes to platforms into 4 patches
> * Made "do not zero vmemmap_buf" as a separate patch
> v1 - v2
> - Per request, added s390 to deferred "struct page" zeroing
> - Collected performance data on x86 which proofs the importance to
> keep memset() as prefetch (see below).
>
> When deferred struct page initialization feature is enabled, we get a
> performance gain of initializing vmemmap in parallel after other CPUs are
> started. However, we still zero the memory for vmemmap using one boot CPU.
> This patch-set fixes the memset-zeroing limitation by deferring it as well.
I like the idea of postponing the zeroing from the allocation to the
init time. To be honest the improvement looks much larger than I would
expect (Btw. this should be a part of the changelog rather than a
outside link).
The implementation just looks too large to what I would expect. E.g. do
we really need to add zero argument to the large part of the memblock
API? Wouldn't it be easier to simply export memblock_virt_alloc_internal
(or its tiny wrapper memblock_virt_alloc_core) and move the zeroing
outside to its 2 callers? A completely untested scratched version at the
end of the email.
Also it seems that this is not 100% correct either as it only cares
about VMEMMAP while DEFERRED_STRUCT_PAGE_INIT might be enabled also for
SPARSEMEM. This would suggest that we would zero out pages twice,
right?
A similar concern would go to the memory hotplug patch which will
fall back to the slab/page allocator IIRC. On the other hand
__init_single_page is shared with the hotplug code so again we would
initialize 2 times.
So I suspect more changes are needed. I will have a closer look tomorrow.
> arch/powerpc/mm/init_64.c | 4 +-
> arch/s390/mm/vmem.c | 5 ++-
> arch/sparc/mm/init_64.c | 26 +++++++----------------
> arch/x86/mm/init_64.c | 3 +-
> include/linux/bootmem.h | 3 ++
> include/linux/mm.h | 15 +++++++++++--
> mm/memblock.c | 46 ++++++++++++++++++++++++++++++++++++------
> mm/page_alloc.c | 3 ++
> mm/sparse-vmemmap.c | 48 +++++++++++++++++++++++++++++---------------
> 9 files changed, 103 insertions(+), 50 deletions(-)
The bootmem API change mentioned above.
include/linux/bootmem.h | 3 +++
mm/memblock.c | 41 ++++++++++++++++++++++++++---------------
mm/sparse-vmemmap.c | 2 +-
3 files changed, 30 insertions(+), 16 deletions(-)
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 962164d36506..c9a08463d9a8 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -160,6 +160,9 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
#define BOOTMEM_ALLOC_ANYWHERE (~(phys_addr_t)0)
/* FIXME: Move to memblock.h at a point where we remove nobootmem.c */
+void * memblock_virt_alloc_core(phys_addr_t size, phys_addr_t align,
+ phys_addr_t min_addr, phys_addr_t max_addr,
+ int nid);
void *memblock_virt_alloc_try_nid_nopanic(phys_addr_t size,
phys_addr_t align, phys_addr_t min_addr,
phys_addr_t max_addr, int nid);
diff --git a/mm/memblock.c b/mm/memblock.c
index b049c9b2dba8..eab7da94f873 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1271,8 +1271,7 @@ phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, i
*
* The memory block is aligned on SMP_CACHE_BYTES if @align == 0.
*
- * The phys address of allocated boot memory block is converted to virtual and
- * allocated memory is reset to 0.
+ * The function has to be zeroed out explicitly.
*
* In addition, function sets the min_count to 0 using kmemleak_alloc for
* allocated boot memory block, so that it is never reported as leaks.
@@ -1280,15 +1279,18 @@ phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, i
* RETURNS:
* Virtual address of allocated memory block on success, NULL on failure.
*/
-static void * __init memblock_virt_alloc_internal(
+static inline void * __init memblock_virt_alloc_internal(
phys_addr_t size, phys_addr_t align,
phys_addr_t min_addr, phys_addr_t max_addr,
- int nid)
+ int nid, void *caller)
{
phys_addr_t alloc;
void *ptr;
ulong flags = choose_memblock_flags();
+ memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF\n",
+ __func__, (u64)size, (u64)align, nid, (u64)min_addr,
+ (u64)max_addr, caller);
if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
nid = NUMA_NO_NODE;
@@ -1334,7 +1336,6 @@ static void * __init memblock_virt_alloc_internal(
return NULL;
done:
ptr = phys_to_virt(alloc);
- memset(ptr, 0, size);
/*
* The min_count is set to 0 so that bootmem allocated blocks
@@ -1347,6 +1348,14 @@ static void * __init memblock_virt_alloc_internal(
return ptr;
}
+void * __init memblock_virt_alloc_core(phys_addr_t size, phys_addr_t align,
+ phys_addr_t min_addr, phys_addr_t max_addr,
+ int nid)
+{
+ return memblock_virt_alloc_internal(size, align, min_addr, max_addr, nid,
+ (void *)_RET_IP_);
+}
+
/**
* memblock_virt_alloc_try_nid_nopanic - allocate boot memory block
* @size: size of memory block to be allocated in bytes
@@ -1369,11 +1378,14 @@ void * __init memblock_virt_alloc_try_nid_nopanic(
phys_addr_t min_addr, phys_addr_t max_addr,
int nid)
{
- memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF\n",
- __func__, (u64)size, (u64)align, nid, (u64)min_addr,
- (u64)max_addr, (void *)_RET_IP_);
- return memblock_virt_alloc_internal(size, align, min_addr,
- max_addr, nid);
+ void *ptr;
+
+ ptr = memblock_virt_alloc_internal(size, align, min_addr,
+ max_addr, nid, (void *)_RET_IP_);
+ if (ptr)
+ memset(ptr, 0, size);
+
+ return ptr;
}
/**
@@ -1401,13 +1413,12 @@ void * __init memblock_virt_alloc_try_nid(
{
void *ptr;
- memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx %pF\n",
- __func__, (u64)size, (u64)align, nid, (u64)min_addr,
- (u64)max_addr, (void *)_RET_IP_);
ptr = memblock_virt_alloc_internal(size, align,
- min_addr, max_addr, nid);
- if (ptr)
+ min_addr, max_addr, nid, (void *)_RET_IP_);
+ if (ptr) {
+ memset(ptr, 0, size);
return ptr;
+ }
panic("%s: Failed to allocate %llu bytes align=0x%llx nid=%d from=0x%llx max_addr=0x%llx\n",
__func__, (u64)size, (u64)align, nid, (u64)min_addr,
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index a56c3989f773..4e060f0f9fe5 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -41,7 +41,7 @@ static void * __ref __earlyonly_bootmem_alloc(int node,
unsigned long align,
unsigned long goal)
{
- return memblock_virt_alloc_try_nid(size, align, goal,
+ return memblock_virt_alloc_core(size, align, goal,
BOOTMEM_ALLOC_ACCESSIBLE, node);
}
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-09 21:00 +0200 |
| Message-ID | <tFiwy-5FK-15@gated-at.bofh.it> |
| In reply to | #1638330 |
Hi Michal, > I like the idea of postponing the zeroing from the allocation to the > init time. To be honest the improvement looks much larger than I would > expect (Btw. this should be a part of the changelog rather than a > outside link). The improvements are larger, because this time was never measured, as Linux does not have early boot time stamps. I added them for x86 and SPARC to emasure the performance. I am pushing those changes through separate patchsets. > > The implementation just looks too large to what I would expect. E.g. do > we really need to add zero argument to the large part of the memblock > API? Wouldn't it be easier to simply export memblock_virt_alloc_internal > (or its tiny wrapper memblock_virt_alloc_core) and move the zeroing > outside to its 2 callers? A completely untested scratched version at the > end of the email. I am OK, with this change. But, I do not really see a difference between: memblock_virt_alloc_raw() and memblock_virt_alloc_core() In both cases we use memblock_virt_alloc_internal(), but the only difference is that in my case we tell memblock_virt_alloc_internal() to zero the pages if needed, and in your case the other two callers are zeroing it. I like moving memblock_dbg() inside memblock_virt_alloc_internal() > > Also it seems that this is not 100% correct either as it only cares > about VMEMMAP while DEFERRED_STRUCT_PAGE_INIT might be enabled also for > SPARSEMEM. This would suggest that we would zero out pages twice, > right? Thank you, I will check this combination before sending out the next patch. > > A similar concern would go to the memory hotplug patch which will > fall back to the slab/page allocator IIRC. On the other hand > __init_single_page is shared with the hotplug code so again we would > initialize 2 times. Correct, when memory it hotplugged, to gain the benefit of this fix, and also not to regress by actually double zeroing "struct pages" we should not zero it out. However, I do not really have means to test it. > > So I suspect more changes are needed. I will have a closer look tomorrow. Thank you for reviewing this work. I will wait for your comments before sending out updated patches. Pasha
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-05-10 09:30 +0200 |
| Message-ID | <tFuem-6dd-7@gated-at.bofh.it> |
| In reply to | #1638350 |
On Tue 09-05-17 14:54:50, Pasha Tatashin wrote: [...] > >The implementation just looks too large to what I would expect. E.g. do > >we really need to add zero argument to the large part of the memblock > >API? Wouldn't it be easier to simply export memblock_virt_alloc_internal > >(or its tiny wrapper memblock_virt_alloc_core) and move the zeroing > >outside to its 2 callers? A completely untested scratched version at the > >end of the email. > > I am OK, with this change. But, I do not really see a difference between: > > memblock_virt_alloc_raw() > and > memblock_virt_alloc_core() > > In both cases we use memblock_virt_alloc_internal(), but the only difference > is that in my case we tell memblock_virt_alloc_internal() to zero the pages > if needed, and in your case the other two callers are zeroing it. I like > moving memblock_dbg() inside memblock_virt_alloc_internal() Well, I didn't object to this particular part. I was mostly concerned about http://lkml.kernel.org/r/1494003796-748672-4-git-send-email-pasha.tatashin@oracle.com and the "zero" argument for other functions. I guess we can do without that. I _think_ that we should simply _always_ initialize the page at the __init_single_page time rather than during the allocation. That would require dropping __GFP_ZERO for non-memblock allocations. Or do you think we could regress for single threaded initialization? > >Also it seems that this is not 100% correct either as it only cares > >about VMEMMAP while DEFERRED_STRUCT_PAGE_INIT might be enabled also for > >SPARSEMEM. This would suggest that we would zero out pages twice, > >right? > > Thank you, I will check this combination before sending out the next patch. > > > > >A similar concern would go to the memory hotplug patch which will > >fall back to the slab/page allocator IIRC. On the other hand > >__init_single_page is shared with the hotplug code so again we would > >initialize 2 times. > > Correct, when memory it hotplugged, to gain the benefit of this fix, and > also not to regress by actually double zeroing "struct pages" we should not > zero it out. However, I do not really have means to test it. It should be pretty easy to test with kvm, but I can help with testing on the real HW as well. Thanks! -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-10 15:50 +0200 |
| Message-ID | <tFAa6-1mz-19@gated-at.bofh.it> |
| In reply to | #1638606 |
> > Well, I didn't object to this particular part. I was mostly concerned > about > http://lkml.kernel.org/r/1494003796-748672-4-git-send-email-pasha.tatashin@oracle.com > and the "zero" argument for other functions. I guess we can do without > that. I _think_ that we should simply _always_ initialize the page at the > __init_single_page time rather than during the allocation. That would > require dropping __GFP_ZERO for non-memblock allocations. Or do you > think we could regress for single threaded initialization? > Hi Michal, Thats exactly right, I am worried that we will regress when there is no parallelized initialization of "struct pages" if we force unconditionally do memset() in __init_single_page(). The overhead of calling memset() on a smaller chunks (64-bytes) may cause the regression, this is why I opted only for parallelized case to zero this metadata. This way, we are guaranteed to see great improvements from this change without having regressions on platforms and builds that do not support parallelized initialization of "struct pages". However, on some chips such as latest SPARCs it is beneficial to have memset() right inside __init_single_page() even for single threaded case, because it can act as a prefetch on chips with optimized block initialized store instructions. Pasha
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-05-10 17:00 +0200 |
| Message-ID | <tFBfQ-20m-9@gated-at.bofh.it> |
| In reply to | #1638840 |
On Wed 10-05-17 09:42:22, Pasha Tatashin wrote: > > > >Well, I didn't object to this particular part. I was mostly concerned > >about > >http://lkml.kernel.org/r/1494003796-748672-4-git-send-email-pasha.tatashin@oracle.com > >and the "zero" argument for other functions. I guess we can do without > >that. I _think_ that we should simply _always_ initialize the page at the > >__init_single_page time rather than during the allocation. That would > >require dropping __GFP_ZERO for non-memblock allocations. Or do you > >think we could regress for single threaded initialization? > > > > Hi Michal, > > Thats exactly right, I am worried that we will regress when there is no > parallelized initialization of "struct pages" if we force unconditionally do > memset() in __init_single_page(). The overhead of calling memset() on a > smaller chunks (64-bytes) may cause the regression, this is why I opted only > for parallelized case to zero this metadata. This way, we are guaranteed to > see great improvements from this change without having regressions on > platforms and builds that do not support parallelized initialization of > "struct pages". Have you measured that? I do not think it would be super hard to measure. I would be quite surprised if this added much if anything at all as the whole struct page should be in the cache line already. We do set reference count and other struct members. Almost nobody should be looking at our page at this time and stealing the cache line. On the other hand a large memcpy will basically wipe everything away from the cpu cache. Or am I missing something? -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-10 17:10 +0200 |
| Message-ID | <tFBpw-2iN-21@gated-at.bofh.it> |
| In reply to | #1638896 |
On 05/10/2017 10:57 AM, Michal Hocko wrote: > On Wed 10-05-17 09:42:22, Pasha Tatashin wrote: >>> >>> Well, I didn't object to this particular part. I was mostly concerned >>> about >>> http://lkml.kernel.org/r/1494003796-748672-4-git-send-email-pasha.tatashin@oracle.com >>> and the "zero" argument for other functions. I guess we can do without >>> that. I _think_ that we should simply _always_ initialize the page at the >>> __init_single_page time rather than during the allocation. That would >>> require dropping __GFP_ZERO for non-memblock allocations. Or do you >>> think we could regress for single threaded initialization? >>> >> >> Hi Michal, >> >> Thats exactly right, I am worried that we will regress when there is no >> parallelized initialization of "struct pages" if we force unconditionally do >> memset() in __init_single_page(). The overhead of calling memset() on a >> smaller chunks (64-bytes) may cause the regression, this is why I opted only >> for parallelized case to zero this metadata. This way, we are guaranteed to >> see great improvements from this change without having regressions on >> platforms and builds that do not support parallelized initialization of >> "struct pages". > > Have you measured that? I do not think it would be super hard to > measure. I would be quite surprised if this added much if anything at > all as the whole struct page should be in the cache line already. We do > set reference count and other struct members. Almost nobody should be > looking at our page at this time and stealing the cache line. On the > other hand a large memcpy will basically wipe everything away from the > cpu cache. Or am I missing something? > Perhaps you are right, and I will measure on x86. But, I suspect hit can become unacceptable on some platfoms: there is an overhead of calling a function, even if it is leaf-optimized, and there is an overhead in memset() to check for alignments of size and address, types of setting (zeroing vs. non-zeroing), etc., that adds up quickly. Pasha
[toc] | [prev] | [next] | [standalone]
| From | David Miller <davem@davemloft.net> |
|---|---|
| Date | 2017-05-10 17:30 +0200 |
| Message-ID | <tFBIR-2p1-1@gated-at.bofh.it> |
| In reply to | #1638899 |
From: Pasha Tatashin <pasha.tatashin@oracle.com> Date: Wed, 10 May 2017 11:01:40 -0400 > Perhaps you are right, and I will measure on x86. But, I suspect hit > can become unacceptable on some platfoms: there is an overhead of > calling a function, even if it is leaf-optimized, and there is an > overhead in memset() to check for alignments of size and address, > types of setting (zeroing vs. non-zeroing), etc., that adds up > quickly. Another source of overhead on the sparc64 side is that we much do memory barriers around the block initializiing stores. So batching calls to memset() amortize that as well.
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-11 22:50 +0200 |
| Message-ID | <tG3c5-2La-1@gated-at.bofh.it> |
| In reply to | #1638899 |
>> >> Have you measured that? I do not think it would be super hard to >> measure. I would be quite surprised if this added much if anything at >> all as the whole struct page should be in the cache line already. We do >> set reference count and other struct members. Almost nobody should be >> looking at our page at this time and stealing the cache line. On the >> other hand a large memcpy will basically wipe everything away from the >> cpu cache. Or am I missing something? >> Here is data for single thread (deferred struct page init is disabled): Intel CPU E7-8895 v3 @ 2.60GHz 1T memory ----------------------------------------- time to memset "struct pages in memblock: 11.28s time to init "struct pag"es: 4.90s Moving memset into __init_single_page() time to init and memset "struct page"es: 8.39s SPARC M6 @ 3600 MHz 1T memory ----------------------------------------- time to memset "struct pages in memblock: 1.60s time to init "struct pag"es: 3.37s Moving memset into __init_single_page() time to init and memset "struct page"es: 12.99s So, moving memset() into __init_single_page() benefits Intel. I am actually surprised why memset() is so slow on intel when it is called from memblock. But, hurts SPARC, I guess these membars at the end of memset() kills the performance. Also, when looking at these values, remeber that Intel has twice as many "struct page" for the same amount of memory. Pasha
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-11 23:10 +0200 |
| Message-ID | <tG3vu-37w-65@gated-at.bofh.it> |
| In reply to | #1640011 |
We should either keep memset() only for deferred struct pages as what I have in my patches. Another option is to add a new function struct_page_clear() which would default to memset() and to something else on platforms that decide to optimize it. On SPARC it would call STBIs, and we would do one membar call after all "struct pages" are initialized. I think what I sent out already is cleaner and better solution, because I am not sure what kind of performance we would see on other chips. On 05/11/2017 04:47 PM, Pasha Tatashin wrote: >>> >>> Have you measured that? I do not think it would be super hard to >>> measure. I would be quite surprised if this added much if anything at >>> all as the whole struct page should be in the cache line already. We do >>> set reference count and other struct members. Almost nobody should be >>> looking at our page at this time and stealing the cache line. On the >>> other hand a large memcpy will basically wipe everything away from the >>> cpu cache. Or am I missing something? >>> > > Here is data for single thread (deferred struct page init is disabled): > > Intel CPU E7-8895 v3 @ 2.60GHz 1T memory > ----------------------------------------- > time to memset "struct pages in memblock: 11.28s > time to init "struct pag"es: 4.90s > > Moving memset into __init_single_page() > time to init and memset "struct page"es: 8.39s > > SPARC M6 @ 3600 MHz 1T memory > ----------------------------------------- > time to memset "struct pages in memblock: 1.60s > time to init "struct pag"es: 3.37s > > Moving memset into __init_single_page() > time to init and memset "struct page"es: 12.99s > > > So, moving memset() into __init_single_page() benefits Intel. I am > actually surprised why memset() is so slow on intel when it is called > from memblock. But, hurts SPARC, I guess these membars at the end of > memset() kills the performance. > > Also, when looking at these values, remeber that Intel has twice as many > "struct page" for the same amount of memory. > > Pasha > -- > To unsubscribe from this list: send the line "unsubscribe sparclinux" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
[toc] | [prev] | [next] | [standalone]
| From | David Miller <davem@davemloft.net> |
|---|---|
| Date | 2017-05-12 19:00 +0200 |
| Message-ID | <tGm54-7o1-11@gated-at.bofh.it> |
| In reply to | #1640047 |
From: Pasha Tatashin <pasha.tatashin@oracle.com> Date: Thu, 11 May 2017 16:59:33 -0400 > We should either keep memset() only for deferred struct pages as what > I have in my patches. > > Another option is to add a new function struct_page_clear() which > would default to memset() and to something else on platforms that > decide to optimize it. > > On SPARC it would call STBIs, and we would do one membar call after > all "struct pages" are initialized. No membars will be performed for single individual page struct clear, the cutoff to use the STBI is larger than that.
[toc] | [prev] | [next] | [standalone]
| From | Pasha Tatashin <pasha.tatashin@oracle.com> |
|---|---|
| Date | 2017-05-12 19:30 +0200 |
| Message-ID | <tGmy6-7Uc-37@gated-at.bofh.it> |
| In reply to | #1640598 |
On 05/12/2017 12:57 PM, David Miller wrote:
> From: Pasha Tatashin <pasha.tatashin@oracle.com>
> Date: Thu, 11 May 2017 16:59:33 -0400
>
>> We should either keep memset() only for deferred struct pages as what
>> I have in my patches.
>>
>> Another option is to add a new function struct_page_clear() which
>> would default to memset() and to something else on platforms that
>> decide to optimize it.
>>
>> On SPARC it would call STBIs, and we would do one membar call after
>> all "struct pages" are initialized.
>
> No membars will be performed for single individual page struct clear,
> the cutoff to use the STBI is larger than that.
>
Right now it is larger, but what I suggested is to add a new optimized
routine just for this case, which would do STBI for 64-bytes but without
membar (do membar at the end of memmap_init_zone() and
deferred_init_memmap()
#define struct_page_clear(page) \
__asm__ __volatile__( \
"stxa %%g0, [%0]%2\n" \
"stxa %%xg0, [%0 + %1]%2\n" \
: /* No output */ \
: "r" (page), "r" (0x20), "i"(ASI_BLK_INIT_QUAD_LDD_P))
And insert it into __init_single_page() instead of memset()
The final result is 4.01s/T which is even faster compared to current 4.97s/T
Pasha
[toc] | [prev] | [next] | [standalone]
| From | David Miller <davem@davemloft.net> |
|---|---|
| Date | 2017-05-12 19:40 +0200 |
| Message-ID | <tGmHM-7YH-5@gated-at.bofh.it> |
| In reply to | #1640641 |
From: Pasha Tatashin <pasha.tatashin@oracle.com> Date: Fri, 12 May 2017 13:24:52 -0400 > Right now it is larger, but what I suggested is to add a new optimized > routine just for this case, which would do STBI for 64-bytes but > without membar (do membar at the end of memmap_init_zone() and > deferred_init_memmap() > > #define struct_page_clear(page) \ > __asm__ __volatile__( \ > "stxa %%g0, [%0]%2\n" \ > "stxa %%xg0, [%0 + %1]%2\n" \ > : /* No output */ \ > : "r" (page), "r" (0x20), "i"(ASI_BLK_INIT_QUAD_LDD_P)) > > And insert it into __init_single_page() instead of memset() > > The final result is 4.01s/T which is even faster compared to current > 4.97s/T Ok, indeed, that would work.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web