Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: "Lorenzo Stoakes (ARM)" <ljs@kernel.org>
To: Kiryl Shutsemau <kirill@shutemov.name>
Cc: akpm@linux-foundation.org, david@kernel.org,
	nico.pache@linux.dev,  baolin.wang@linux.alibaba.com,
	baohua@kernel.org, dev.jain@arm.com, hughd@google.com,
	 lance.yang@linux.dev, liam@infradead.org, mhocko@suse.com,
	rppt@kernel.org,  ryan.roberts@arm.com, shuah@kernel.org,
	surenb@google.com, usama.arif@linux.dev,  vbabka@kernel.org,
	ziy@nvidia.com, usama.anjum@arm.com, agordeev@linux.ibm.com,
	 linux-mm@kvack.org, linux-kselftest@vger.kernel.org,
	linux-kernel@vger.kernel.org,  kas@kernel.org
Subject: Re: [PATCH v4 10/19] selftests/mm: add khugepaged completion barrier helper
Date: Tue, 18 Aug 2026 11:34:27 +0100	[thread overview]
Message-ID: <aoQ0VzEcH-SydZXs@lucifer> (raw)
In-Reply-To: <20260815015901.1236937-11-kirill@shutemov.name>

On Sat, Aug 15, 2026 at 02:58:52AM +0100, Kiryl Shutsemau wrote:
> From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
>
> Race and functional tests need to drive khugepaged in step: set up a
> layout, let one full scan pass over it, check the result.  The khugepaged
> selftest already waits for full_scans to advance by two, but only makes
> progress if scan_sleep_millisecs happens to be short.
>
> Lift it into khugepaged_full_pass() and drive it through sysfs: any store
> to scan_sleep_millisecs wakes the daemon, so the barrier completes whatever
> the scan cadence.  A store can be lost when the daemon is between scans, so
> it keeps storing until the pass lands; a store to an awake daemon costs
> nothing and queues no extra pass.
>
> One wake completes one pass only if the whole mm list fits in a scan batch,
> so callers need a large pages_to_scan.
>
> Settings pushes must not start passes either.  A store to either sleep knob
> wakes the daemon, so thp_write_settings() now writes a khugepaged knob only
> when its value changes.  The other knobs do not wake, but writing them
> uniformly costs nothing.  thp_update_num() is exported for tests that want
> the same restraint.
>
> Assisted-by: Claude-Code:claude-opus-5
> Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
> Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
> ---
>  .../testing/selftests/mm/hugepage_settings.c  | 74 ++++++++++++++++---
>  .../testing/selftests/mm/hugepage_settings.h  |  3 +
>  2 files changed, 68 insertions(+), 9 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/testing/selftests/mm/hugepage_settings.c
> index d7917dce3aba..992efee17b71 100644
> --- a/tools/testing/selftests/mm/hugepage_settings.c
> +++ b/tools/testing/selftests/mm/hugepage_settings.c
> @@ -183,6 +183,19 @@ void thp_read_settings(struct thp_settings *settings)
>  	}
>  }
>
> +/*
> + * Write only on change: a store to either sleep knob wakes khugepaged --
> + * __sleep_millisecs_store() clears khugepaged_sleep_expire and wakes the
> + * queue -- and settings pushes/pops must not start scan passes nobody
> + * asked for; khugepaged_full_pass() is the only sanctioned wake.  The
> + * other knobs do not wake, but writing them the same way costs nothing.
> + */

This seems quite schloppy and way too much information in a single dense
comment.

You/claude don't need to give your life story in every comment :)

