From: Yury Norov <yury.norov@gmail.com>
To: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
linux-kernel@vger.kernel.org,
Alexey Klimov <klimov.linux@gmail.com>,
Andy Whitcroft <apw@canonical.com>,
Catalin Marinas <catalin.marinas@arm.com>,
David Laight <David.Laight@aculab.com>,
Dennis Zhou <dennis@kernel.org>,
Guenter Roeck <linux@roeck-us.net>,
Kees Cook <keescook@chromium.org>,
Rasmus Villemoes <linux@rasmusvillemoes.dk>,
Valentin Schneider <vschneid@redhat.com>,
Sven Schnelle <svens@linux.ibm.com>,
Russell King <linux@armlinux.org.uk>
Subject: Re: [PATCH v4 3/4] lib/find_bit: optimize find_next_bit() functions
Date: Mon, 19 Sep 2022 18:41:25 -0700 [thread overview]
Message-ID: <YykaRYstXwJGqwvB@yury-laptop> (raw)
In-Reply-To: <YyhykvFCOskPAp59@smile.fi.intel.com>
On Mon, Sep 19, 2022 at 04:45:54PM +0300, Andy Shevchenko wrote:
> On Wed, Sep 14, 2022 at 07:07:29PM -0700, Yury Norov wrote:
> > Over the past couple years, the function _find_next_bit() was extended
> > with parameters that modify its behavior to implement and- zero- and le-
> > flavors. The parameters are passed at compile time, but current design
> > prevents a compiler from optimizing out the conditionals.
> >
> > As find_next_bit() API grows, I expect that more parameters will be added.
> > Current design would require more conditional code in _find_next_bit(),
> > which would bloat the helper even more and make it barely readable.
> >
> > This patch replaces _find_next_bit() with a macro FIND_NEXT_BIT, and adds
> > a set of wrappers, so that the compile-time optimizations become possible.
> >
> > The common logic is moved to the new macro, and all flavors may be
> > generated by providing a FETCH macro parameter, like in this example:
> >
> > #define FIND_NEXT_BIT(FETCH, MUNGE, size, start) ...
> >
> > find_next_xornot_and_bit(addr1, addr2, addr3, size, start)
> > {
> > return FIND_NEXT_BIT(addr1[idx] ^ ~addr2[idx] & addr3[idx],
> > /* nop */, size, start);
> > }
> >
> > The FETCH may be of any complexity, as soon as it only refers the bitmap(s)
> > and an iterator idx.
> >
> > MUNGE is here to support _le code generation for BE builds. May be
> > empty.
> >
> > I ran find_bit_benchmark 16 times on top of 6.0-rc2 and 16 times on top
> > of 6.0-rc2 + this series. The results for kvm/x86_64 are:
> >
> > v6.0-rc2 Optimized Difference Z-score
> > Random dense bitmap ns ns ns %
> > find_next_bit: 787735 670546 117189 14.9 3.97
> > find_next_zero_bit: 777492 664208 113284 14.6 10.51
> > find_last_bit: 830925 687573 143352 17.3 2.35
> > find_first_bit: 3874366 3306635 567731 14.7 1.84
> > find_first_and_bit: 40677125 37739887 2937238 7.2 1.36
> > find_next_and_bit: 347865 304456 43409 12.5 1.35
> >
> > Random sparse bitmap
> > find_next_bit: 19816 14021 5795 29.2 6.10
> > find_next_zero_bit: 1318901 1223794 95107 7.2 1.41
> > find_last_bit: 14573 13514 1059 7.3 6.92
> > find_first_bit: 1313321 1249024 64297 4.9 1.53
> > find_first_and_bit: 8921 8098 823 9.2 4.56
> > find_next_and_bit: 9796 7176 2620 26.7 5.39
> >
> > Where the statistics is significant (z-score > 3), the improvement
> > is ~15%.
> >
> > According to the bloat-o-meter, the Image size is 10-11K less:
> >
> > x86_64/defconfig:
> > add/remove: 32/14 grow/shrink: 61/782 up/down: 6344/-16521 (-10177)
> >
> > arm64/defconfig:
> > add/remove: 3/2 grow/shrink: 50/714 up/down: 608/-11556 (-10948)
>
> ...
>
> > /*
>
> Seems like you wanted this to be a kernel doc, but it isn't right now.
No, I didn't. I can remove '@' below, if that concerns you.
> > - * This is a common helper function for find_next_bit, find_next_zero_bit, and
> > - * find_next_and_bit. The differences are:
> > - * - The "invert" argument, which is XORed with each fetched word before
> > - * searching it for one bits.
> > - * - The optional "addr2", which is anded with "addr1" if present.
> > + * Common helper for find_next_bit() function family
>
> In such case this should start with a name of the macro
>
> * FIND_NEXT_BIT - ...
>
> > + * @FETCH: The expression that fetches and pre-processes each word of bitmap(s)
> > + * @MUNGE: The expression that post-processes a word containing found bit (may be empty)
> > + * @size: The bitmap size in bits
> > + * @start: The bitnumber to start searching at
> > */
>
> ...
>
> > +#define FIND_NEXT_BIT(FETCH, MUNGE, size, start) \
> > +({ \
> > + unsigned long mask, idx, tmp, sz = (size), __start = (start); \
> > + \
> > + if (unlikely(__start >= sz)) \
> > + goto out; \
> > + \
> > + mask = MUNGE(BITMAP_FIRST_WORD_MASK(__start)); \
> > + idx = __start / BITS_PER_LONG; \
> > + \
> > + for (tmp = (FETCH) & mask; !tmp; tmp = (FETCH)) { \
> > + if ((idx + 1) * BITS_PER_LONG >= sz) \
> > + goto out; \
> > + idx++; \
> > + } \
> > + \
> > + sz = min(idx * BITS_PER_LONG + __ffs(MUNGE(tmp)), sz); \
> > +out: \
>
> I dunno if GCC expression limits the scope of goto labels, but on the safe side
> you can add a prefix to it, so it becomes:
>
> FIND_NEXT_BIT_out:
>
> (or alike).
As Linus already said, the 'out' is function-scope. We can make it a
block-scope with __label__, but this would make an impression that we
are OK with stacking many FIND macros in a single function.
I spend some time trying to figure out a legitimate usecase for it, but
nothing came in mind. There are many real cases when we need 2 or more
find functions at once but all that cases would work with regular
wrappers around FIND_BIT(). Check this, for example:
https://lore.kernel.org/lkml/20220919210559.1509179-6-yury.norov@gmail.com/
I don't know how FIND_BIT() machinery will evolve with time. For now
it's a clean and neat local helper with a very straightforward usage.
Lets keep it simple now? If someone will decide to call FIND_BIT()
twice and fail, it would be a good hint that he's doing something
wrong.
> > + sz; \
> > +})
>
> ...
>
> > +unsigned long _find_next_zero_bit_le(const unsigned long *addr, unsigned
> > + long size, unsigned long offset)
>
> Usually we don't split parameters between lines.
Ok
Thanks,
Yury
next prev parent reply other threads:[~2022-09-20 1:44 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-15 2:07 [PATCH v4 0/4] lib: optimize find_bit() functions Yury Norov
2022-09-15 2:07 ` [PATCH v4 1/4] lib/find_bit: introduce FIND_FIRST_BIT() macro Yury Norov
2022-09-15 2:07 ` [PATCH v4 2/4] lib/find_bit: create find_first_zero_bit_le() Yury Norov
2022-09-19 13:45 ` Andy Shevchenko
2022-09-15 2:07 ` [PATCH v4 3/4] lib/find_bit: optimize find_next_bit() functions Yury Norov
2022-09-15 16:25 ` Valentin Schneider
2022-09-19 13:45 ` Andy Shevchenko
2022-09-19 15:23 ` Linus Torvalds
2022-09-20 11:59 ` Andy Shevchenko
2022-09-20 1:41 ` Yury Norov [this message]
2022-09-15 2:07 ` [PATCH v4 4/4] tools: sync find_bit() implementation Yury Norov
2022-09-21 15:40 ` [PATCH v4 0/4] lib: optimize find_bit() functions Yury Norov
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=YykaRYstXwJGqwvB@yury-laptop \
--to=yury.norov@gmail.com \
--cc=David.Laight@aculab.com \
--cc=andriy.shevchenko@linux.intel.com \
--cc=apw@canonical.com \
--cc=catalin.marinas@arm.com \
--cc=dennis@kernel.org \
--cc=keescook@chromium.org \
--cc=klimov.linux@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=linux@rasmusvillemoes.dk \
--cc=linux@roeck-us.net \
--cc=svens@linux.ibm.com \
--cc=torvalds@linux-foundation.org \
--cc=vschneid@redhat.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.