From: David Laight <david.laight.linux@gmail.com>
To: "Uwe Kleine-König" <u.kleine-koenig@baylibre.com>
Cc: Nicolas Pitre <nico@fluxnic.net>,
Andrew Morton <akpm@linux-foundation.org>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] math64: Provide an uprounding variant of mul_u64_u64_div_u64()
Date: Wed, 2 Apr 2025 21:59:19 +0100 [thread overview]
Message-ID: <20250402215919.2b933752@pumpkin> (raw)
In-Reply-To: <gqqxuoz5jfrlsmrxdhwevfo7kflxjqhbkfy2ksnsdcadbk52hd@yaitrauy52xg>
On Wed, 2 Apr 2025 17:01:49 +0200
Uwe Kleine-König <u.kleine-koenig@baylibre.com> wrote:
> Hello David,
>
> On Wed, Apr 02, 2025 at 01:52:19PM +0100, David Laight wrote:
> > On Wed, 2 Apr 2025 10:16:19 +0200
> > Uwe Kleine-König <u.kleine-koenig@baylibre.com> wrote:
> >
> > > On Tue, Apr 01, 2025 at 10:37:31PM +0100, David Laight wrote:
> > > > On Tue, 1 Apr 2025 16:30:34 -0400 (EDT)
> > > > Nicolas Pitre <nico@fluxnic.net> wrote:
> > > >
> > > > > On Tue, 1 Apr 2025, Nicolas Pitre wrote:
> > > > >
> > > > > > On Tue, 1 Apr 2025, David Laight wrote:
> > > > > >
> > > > > > > Looking at the C version, I wonder if the two ilog2() calls are needed.
> > > > > > > They may not be cheap, and are the same as checking 'n_hi == 0'.
> > > > > >
> > > > > > Which two calls? I see only one.
> > > > >
> > > > > Hmmm, sorry. If by ilog2() you mean the clz's then those are cheap. Most
> > > > > CPUs have a dedicated instruction for that. The ctz, though, is more
> > > > > expensive (unless it is ARMv7 and above with an RBIT instruction).
> > > >
> > > > The code (6.14-rc6) starts:
> > > >
> > > > u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c)
> > > > {
> > > > if (ilog2(a) + ilog2(b) <= 62)
> > > > return div64_u64(a * b, c);
> > > >
> > > > Now ilog2() is (probably) much the same as clz - but not all cpu have it.
> > > > Indeed clz(a) + clz(b) >= 64 would be a more obvious test.
> > >
> > > Ack, the more intuitive check might be
> > >
> > > if (fls64(a) + fls64(b) <= 64)
> > > return div64_u64(a * b, c);
> > >
> > > then, but maybe "intuitive" is subjective here?
> >
> > Depends on whether you grok 'clz' or 'fls' :-)
>
> And it also depends on the availability of the respective functions.
> There is a fls64 function provided by include/asm-generic/bitops/fls64.h
> and in several arch-specific arch/*/include/asm/bitops.h, but I didn't
> find a clz function apart from one for arch=arc.
>
> > > > On 32bit a check for a >> 32 | b >> 32 before the multiply might be sane.
> > >
> > > Not 100% sure I'm following. `a >> 32 | b >> 32` is just an indicator
> > > that a * b fits into an u64 and in that case the above check is the
> > > better one as this also catches e.g. a = (1ULL << 32) and b = 42.
> >
> > That is to optimise the multiple as well as the divide.
> > It is also a very cheap test.
>
> OK, so we have:
>
> `a >> 32 | b >> 32` | `fls64(a) + fls64(b) <= 64`
> cheap | ✓ | ✓
fls() isn't always cheap.
x86 has had bsr since the 386, but I don't remember seeing it in arm32 or ppc.
The 'a >> 32 | b >> 32' is very cheap on 32bit.
> allows to skip multiplication | ✓ | ✓
> allows to skip 128bit division | ✓ | ✓
> catches all skip possibilities | x | ✓
>
> > > > > > And please explain how it can be the same as checking 'n_hi == 0'.
> > > > >
> > > > > This question still stands.
> > > >
> > > > 'ni_hi == 0' is exactly the condition under which you can do a 64 bit divide.
> > > > Since it is when 'a * b' fits in 64 bits.
> > > >
> > > > If you assume that most calls need the 128bit product (or why use the function)
> > > > then there is little point adding code to optimise for the unusual case.
> > >
> > > n_hi won't be zero when the branch
> > >
> > > if (ilog2(a) + ilog2(b) <= 62)
> > > return div64_u64(a * b, c);
> > >
> > > wasn't taken?
> >
> > Right, but you can remove that test and check n_hi instead.
> > The multiplies are cheap compared to the divide loop.
> > (Especially when uint128 exists.)
>
> But you can check n_hi only after you completed the multiplication, so
> checking `ilog2(a) + ilog2(b) <= 62` (or `fls64(a) + fls64(b) <= 64` or
> `clz(a) + clz(b) >= 64`) sounds like a good idea to me.
Depends on how much of the time you think the multiply is needed.
If it is needed most of the time you want to do it first.
If it is hardly ever needed then the initial check is likely to be a gain.
David
>
> > I also think you can do a much better divide loop (for many cpu).
> > Shift 'c' so that clz(c) is 32.
> > Shift 'n_hi/n_lo' so that clz(n_hi) is 1.
> > Do a 64 by 32 divide and remainder (probably about 32 or 64 clocks).
> > If bits of 'c' were discarded multiple and subtract (with overflow check).
> > 'Rinse and repeat' with the remainder.
> > Build the quotient out of all the partial values.
>
> I let this for Nicolas to reply. I guess he is much more into these
> details than me.
>
> Best regards
> Uwe
next prev parent reply other threads:[~2025-04-02 20:59 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-19 17:14 [PATCH] math64: Provide an uprounding variant of mul_u64_u64_div_u64() Uwe Kleine-König
2025-03-19 19:38 ` Nicolas Pitre
2025-03-20 7:36 ` Uwe Kleine-König
2025-03-21 13:18 ` David Laight
2025-03-31 16:14 ` Uwe Kleine-König
2025-03-31 18:53 ` David Laight
2025-04-01 7:25 ` Uwe Kleine-König
2025-04-01 19:26 ` David Laight
2025-04-01 20:13 ` Nicolas Pitre
2025-04-01 20:30 ` Nicolas Pitre
2025-04-01 21:37 ` David Laight
2025-04-01 22:10 ` Nicolas Pitre
2025-04-02 8:16 ` Uwe Kleine-König
2025-04-02 12:52 ` David Laight
2025-04-02 15:01 ` Uwe Kleine-König
2025-04-02 20:59 ` David Laight [this message]
2025-04-03 6:08 ` Uwe Kleine-König
2025-04-02 21:46 ` David Laight
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=20250402215919.2b933752@pumpkin \
--to=david.laight.linux@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nico@fluxnic.net \
--cc=u.kleine-koenig@baylibre.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