Smaller, clearer, human-written please.

	/*

> +void thp_update_num(const char *name, unsigned long num)
> +{
> +	if (thp_read_num(name) != num)
> +		thp_write_num(name, num);
> +}
> +
>  void thp_write_settings(struct thp_settings *settings)
>  {
>  	struct khugepaged_settings *khugepaged = &settings->khugepaged;
> @@ -198,15 +211,15 @@ void thp_write_settings(struct thp_settings *settings)
>  			shmem_enabled_strings[settings->shmem_enabled]);
>  	thp_write_num("use_zero_page", settings->use_zero_page);
>
> -	thp_write_num("khugepaged/defrag", khugepaged->defrag);
> -	thp_write_num("khugepaged/alloc_sleep_millisecs",
> -			khugepaged->alloc_sleep_millisecs);
> -	thp_write_num("khugepaged/scan_sleep_millisecs",
> -			khugepaged->scan_sleep_millisecs);
> -	thp_write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
> -	thp_write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
> -	thp_write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared);
> -	thp_write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan);
> +	thp_update_num("khugepaged/defrag", khugepaged->defrag);
> +	thp_update_num("khugepaged/alloc_sleep_millisecs",
> +		       khugepaged->alloc_sleep_millisecs);
> +	thp_update_num("khugepaged/scan_sleep_millisecs",
> +		       khugepaged->scan_sleep_millisecs);
> +	thp_update_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
> +	thp_update_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
> +	thp_update_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared);
> +	thp_update_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan);
>
>  	if (dev_queue_read_ahead_path[0])
>  		write_num(dev_queue_read_ahead_path, settings->read_ahead_kb);
> @@ -230,6 +243,49 @@ void thp_write_settings(struct thp_settings *settings)
>  	}
>  }
>
> +/*
> + * Completion barrier for khugepaged: wait until a full scan pass that
> + * started after this call has finished. full_scans must advance by two;
> + * a +1 step may complete a pass that examined this mm before the
> + * caller's setup was in place.
> + *
> + * Any store to scan_sleep_millisecs wakes the daemon, so the barrier works
> + * whatever the configured scan cadence -- but a store can be lost.
> + * __sleep_millisecs_store() clears khugepaged_sleep_expire and wakes the
> + * queue; if the daemon is between scans rather than sleeping, it sets
> + * khugepaged_sleep_expire itself on the way into khugepaged_wait_work() and
> + * then sleeps for the full interval, having never seen the store.  So keep
> + * storing until the pass lands; a store while the daemon is awake costs
> + * nothing and does not queue an extra pass.
> + *
> + * One wake completes one full pass only if the whole mm list fits in
> + * one scan batch, so callers must pair this with a large
> + * pages_to_scan.
> + */

Same comment about the comment. This is dense and schloppy. Clarity and
terseness please.

