All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
	"David Hildenbrand" <david@kernel.org>
Cc: "Paul E. McKenney" <paulmck@kernel.org>,
	"Steven Rostedt" <rostedt@goodmis.org>,
	"Masami Hiramatsu" <mhiramat@kernel.org>,
	"Dennis Zhou" <dennis@kernel.org>, "Tejun Heo" <tj@kernel.org>,
	"Christoph Lameter" <cl@gentwo.org>,
	"Martin Liu" <liumartin@google.com>,
	"David Rientjes" <rientjes@google.com>,
	christian.koenig@amd.com, "Shakeel Butt" <shakeel.butt@linux.dev>,
	"SeongJae Park" <sj@kernel.org>, "Michal Hocko" <mhocko@suse.com>,
	"Johannes Weiner" <hannes@cmpxchg.org>,
	"Sweet Tea Dorminy" <sweettea-kernel@dorminy.me>,
	"Lorenzo Stoakes" <ljs@kernel.org>,
	"Liam R. Howlett" <liam@infradead.org>,
	"Mike Rapoport" <rppt@kernel.org>,
	"Suren Baghdasaryan" <surenb@google.com>,
	"Vlastimil Babka" <vbabka@kernel.org>,
	"Christian Brauner" <brauner@kernel.org>,
	"Wei Yang" <richard.weiyang@gmail.com>,
	"Miaohe Lin" <linmiaohe@huawei.com>,
	"Al Viro" <viro@zeniv.linux.org.uk>,
	"Yu Zhao" <yuzhao@google.com>,
	"Roman Gushchin" <roman.gushchin@linux.dev>,
	"Mateusz Guzik" <mjguzik@gmail.com>,
	"Matthew Wilcox" <willy@infradead.org>,
	"Baolin Wang" <baolin.wang@linux.alibaba.com>,
	"Aboorva Devarajan" <aboorvad@linux.ibm.com>,
	"David Carlier" <devnexen@gmail.com>,
	"Josh Law" <objecting@objecting.org>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	linux-mm@kvack.org, "Jonathan Corbet" <corbet@lwn.net>,
	"Shuah Khan" <skhan@linuxfoundation.org>,
	"Randy Dunlap" <rdunlap@infradead.org>,
	"Kees Cook" <kees@kernel.org>, "Ingo Molnar" <mingo@redhat.com>,
	"Peter Zijlstra" <peterz@infradead.org>,
	"Juri Lelli" <juri.lelli@redhat.com>,
	"Vincent Guittot" <vincent.guittot@linaro.org>,
	"Dietmar Eggemann" <dietmar.eggemann@arm.com>,
	"Ben Segall" <bsegall@google.com>, "Mel Gorman" <mgorman@suse.de>,
	"Valentin Schneider" <vschneid@redhat.com>,
	"K Prateek Nayak" <kprateek.nayak@amd.com>,
	linux-trace-kernel@vger.kernel.org, "Jan Kara" <jack@suse.cz>,
	"Oleg Nesterov" <oleg@redhat.com>
Subject: Re: [RFC PATCH v23 02/10] lib: test hierarchical per-cpu counters
Date: Tue, 03 Nov 2026 19:07:49 +0000	[thread overview]
Message-ID: <sashiko-outbox-195884@kernel.org> (raw)
In-Reply-To: <20261102190708.1287100-3-mathieu.desnoyers@efficios.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] lib/tests: unlocked cpu_online_mask read passed to work_on_cpu()
- [Medium] lib/tests: missing release/acquire ordering on sh.started in contention test
- [Low] lib/tests: unlocked num_online_cpus() check in do_hpcc_test_saturated_compare()
--

commit 48b3ce088047ee1ccff5c20155903c1a143e78df
Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>

lib: test hierarchical per-cpu counters

Introduce KUnit tests for hierarchical per-CPU counters covering
single-threaded updates, concurrent multi-threaded updates, contended
carries, and saturated counter comparisons.

Link: https://lkml.kernel.org/r/20260227153730.1556542-3-mathieu.desnoyers@efficios.com

> diff --git a/lib/tests/percpu_counter_tree_kunit.c b/lib/tests/percpu_counter_tree_kunit.c
> new file mode 100644
> index 0000000000000..58b2e488e3c6b
> --- /dev/null
> +++ b/lib/tests/percpu_counter_tree_kunit.c

