From: Yury Norov <yury.norov@gmail.com>
To: Mark Rutland <mark.rutland@arm.com>
Cc: I Hsin Cheng <richard120310@gmail.com>,
linux@rasmusvillemoes.dk, jserv@ccns.ncku.edu.tw,
linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH] cpumask: Implement "random" version of cpumask_any_but()
Date: Mon, 13 Jan 2025 13:00:56 -0500 [thread overview]
Message-ID: <Z4VU2MfOSq9VJvBN@thinkpad> (raw)
In-Reply-To: <Z4TzZMCn_OWuQBNH@J2N7QTR9R3>
On Mon, Jan 13, 2025 at 11:05:19AM +0000, Mark Rutland wrote:
> On Mon, Jan 13, 2025 at 02:18:39PM +0800, I Hsin Cheng wrote:
> > Original implementation of "cpumask_any_but()" isn't actually random as
> > the comment claims itself to be. It's behavior is in fact to select the
> > first cpu in "mask" which isn't equal to "cpu".
>
> What it says specifically is:
>
> cpumask_any_but - return a "random" in a cpumask, but not this one.
>
> ... and by "random", it really means "arbitrary".
>
> The idea here is that the caller is specifying that it doesn't care
> which specific CPU is chosen, but this is not required to be a random
> selection.
>
> > Re-implement the function so we can choose a random cpu by randomly
> > select the value of "n" and choose the nth cpu in "mask"
> >
> > Experiments[1] are done below to verify it generate more random result than
> > orginal implementation which tends to select the same cpu over and over
> > again.
>
> I think what you're after here is similar to
> cpumask_any_and_distribute(), and you should look at building
> cpumask_any_but_distribute() in the same way, rather than changing
> cpumask_any_but().
>
> Mark.
I agree with Mark. cpumask_any_but_distribute() is what you most
likely need. Anyways, whatever you end up please don't change existing
API, especially in a way that hurts performance so badly.
>
> > Signed-off-by: I Hsin Cheng <richard120310@gmail.com>
This patch should go with a demonstration that some particular
system(s) benefits from it, and the others don't suffer.
> > ---
> > The test is done on x86_64 architecture with 6.8.0-48-generic kernel
> > version on Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
> >
> > [1]:
> > Test script:
> >
> > int init_module(void)
> > {
> > const struct cpumask *cur_mask = cpu_online_mask;
> > unsigned int cpu = 5, result;
> > int times = 50;
> >
> > pr_info("Old cpumask_any_but(): ");
> > for (int i = 0; i < times; i++) {
> > result = cpumask_any_but(cur_mask, cpu);
> > pr_cont("%u ", result);
> > }
> > pr_info("\n");
> >
> > pr_info("New cpumask_any_but(): ");
> > for (int i = 0; i < times; i++) {
> > result = cpumask_any_but_v2(cur_mask, cpu);
> > pr_cont("%u ", result);
> > }
> > pr_info("\n");
> >
> > return 0;
> > }
> >
> > Experiment result showned as below display in dmesg:
> > [ 8036.558152] Old cpumask_any_but(): 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
> >
> > [ 8036.558193] New cpumask_any_but(): 7 1 1 2 2 2 3 4 0 2 7 4 6 3 3 2 2 4 2 7 6 6 6 4 6 6 6 4 4 7 6 2 2 6 7 6 6 3 0 6 2 1 0 4 4 6 4 6 6 3
>
> > ---
> > include/linux/cpumask.h | 14 ++++++++++----
> > 1 file changed, 10 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
> > index 9278a50d5..336297960 100644
> > --- a/include/linux/cpumask.h
> > +++ b/include/linux/cpumask.h
#include <linux/random.h>
Which would be really good to avoid.
> > @@ -401,12 +401,18 @@ unsigned int __pure cpumask_next_wrap(int n, const struct cpumask *mask, int sta
> > static __always_inline
> > unsigned int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
> > {
> > - unsigned int i;
> > + unsigned int i, n, weight;
> >
> > cpumask_check(cpu);
> > - for_each_cpu(i, mask)
> > - if (i != cpu)
> > - break;
> > + weight = cpumask_weight(mask);
> > + n = get_random_u32() % weight;
> > +
> > + /* If we accidentally pick "n" equal to "cpu",
> > + * then simply choose "n + 1"th cpu.
> > + */
> > + if (n == cpu)
> > + n = (n + 1) % weight;
> > + i = cpumask_nth(n, mask);
This is an entirely broken thing, and it works only because your CPU mask
is dense. Imagine cpumask: 0111 1111. Your new cpumask_any_but(mask, 5)
will return 5 exactly, if the get_random_u32() draws 4.
It looks broken even for a dense mask. By probability, your code returns:
P(0-4,7) == 1/8,
P(5) == 0,
P(6) == 1/4.
Assuming you are trying to implement a random uniform distribution drawing,
the correct probabilities should look like:
P(0-4,6-7) == 1/7,
P(5) == 0,
Thanks,
Yury
> > return i;
> > }
> >
> > --
> > 2.43.0
> >
> >
next prev parent reply other threads:[~2025-01-13 18:00 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-13 6:18 [RFC PATCH] cpumask: Implement "random" version of cpumask_any_but() I Hsin Cheng
2025-01-13 9:45 ` kernel test robot
2025-01-13 9:45 ` kernel test robot
2025-01-13 10:13 ` Kuan-Wei Chiu
2025-01-13 10:27 ` I Hsin Cheng
2025-01-13 11:09 ` Kuan-Wei Chiu
2025-01-13 11:05 ` Mark Rutland
2025-01-13 18:00 ` Yury Norov [this message]
2025-01-14 7:15 ` I Hsin Cheng
2025-01-14 15:02 ` Mark Rutland
2025-01-14 15:43 ` Yury Norov
2025-01-15 7:24 ` I Hsin Cheng
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=Z4VU2MfOSq9VJvBN@thinkpad \
--to=yury.norov@gmail.com \
--cc=jserv@ccns.ncku.edu.tw \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@rasmusvillemoes.dk \
--cc=mark.rutland@arm.com \
--cc=richard120310@gmail.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.