> +bool khugepaged_full_pass(unsigned int timeout_s)
> +{
> +	unsigned long deadline_ms = timeout_s * 1000UL;
> +	unsigned long sleep_ms =
> +		thp_read_num("khugepaged/scan_sleep_millisecs");
> +	unsigned long elapsed_ms = 0;
> +	int pass;
> +
> +	for (pass = 0; pass < 2; pass++) {
> +		unsigned long target =
> +			thp_read_num("khugepaged/full_scans") + 1;
> +
> +		while (thp_read_num("khugepaged/full_scans") < target) {
> +			if (elapsed_ms >= deadline_ms)
> +				return false;
> +			thp_write_num("khugepaged/scan_sleep_millisecs",
> +				      sleep_ms);
> +			usleep(10 * 1000);
> +			elapsed_ms += 10;
> +		}
> +	}
> +	return true;
> +}
> +
>  struct thp_settings *thp_current_settings(void)
>  {
>  	if (!settings_index) {
> diff --git a/tools/testing/selftests/mm/hugepage_settings.h b/tools/testing/selftests/mm/hugepage_settings.h
> index 726c73c43c05..ba7d38370d43 100644
> --- a/tools/testing/selftests/mm/hugepage_settings.h
> +++ b/tools/testing/selftests/mm/hugepage_settings.h
> @@ -70,6 +70,7 @@ int thp_read_string(const char *name, const char * const strings[]);
>  void thp_write_string(const char *name, const char *val);
>  unsigned long thp_read_num(const char *name);
>  void thp_write_num(const char *name, unsigned long num);
> +void thp_update_num(const char *name, unsigned long num);
>
>  void thp_write_settings(struct thp_settings *settings);
>  void thp_read_settings(struct thp_settings *settings);
> @@ -83,6 +84,8 @@ static inline void thp_save_settings(void)
>  	hugepage_save_settings(/* thp = */ true, /* hugetlb = */ false);
>  }
>
> +bool khugepaged_full_pass(unsigned int timeout_s);
> +
>  void thp_set_read_ahead_path(char *path);
>  unsigned long thp_supported_orders(void);
>  unsigned long thp_shmem_supported_orders(void);
> --
> 2.54.0
>

--
Cheers, Lorenzo


  reply	other threads:[~2026-08-18 10:34 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-15  1:58 [PATCH v4 00/19] selftests/mm: improve khugepaged coverage Kiryl Shutsemau
2026-08-15  1:58 ` [PATCH v4 01/19] selftests/mm: raise the khugepaged test-case cap Kiryl Shutsemau
2026-08-18  9:11   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 02/19] selftests/mm: skip collapse_compound_extreme() where the PMD is too large Kiryl Shutsemau
2026-08-18  9:22   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 03/19] selftests/mm: scale khugepaged's collapse wait with the PMD size Kiryl Shutsemau
2026-08-18 10:04   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 04/19] selftests/mm: skip khugepaged page cache cases without a PMD folio Kiryl Shutsemau
2026-08-18 10:07   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 05/19] selftests/mm: make the swap cases' swapout reliable Kiryl Shutsemau
2026-08-18 10:11   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 06/19] selftests/mm: stop khugepaged during the MADV_COLLAPSE cases Kiryl Shutsemau
2026-08-18 10:12   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 07/19] selftests/mm: move is_backed_by_folio() into vm_util Kiryl Shutsemau
2026-08-18 10:14   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 08/19] selftests/mm: add folio-order check for address ranges Kiryl Shutsemau
2026-08-18 10:25   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 09/19] selftests/mm: add folio-order detection self-check Kiryl Shutsemau
2026-08-18 10:30   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 10/19] selftests/mm: add khugepaged completion barrier helper Kiryl Shutsemau
2026-08-18 10:34   ` Lorenzo Stoakes (ARM) [this message]
2026-08-15  1:58 ` [PATCH v4 11/19] selftests/mm: add order-parameterized khugepaged collapse cases Kiryl Shutsemau
2026-08-18 10:38   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 12/19] selftests/mm: parameterize the mixed-source collapse case by source order Kiryl Shutsemau
2026-08-18 10:47   ` Lorenzo Stoakes (ARM)
2026-08-15  1:58 ` [PATCH v4 13/19] selftests/mm: cover a shared-source collapse write race Kiryl Shutsemau
2026-08-15  1:58 ` [PATCH v4 14/19] selftests/mm: run every supported collapse order by default Kiryl Shutsemau
2026-08-15  1:58 ` [PATCH v4 15/19] selftests/mm: check that one khugepaged pass collapses one window Kiryl Shutsemau
2026-08-15  1:58 ` [PATCH v4 16/19] selftests/mm: add khugepaged race harness Kiryl Shutsemau
2026-08-15  1:58 ` [PATCH v4 17/19] selftests/mm: race collapse of windows with holes Kiryl Shutsemau
2026-08-15  1:59 ` [PATCH v4 18/19] selftests/mm: add memory-pressure threads to the khugepaged race harness Kiryl Shutsemau
2026-08-15  1:59 ` [PATCH v4 19/19] selftests/mm: zap whole PTE tables in " Kiryl Shutsemau

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=aoQ0VzEcH-SydZXs@lucifer \
    --to=ljs@kernel.org \
    --cc=agordeev@linux.ibm.com \
    --cc=akpm@linux-foundation.org \
    --cc=baohua@kernel.org \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=david@kernel.org \
    --cc=dev.jain@arm.com \
    --cc=hughd@google.com \
    --cc=kas@kernel.org \
    --cc=kirill@shutemov.name \
    --cc=lance.yang@linux.dev \
    --cc=liam@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@suse.com \
    --cc=nico.pache@linux.dev \
    --cc=rppt@kernel.org \
    --cc=ryan.roberts@arm.com \
    --cc=shuah@kernel.org \
    --cc=surenb@google.com \
    --cc=usama.anjum@arm.com \
    --cc=usama.arif@linux.dev \
    --cc=vbabka@kernel.org \
    --cc=ziy@nvidia.com \
    /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