[ ... ]

> +static void do_hpcc_test_single_thread(struct kunit *test, int _cpu0, int _cpu1,
> +				       enum up_test_inc_type type)
> +{
> +	unsigned long batch_size_order = 5;
> +	int cpu0 = _cpu0;
> +	int cpu1 = _cpu1;
> +	unsigned long deadline = jiffies + SINGLE_THREAD_MAX_SECONDS * HZ;
> +	int ret, i;
> +
> +	ret = init_counters(1UL << batch_size_order);
> +	KUNIT_EXPECT_EQ(test, ret, 0);
> +	if (ret)
> +		return;
> +	cpus_read_lock();
> +	for (i = 0; i < 10000 && time_before(jiffies, deadline); i++) {
> +		struct single_thread_update u0 = { .counter_index = 0 };
> +		struct single_thread_update u1 = { .counter_index = 1 };
> +		long increment;
> +
> +		switch (type) {
> +		case INC_ONE:
> +			increment = 1;
> +			break;
> +		case INC_MINUS_ONE:
> +			increment = -1;
> +			break;
> +		case INC_RANDOM:
> +			increment = (long)get_random_long() % 50000;
> +			break;
> +		default:
> +			WARN_ON_ONCE(1);
> +			increment = 0;
> +		}
> +		if (_cpu0 < 0)
> +			cpu0 = cpumask_any_distribute(cpu_online_mask);
> +		if (_cpu1 < 0)
> +			cpu1 = cpumask_any_distribute(cpu_online_mask);
> +		u0.increment = increment;
> +		u1.increment = increment;
> +		work_on_cpu(cpu0, single_thread_update_fn, &u0);
> +		work_on_cpu(cpu1, single_thread_update_fn, &u1);
> +		check_counters(test);
> +	}
> +	cpus_read_unlock();
> +	fini_counters();
> +}
> +
> +static void hpcc_test_single_thread_first(struct kunit *test)
> +{
> +	int cpu = cpumask_first(cpu_online_mask);
> +
> +	do_hpcc_test_single_thread(test, cpu, cpu, INC_ONE);
> +	do_hpcc_test_single_thread(test, cpu, cpu, INC_MINUS_ONE);
> +	do_hpcc_test_single_thread(test, cpu, cpu, INC_RANDOM);
> +}
> +
> +static void hpcc_test_single_thread_first_random(struct kunit *test)
> +{
> +	int cpu = cpumask_first(cpu_online_mask);
> +
> +	do_hpcc_test_single_thread(test, cpu, -1, INC_ONE);
> +	do_hpcc_test_single_thread(test, cpu, -1, INC_MINUS_ONE);
> +	do_hpcc_test_single_thread(test, cpu, -1, INC_RANDOM);
> +}

[Severity: Medium]
Can cpu go offline before or between the calls to
do_hpcc_test_single_thread()?

Both hpcc_test_single_thread_first() and
hpcc_test_single_thread_first_random() sample cpumask_first(cpu_online_mask)
without holding cpus_read_lock(), and then pass that cpu across three
separate calls to do_hpcc_test_single_thread(), each of which acquires and
releases cpus_read_lock() on its own.

Because _cpu0 >= 0 (and _cpu1 >= 0 in hpcc_test_single_thread_first()),
do_hpcc_test_single_thread() never re-reads or validates cpu0 or cpu1 under
cpus_read_lock() before passing them to work_on_cpu(), which requires the
caller to ensure the target CPU cannot go offline.

If CPU hot-unplug runs concurrently under CONFIG_HOTPLUG_CPU=y, could
work_on_cpu() be called on an offline CPU?

[ ... ]

