From: Muchun Song <songmuchun@bytedance.com>
To: Joao Martins <joao.m.martins@oracle.com>
Cc: Linux Memory Management List <linux-mm@kvack.org>,
Dan Williams <dan.j.williams@intel.com>,
Vishal Verma <vishal.l.verma@intel.com>,
Dave Jiang <dave.jiang@intel.com>,
Naoya Horiguchi <naoya.horiguchi@nec.com>,
Matthew Wilcox <willy@infradead.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
John Hubbard <jhubbard@nvidia.com>,
Jane Chu <jane.chu@oracle.com>,
Mike Kravetz <mike.kravetz@oracle.com>,
Andrew Morton <akpm@linux-foundation.org>,
Jonathan Corbet <corbet@lwn.net>,
nvdimm@lists.linux.dev, linux-doc@vger.kernel.org
Subject: Re: [External] [PATCH v2 07/14] mm/hugetlb_vmemmap: move comment block to Documentation/vm
Date: Mon, 21 Jun 2021 21:12:03 +0800 [thread overview]
Message-ID: <CAMZfGtXSJE2ZsSOBW7Ef0VtP=+Q=cULSw9urqZGSG_WbGTiaSA@mail.gmail.com> (raw)
In-Reply-To: <20210617184507.3662-8-joao.m.martins@oracle.com>
On Fri, Jun 18, 2021 at 2:46 AM Joao Martins <joao.m.martins@oracle.com> wrote:
>
> In preparation for device-dax for using hugetlbfs compound page tail
> deduplication technique, move the comment block explanation into a
> common place in Documentation/vm.
>
> Cc: Muchun Song <songmuchun@bytedance.com>
> Cc: Mike Kravetz <mike.kravetz@oracle.com>
> Suggested-by: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
> ---
> Documentation/vm/compound_pagemaps.rst | 170 +++++++++++++++++++++++++
> Documentation/vm/index.rst | 1 +
> mm/hugetlb_vmemmap.c | 162 +----------------------
> 3 files changed, 172 insertions(+), 161 deletions(-)
> create mode 100644 Documentation/vm/compound_pagemaps.rst
IMHO, how about the name of vmemmap_remap.rst? page_frags.rst seems
to tell people it's about the page mapping not its vmemmap mapping.
Thanks.
>
> diff --git a/Documentation/vm/compound_pagemaps.rst b/Documentation/vm/compound_pagemaps.rst
> new file mode 100644
> index 000000000000..6b1af50e8201
> --- /dev/null
> +++ b/Documentation/vm/compound_pagemaps.rst
> @@ -0,0 +1,170 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +.. _commpound_pagemaps:
> +
> +==================================
> +Free some vmemmap pages of HugeTLB
> +==================================
> +
> +The struct page structures (page structs) are used to describe a physical
> +page frame. By default, there is a one-to-one mapping from a page frame to
> +it's corresponding page struct.
> +
> +HugeTLB pages consist of multiple base page size pages and is supported by
> +many architectures. See hugetlbpage.rst in the Documentation directory for
> +more details. On the x86-64 architecture, HugeTLB pages of size 2MB and 1GB
> +are currently supported. Since the base page size on x86 is 4KB, a 2MB
> +HugeTLB page consists of 512 base pages and a 1GB HugeTLB page consists of
> +4096 base pages. For each base page, there is a corresponding page struct.
> +
> +Within the HugeTLB subsystem, only the first 4 page structs are used to
> +contain unique information about a HugeTLB page. __NR_USED_SUBPAGE provides
> +this upper limit. The only 'useful' information in the remaining page structs
> +is the compound_head field, and this field is the same for all tail pages.
> +
> +By removing redundant page structs for HugeTLB pages, memory can be returned
> +to the buddy allocator for other uses.
> +
> +Different architectures support different HugeTLB pages. For example, the
> +following table is the HugeTLB page size supported by x86 and arm64
> +architectures. Because arm64 supports 4k, 16k, and 64k base pages and
> +supports contiguous entries, so it supports many kinds of sizes of HugeTLB
> +page.
> +
> ++--------------+-----------+-----------------------------------------------+
> +| Architecture | Page Size | HugeTLB Page Size |
> ++--------------+-----------+-----------+-----------+-----------+-----------+
> +| x86-64 | 4KB | 2MB | 1GB | | |
> ++--------------+-----------+-----------+-----------+-----------+-----------+
> +| | 4KB | 64KB | 2MB | 32MB | 1GB |
> +| +-----------+-----------+-----------+-----------+-----------+
> +| arm64 | 16KB | 2MB | 32MB | 1GB | |
> +| +-----------+-----------+-----------+-----------+-----------+
> +| | 64KB | 2MB | 512MB | 16GB | |
> ++--------------+-----------+-----------+-----------+-----------+-----------+
> +
> +When the system boot up, every HugeTLB page has more than one struct page
> +structs which size is (unit: pages):
> +
> + struct_size = HugeTLB_Size / PAGE_SIZE * sizeof(struct page) / PAGE_SIZE
> +
> +Where HugeTLB_Size is the size of the HugeTLB page. We know that the size
> +of the HugeTLB page is always n times PAGE_SIZE. So we can get the following
> +relationship.
> +
> + HugeTLB_Size = n * PAGE_SIZE
> +
> +Then,
> +
> + struct_size = n * PAGE_SIZE / PAGE_SIZE * sizeof(struct page) / PAGE_SIZE
> + = n * sizeof(struct page) / PAGE_SIZE
> +
> +We can use huge mapping at the pud/pmd level for the HugeTLB page.
> +
> +For the HugeTLB page of the pmd level mapping, then
> +
> + struct_size = n * sizeof(struct page) / PAGE_SIZE
> + = PAGE_SIZE / sizeof(pte_t) * sizeof(struct page) / PAGE_SIZE
> + = sizeof(struct page) / sizeof(pte_t)
> + = 64 / 8
> + = 8 (pages)
> +
> +Where n is how many pte entries which one page can contains. So the value of
> +n is (PAGE_SIZE / sizeof(pte_t)).
> +
> +This optimization only supports 64-bit system, so the value of sizeof(pte_t)
> +is 8. And this optimization also applicable only when the size of struct page
> +is a power of two. In most cases, the size of struct page is 64 bytes (e.g.
> +x86-64 and arm64). So if we use pmd level mapping for a HugeTLB page, the
> +size of struct page structs of it is 8 page frames which size depends on the
> +size of the base page.
> +
> +For the HugeTLB page of the pud level mapping, then
> +
> + struct_size = PAGE_SIZE / sizeof(pmd_t) * struct_size(pmd)
> + = PAGE_SIZE / 8 * 8 (pages)
> + = PAGE_SIZE (pages)
> +
> +Where the struct_size(pmd) is the size of the struct page structs of a
> +HugeTLB page of the pmd level mapping.
> +
> +E.g.: A 2MB HugeTLB page on x86_64 consists in 8 page frames while 1GB
> +HugeTLB page consists in 4096.
> +
> +Next, we take the pmd level mapping of the HugeTLB page as an example to
> +show the internal implementation of this optimization. There are 8 pages
> +struct page structs associated with a HugeTLB page which is pmd mapped.
> +
> +Here is how things look before optimization.
> +
> + HugeTLB struct pages(8 pages) page frame(8 pages)
> + +-----------+ ---virt_to_page---> +-----------+ mapping to +-----------+
> + | | | 0 | -------------> | 0 |
> + | | +-----------+ +-----------+
> + | | | 1 | -------------> | 1 |
> + | | +-----------+ +-----------+
> + | | | 2 | -------------> | 2 |
> + | | +-----------+ +-----------+
> + | | | 3 | -------------> | 3 |
> + | | +-----------+ +-----------+
> + | | | 4 | -------------> | 4 |
> + | PMD | +-----------+ +-----------+
> + | level | | 5 | -------------> | 5 |
> + | mapping | +-----------+ +-----------+
> + | | | 6 | -------------> | 6 |
> + | | +-----------+ +-----------+
> + | | | 7 | -------------> | 7 |
> + | | +-----------+ +-----------+
> + | |
> + | |
> + | |
> + +-----------+
> +
> +The value of page->compound_head is the same for all tail pages. The first
> +page of page structs (page 0) associated with the HugeTLB page contains the 4
> +page structs necessary to describe the HugeTLB. The only use of the remaining
> +pages of page structs (page 1 to page 7) is to point to page->compound_head.
> +Therefore, we can remap pages 2 to 7 to page 1. Only 2 pages of page structs
> +will be used for each HugeTLB page. This will allow us to free the remaining
> +6 pages to the buddy allocator.
> +
> +Here is how things look after remapping.
> +
> + HugeTLB struct pages(8 pages) page frame(8 pages)
> + +-----------+ ---virt_to_page---> +-----------+ mapping to +-----------+
> + | | | 0 | -------------> | 0 |
> + | | +-----------+ +-----------+
> + | | | 1 | -------------> | 1 |
> + | | +-----------+ +-----------+
> + | | | 2 | ----------------^ ^ ^ ^ ^ ^
> + | | +-----------+ | | | | |
> + | | | 3 | ------------------+ | | | |
> + | | +-----------+ | | | |
> + | | | 4 | --------------------+ | | |
> + | PMD | +-----------+ | | |
> + | level | | 5 | ----------------------+ | |
> + | mapping | +-----------+ | |
> + | | | 6 | ------------------------+ |
> + | | +-----------+ |
> + | | | 7 | --------------------------+
> + | | +-----------+
> + | |
> + | |
> + | |
> + +-----------+
> +
> +When a HugeTLB is freed to the buddy system, we should allocate 6 pages for
> +vmemmap pages and restore the previous mapping relationship.
> +
> +For the HugeTLB page of the pud level mapping. It is similar to the former.
> +We also can use this approach to free (PAGE_SIZE - 2) vmemmap pages.
> +
> +Apart from the HugeTLB page of the pmd/pud level mapping, some architectures
> +(e.g. aarch64) provides a contiguous bit in the translation table entries
> +that hints to the MMU to indicate that it is one of a contiguous set of
> +entries that can be cached in a single TLB entry.
> +
> +The contiguous bit is used to increase the mapping size at the pmd and pte
> +(last) level. So this type of HugeTLB page can be optimized only when its
> +size of the struct page structs is greater than 2 pages.
> +
> diff --git a/Documentation/vm/index.rst b/Documentation/vm/index.rst
> index eff5fbd492d0..19f981a73a54 100644
> --- a/Documentation/vm/index.rst
> +++ b/Documentation/vm/index.rst
> @@ -31,6 +31,7 @@ descriptions of data structures and algorithms.
> active_mm
> arch_pgtable_helpers
> balance
> + commpound_pagemaps
> cleancache
> free_page_reporting
> frontswap
> diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
> index c540c21e26f5..69d1f0a90e02 100644
> --- a/mm/hugetlb_vmemmap.c
> +++ b/mm/hugetlb_vmemmap.c
> @@ -6,167 +6,7 @@
> *
> * Author: Muchun Song <songmuchun@bytedance.com>
> *
> - * The struct page structures (page structs) are used to describe a physical
> - * page frame. By default, there is a one-to-one mapping from a page frame to
> - * it's corresponding page struct.
> - *
> - * HugeTLB pages consist of multiple base page size pages and is supported by
> - * many architectures. See hugetlbpage.rst in the Documentation directory for
> - * more details. On the x86-64 architecture, HugeTLB pages of size 2MB and 1GB
> - * are currently supported. Since the base page size on x86 is 4KB, a 2MB
> - * HugeTLB page consists of 512 base pages and a 1GB HugeTLB page consists of
> - * 4096 base pages. For each base page, there is a corresponding page struct.
> - *
> - * Within the HugeTLB subsystem, only the first 4 page structs are used to
> - * contain unique information about a HugeTLB page. __NR_USED_SUBPAGE provides
> - * this upper limit. The only 'useful' information in the remaining page structs
> - * is the compound_head field, and this field is the same for all tail pages.
> - *
> - * By removing redundant page structs for HugeTLB pages, memory can be returned
> - * to the buddy allocator for other uses.
> - *
> - * Different architectures support different HugeTLB pages. For example, the
> - * following table is the HugeTLB page size supported by x86 and arm64
> - * architectures. Because arm64 supports 4k, 16k, and 64k base pages and
> - * supports contiguous entries, so it supports many kinds of sizes of HugeTLB
> - * page.
> - *
> - * +--------------+-----------+-----------------------------------------------+
> - * | Architecture | Page Size | HugeTLB Page Size |
> - * +--------------+-----------+-----------+-----------+-----------+-----------+
> - * | x86-64 | 4KB | 2MB | 1GB | | |
> - * +--------------+-----------+-----------+-----------+-----------+-----------+
> - * | | 4KB | 64KB | 2MB | 32MB | 1GB |
> - * | +-----------+-----------+-----------+-----------+-----------+
> - * | arm64 | 16KB | 2MB | 32MB | 1GB | |
> - * | +-----------+-----------+-----------+-----------+-----------+
> - * | | 64KB | 2MB | 512MB | 16GB | |
> - * +--------------+-----------+-----------+-----------+-----------+-----------+
> - *
> - * When the system boot up, every HugeTLB page has more than one struct page
> - * structs which size is (unit: pages):
> - *
> - * struct_size = HugeTLB_Size / PAGE_SIZE * sizeof(struct page) / PAGE_SIZE
> - *
> - * Where HugeTLB_Size is the size of the HugeTLB page. We know that the size
> - * of the HugeTLB page is always n times PAGE_SIZE. So we can get the following
> - * relationship.
> - *
> - * HugeTLB_Size = n * PAGE_SIZE
> - *
> - * Then,
> - *
> - * struct_size = n * PAGE_SIZE / PAGE_SIZE * sizeof(struct page) / PAGE_SIZE
> - * = n * sizeof(struct page) / PAGE_SIZE
> - *
> - * We can use huge mapping at the pud/pmd level for the HugeTLB page.
> - *
> - * For the HugeTLB page of the pmd level mapping, then
> - *
> - * struct_size = n * sizeof(struct page) / PAGE_SIZE
> - * = PAGE_SIZE / sizeof(pte_t) * sizeof(struct page) / PAGE_SIZE
> - * = sizeof(struct page) / sizeof(pte_t)
> - * = 64 / 8
> - * = 8 (pages)
> - *
> - * Where n is how many pte entries which one page can contains. So the value of
> - * n is (PAGE_SIZE / sizeof(pte_t)).
> - *
> - * This optimization only supports 64-bit system, so the value of sizeof(pte_t)
> - * is 8. And this optimization also applicable only when the size of struct page
> - * is a power of two. In most cases, the size of struct page is 64 bytes (e.g.
> - * x86-64 and arm64). So if we use pmd level mapping for a HugeTLB page, the
> - * size of struct page structs of it is 8 page frames which size depends on the
> - * size of the base page.
> - *
> - * For the HugeTLB page of the pud level mapping, then
> - *
> - * struct_size = PAGE_SIZE / sizeof(pmd_t) * struct_size(pmd)
> - * = PAGE_SIZE / 8 * 8 (pages)
> - * = PAGE_SIZE (pages)
> - *
> - * Where the struct_size(pmd) is the size of the struct page structs of a
> - * HugeTLB page of the pmd level mapping.
> - *
> - * E.g.: A 2MB HugeTLB page on x86_64 consists in 8 page frames while 1GB
> - * HugeTLB page consists in 4096.
> - *
> - * Next, we take the pmd level mapping of the HugeTLB page as an example to
> - * show the internal implementation of this optimization. There are 8 pages
> - * struct page structs associated with a HugeTLB page which is pmd mapped.
> - *
> - * Here is how things look before optimization.
> - *
> - * HugeTLB struct pages(8 pages) page frame(8 pages)
> - * +-----------+ ---virt_to_page---> +-----------+ mapping to +-----------+
> - * | | | 0 | -------------> | 0 |
> - * | | +-----------+ +-----------+
> - * | | | 1 | -------------> | 1 |
> - * | | +-----------+ +-----------+
> - * | | | 2 | -------------> | 2 |
> - * | | +-----------+ +-----------+
> - * | | | 3 | -------------> | 3 |
> - * | | +-----------+ +-----------+
> - * | | | 4 | -------------> | 4 |
> - * | PMD | +-----------+ +-----------+
> - * | level | | 5 | -------------> | 5 |
> - * | mapping | +-----------+ +-----------+
> - * | | | 6 | -------------> | 6 |
> - * | | +-----------+ +-----------+
> - * | | | 7 | -------------> | 7 |
> - * | | +-----------+ +-----------+
> - * | |
> - * | |
> - * | |
> - * +-----------+
> - *
> - * The value of page->compound_head is the same for all tail pages. The first
> - * page of page structs (page 0) associated with the HugeTLB page contains the 4
> - * page structs necessary to describe the HugeTLB. The only use of the remaining
> - * pages of page structs (page 1 to page 7) is to point to page->compound_head.
> - * Therefore, we can remap pages 2 to 7 to page 1. Only 2 pages of page structs
> - * will be used for each HugeTLB page. This will allow us to free the remaining
> - * 6 pages to the buddy allocator.
> - *
> - * Here is how things look after remapping.
> - *
> - * HugeTLB struct pages(8 pages) page frame(8 pages)
> - * +-----------+ ---virt_to_page---> +-----------+ mapping to +-----------+
> - * | | | 0 | -------------> | 0 |
> - * | | +-----------+ +-----------+
> - * | | | 1 | -------------> | 1 |
> - * | | +-----------+ +-----------+
> - * | | | 2 | ----------------^ ^ ^ ^ ^ ^
> - * | | +-----------+ | | | | |
> - * | | | 3 | ------------------+ | | | |
> - * | | +-----------+ | | | |
> - * | | | 4 | --------------------+ | | |
> - * | PMD | +-----------+ | | |
> - * | level | | 5 | ----------------------+ | |
> - * | mapping | +-----------+ | |
> - * | | | 6 | ------------------------+ |
> - * | | +-----------+ |
> - * | | | 7 | --------------------------+
> - * | | +-----------+
> - * | |
> - * | |
> - * | |
> - * +-----------+
> - *
> - * When a HugeTLB is freed to the buddy system, we should allocate 6 pages for
> - * vmemmap pages and restore the previous mapping relationship.
> - *
> - * For the HugeTLB page of the pud level mapping. It is similar to the former.
> - * We also can use this approach to free (PAGE_SIZE - 2) vmemmap pages.
> - *
> - * Apart from the HugeTLB page of the pmd/pud level mapping, some architectures
> - * (e.g. aarch64) provides a contiguous bit in the translation table entries
> - * that hints to the MMU to indicate that it is one of a contiguous set of
> - * entries that can be cached in a single TLB entry.
> - *
> - * The contiguous bit is used to increase the mapping size at the pmd and pte
> - * (last) level. So this type of HugeTLB page can be optimized only when its
> - * size of the struct page structs is greater than 2 pages.
> + * See Documentation/vm/compound_pagemaps.rst
> */
> #define pr_fmt(fmt) "HugeTLB: " fmt
>
> --
> 2.17.1
>
next prev parent reply other threads:[~2021-06-21 13:12 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-17 18:44 [PATCH v2 00/14] mm, sparse-vmemmap: Introduce compound pagemaps Joao Martins
2021-06-17 18:44 ` [PATCH v2 01/14] memory-failure: fetch compound_head after pgmap_pfn_valid() Joao Martins
2021-06-20 23:56 ` HORIGUCHI NAOYA(堀口 直也)
2021-06-21 13:50 ` Joao Martins
2021-06-17 18:44 ` [PATCH v2 02/14] mm/page_alloc: split prep_compound_page into head and tail subparts Joao Martins
2021-07-13 0:02 ` Mike Kravetz
2021-07-13 1:11 ` Joao Martins
2021-06-17 18:44 ` [PATCH v2 03/14] mm/page_alloc: refactor memmap_init_zone_device() page init Joao Martins
2021-06-17 18:44 ` [PATCH v2 04/14] mm/memremap: add ZONE_DEVICE support for compound pages Joao Martins
2021-06-17 18:44 ` [PATCH v2 05/14] mm/sparse-vmemmap: add a pgmap argument to section activation Joao Martins
2021-06-17 18:44 ` [PATCH v2 06/14] mm/sparse-vmemmap: refactor core of vmemmap_populate_basepages() to helper Joao Martins
2021-06-17 18:45 ` [PATCH v2 07/14] mm/hugetlb_vmemmap: move comment block to Documentation/vm Joao Martins
2021-06-21 13:12 ` Muchun Song [this message]
2021-06-21 13:42 ` [External] " Joao Martins
2021-07-13 0:14 ` Mike Kravetz
2021-07-13 1:11 ` Joao Martins
2021-06-17 18:45 ` [PATCH v2 08/14] mm/sparse-vmemmap: populate compound pagemaps Joao Martins
2021-06-17 18:45 ` [PATCH v2 09/14] mm/page_alloc: reuse tail struct pages for " Joao Martins
2021-06-17 18:45 ` [PATCH v2 10/14] device-dax: use ALIGN() for determining pgoff Joao Martins
2021-06-17 18:45 ` [PATCH v2 11/14] device-dax: ensure dev_dax->pgmap is valid for dynamic devices Joao Martins
2021-06-17 18:45 ` [PATCH v2 12/14] device-dax: compound pagemap support Joao Martins
2021-06-17 18:45 ` [PATCH v2 13/14] mm/gup: grab head page refcount once for group of subpages Joao Martins
2021-06-17 18:45 ` [PATCH v2 14/14] mm/sparse-vmemmap: improve memory savings for compound pud geometry Joao Martins
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAMZfGtXSJE2ZsSOBW7Ef0VtP=+Q=cULSw9urqZGSG_WbGTiaSA@mail.gmail.com' \
--to=songmuchun@bytedance.com \
--cc=akpm@linux-foundation.org \
--cc=corbet@lwn.net \
--cc=dan.j.williams@intel.com \
--cc=dave.jiang@intel.com \
--cc=jane.chu@oracle.com \
--cc=jgg@ziepe.ca \
--cc=jhubbard@nvidia.com \
--cc=joao.m.martins@oracle.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mike.kravetz@oracle.com \
--cc=naoya.horiguchi@nec.com \
--cc=nvdimm@lists.linux.dev \
--cc=vishal.l.verma@intel.com \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).