> +static int contention_worker_fn(void *data)
> +{
> +	struct contention_data *cd = data;
> +	struct contention_shared *sh = cd->sh;
> +	int round;
> +
> +	wait_event(contention_wq, READ_ONCE(sh->started));
> +	for (round = 1; round <= CONTENTION_NR_ROUNDS; round++) {
> +		if (cd->coordinator) {
> +			atomic_set_release(&sh->round, round);
> +			contention_add(cd);
> +			while (atomic_read_acquire(&sh->nr_done) < round * (sh->nr_workers - 1))
> +				cond_resched();
> +#ifdef CONFIG_SMP
> +			if (percpu_counter_tree_check_residuals(&counter[0]))
> +				sh->nr_errors++;
> +#endif
> +		} else {
> +			while (atomic_read_acquire(&sh->round) < round)
> +				cond_resched();
> +			contention_add(cd);
> +			/* Order the additions before the coordinator check. */
> +			atomic_inc_return_release(&sh->nr_done);
> +		}
> +	}
> +	complete_work();
> +	return 0;
> +}
> +
> +static void do_hpcc_test_contended_carries(struct kunit *test, unsigned long batch_size)
> +{

[ ... ]

> +	for_each_cpu(cpu, cpus) {
> +		cd[cpu].sh = &sh;
> +		cd[cpu].coordinator = first;
> +		cd[cpu].seed = get_random_u32() | 1;
> +		task[cpu] = kthread_create_on_cpu(contention_worker_fn, &cd[cpu], cpu,
> +						  "kunit_hpcc_contention/%u");
> +		KUNIT_EXPECT_FALSE(test, IS_ERR(task[cpu]));
> +		if (IS_ERR(task[cpu]))
> +			break;
> +		atomic_inc(&kernel_threads_to_run);
> +		get_task_struct(task[cpu]);
> +		wake_up_process(task[cpu]);
> +		sh.nr_workers++;
> +		first = false;
> +	}
> +	/* Start the workers once their number is known. */
> +	WRITE_ONCE(sh.started, true);
> +	wake_up_all(&contention_wq);

[Severity: Medium]
On weakly-ordered architectures, can the coordinator thread in
contention_worker_fn() observe sh->started == true before seeing all
increments to sh.nr_workers?

In do_hpcc_test_contended_carries(), each worker kthread (starting with the
coordinator on the first iteration) is woken via wake_up_process(task[cpu])
inside the loop while sh.nr_workers++ is still being incremented on
subsequent iterations, and completion is published with
WRITE_ONCE(sh.started, true).

In contention_worker_fn(), if the already-running coordinator hits the
wait_event(contention_wq, READ_ONCE(sh->started)) fastpath before
wake_up_all() is called, it does not go through the waitqueue spinlock and
there is no release/acquire pairing ordering the updates to sh.nr_workers
before the coordinator reads sh->nr_workers in:

	while (atomic_read_acquire(&sh->nr_done) < round * (sh->nr_workers - 1))

Could this cause the coordinator to wait for fewer workers than were created
and call percpu_counter_tree_check_residuals(&counter[0]) while other workers
are still updating counter[0]? Should sh.started use smp_store_release() and
smp_load_acquire()?

[ ... ]

> +static void do_hpcc_test_saturated_compare(struct kunit *test, unsigned long batch_size,
> +					   long inc)
> +{

[ ... ]

> +	cpus_read_lock();
> +	for_each_online_cpu(cpu) {
> +		work_on_cpu(cpu, saturate_worker_fn, &sd);
> +		KUNIT_EXPECT_FALSE(test, sd.overrun);
> +		if (sd.overrun)
> +			break;
> +	}
> +	cpus_read_unlock();
> +
> +	precise = percpu_counter_tree_precise_sum(c);
> +	approx = percpu_counter_tree_approximate_sum(c);
> +	kunit_info(test, "batch_size=%lu inc=%ld precise=%ld approx=%ld accuracy=%lu\n",
> +		   batch_size, inc, precise, approx, accuracy);
> +
> +	check_residuals(test, c);
> +	check_residuals(test, &probe);
> +
> +	/* Accuracy contract. */
> +	KUNIT_EXPECT_GE(test, approx, precise - (long)accuracy);
> +	KUNIT_EXPECT_LE(test, approx, precise + (long)accuracy);
> +	/* Saturating every possible CPU reaches the accuracy exactly. */
> +	if (num_online_cpus() == nr_cpu_ids)
> +		KUNIT_EXPECT_EQ(test, (precise - approx) * inc, (long)accuracy);

[Severity: Low]
In do_hpcc_test_saturated_compare(), what happens if a CPU is offline during
the for_each_online_cpu() saturation loop and comes online after
cpus_read_unlock()?

Because num_online_cpus() == nr_cpu_ids is checked after cpus_read_unlock()
is dropped, a CPU brought online in that window would make
num_online_cpus() == nr_cpu_ids true even though saturate_worker_fn() did not
run on it, causing the KUNIT_EXPECT_EQ(test, (precise - approx) * inc,
(long)accuracy) assertion to fail spuriously.

Should num_online_cpus() == nr_cpu_ids be recorded while cpus_read_lock() is
still held?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102190708.1287100-1-mathieu.desnoyers@efficios.com?part=2

  reply	other threads:[~2026-11-03 19:07 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02 19:06 [RFC PATCH v23 00/10] Hierarchical Percpu Counters for RSS Mathieu Desnoyers
2026-11-02 19:06 ` [RFC PATCH v23 01/10] lib: introduce hierarchical per-cpu counters Mathieu Desnoyers
2026-11-02 19:07 ` [RFC PATCH v23 02/10] lib: test " Mathieu Desnoyers
2026-11-03 19:07   ` sashiko-bot [this message]
2026-11-02 19:07 ` [RFC PATCH v23 03/10] mm: use hierarchical per-cpu counters for the RSS counters Mathieu Desnoyers
2026-11-02 19:07 ` [RFC PATCH v23 04/10] tools/testing/hpcc: add userspace test of hierarchical per-CPU counters Mathieu Desnoyers
2026-11-03 19:07   ` sashiko-bot
2026-11-02 19:07 ` [RFC PATCH v23 05/10] mm: report the approximate RSS in the rss_stat tracepoint Mathieu Desnoyers
2026-11-02 19:07 ` [RFC PATCH v23 06/10] lib: percpu_counter_tree: add lazy tree activation Mathieu Desnoyers
2026-11-02 19:07 ` [RFC PATCH v23 07/10] mm: keep the RSS counters of single-threaded processes exact Mathieu Desnoyers
2026-11-02 19:07 ` [RFC PATCH v23 08/10] lib: percpu_counter_tree: add the arity boot parameter Mathieu Desnoyers
2026-11-02 19:07 ` [RFC PATCH v23 09/10] mm: add the rss_stat_batch " Mathieu Desnoyers
2026-11-02 19:07 ` [RFC PATCH v23 10/10] lib: add a benchmark of hierarchical per-cpu counters Mathieu Desnoyers
2026-11-03 19:07   ` sashiko-bot

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=sashiko-outbox-195884@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=aboorvad@linux.ibm.com \
    --cc=akpm@linux-foundation.org \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=brauner@kernel.org \
    --cc=bsegall@google.com \
    --cc=christian.koenig@amd.com \
    --cc=cl@gentwo.org \
    --cc=corbet@lwn.net \
    --cc=david@kernel.org \
    --cc=dennis@kernel.org \
    --cc=devnexen@gmail.com \
    --cc=dietmar.eggemann@arm.com \
    --cc=hannes@cmpxchg.org \
    --cc=jack@suse.cz \
    --cc=juri.lelli@redhat.com \
    --cc=kees@kernel.org \
    --cc=kprateek.nayak@amd.com \
    --cc=liam@infradead.org \
    --cc=linmiaohe@huawei.com \
    --cc=linux-mm@kvack.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=liumartin@google.com \
    --cc=ljs@kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mgorman@suse.de \
    --cc=mhiramat@kernel.org \
    --cc=mhocko@suse.com \
    --cc=mingo@redhat.com \
    --cc=mjguzik@gmail.com \
    --cc=objecting@objecting.org \
    --cc=oleg@redhat.com \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=rdunlap@infradead.org \
    --cc=richard.weiyang@gmail.com \
    --cc=rientjes@google.com \
    --cc=roman.gushchin@linux.dev \
    --cc=rostedt@goodmis.org \
    --cc=rppt@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=shakeel.butt@linux.dev \
    --cc=sj@kernel.org \
    --cc=skhan@linuxfoundation.org \
    --cc=surenb@google.com \
    --cc=sweettea-kernel@dorminy.me \
    --cc=tj@kernel.org \
    --cc=vbabka@kernel.org \
    --cc=vincent.guittot@linaro.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=vschneid@redhat.com \
    --cc=willy@infradead.org \
    --cc=yuzhao@google.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.