Skip to content

[PW_SID:1155023] riscv: word-at-a-time: improve find_zero() - #2560

Closed
linux-riscv-bot wants to merge 5 commits into
workflow__riscv__fixesfrom
pw1155023
Closed

[PW_SID:1155023] riscv: word-at-a-time: improve find_zero()#2560
linux-riscv-bot wants to merge 5 commits into
workflow__riscv__fixesfrom
pw1155023

Conversation

@linux-riscv-bot

Copy link
Copy Markdown

PR for series 1155023 applied to workflow__riscv__fixes

Name: riscv: word-at-a-time: improve find_zero()
URL: https://patchwork.kernel.org/project/linux-riscv/list/?series=1155023
Version: 1

Xixin Liu and others added 5 commits August 31, 2026 19:12
The available-counter mask was a single unsigned long, but iteration
uses RISCV_MAX_COUNTERS, which is 64. On RV32 that reads past the object.
Filling with an unsigned-long bit at index 32 and above is also wrong.

Use DECLARE_BITMAP and set_bit/bitmap helpers. Walk each bitmap word
into CFG_MATCH when checking events, when allocating an index, and when
stopping all counters. Set the counter base to i times BITS_PER_LONG.
Share the CFG_MATCH ecall through a small helper so the 32-bit argument
split is not duplicated. On qemu-system-riscv32 the probe bitmap has bits
above XLEN set, so the first word alone is not enough.

Fixes: e999143 ("RISC-V: Add perf platform driver based on SBI PMU extension")
Assisted-by: DeepSeek:deepseek-v3
Signed-off-by: Xixin Liu <liuxixin@kylinos.cn>
Link: https://patch.msgid.link/prpmask02cmap.v2.1786434000.git.liuxixin@kylinos.cn
[pjw@kernel.org: updated to apply]
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Current find_zero() heavily depends on fls64() for calculation. This
bring non-optimal code when !RISCV_ISA_ZBB.

But in word-at-a-time case, we don't have to go with fls64() code path,
instead, we can fallback to the generic word-at-a-time implementaion.

What's more, the fls64() brings non-necessary zero bits couting for
RV32. In fact, fls() is enough.

Before the patch:

0000000000000000 <find_zero>:
   0:	c529                	beqz	a0,4a <.L1>
   2:	577d                	li	a4,-1
   4:	9301                	srli	a4,a4,0x20
   6:	03f00793          	li	a5,63
   a:	00a76463          	bltu	a4,a0,12 <.L3>
   e:	1502                	slli	a0,a0,0x20
  10:	47fd                	li	a5,31

0000000000000012 <.L3>:
  12:	577d                	li	a4,-1
  14:	8341                	srli	a4,a4,0x10
  16:	00a76463          	bltu	a4,a0,1e <.L4>
  1a:	37c1                	addiw	a5,a5,-16
  1c:	0542                	slli	a0,a0,0x10

000000000000001e <.L4>:
  1e:	577d                	li	a4,-1
  20:	8321                	srli	a4,a4,0x8
  22:	00a76463          	bltu	a4,a0,2a <.L5>
  26:	37e1                	addiw	a5,a5,-8
  28:	0522                	slli	a0,a0,0x8

000000000000002a <.L5>:
  2a:	577d                	li	a4,-1
  2c:	8311                	srli	a4,a4,0x4
  2e:	00a76463          	bltu	a4,a0,36 <.L6>
  32:	37f1                	addiw	a5,a5,-4
  34:	0512                	slli	a0,a0,0x4

0000000000000036 <.L6>:
  36:	577d                	li	a4,-1
  38:	8309                	srli	a4,a4,0x2
  3a:	00a76463          	bltu	a4,a0,42 <.L7>
  3e:	37f9                	addiw	a5,a5,-2
  40:	050a                	slli	a0,a0,0x2

0000000000000042 <.L7>:
  42:	00054563          	bltz	a0,4c <.L12>
  46:	4037d51b          	sraiw	a0,a5,0x3

000000000000004a <.L1>:
  4a:	8082                	ret

000000000000004c <.L12>:
  4c:	2785                	addiw	a5,a5,1
  4e:	4037d51b          	sraiw	a0,a5,0x3
  52:	8082                	ret

After the patch:

0000000000000000 <find_zero>:
   0:	102037b7          	lui	a5,0x10203
   4:	0792                	slli	a5,a5,0x4
   6:	40578793          	addi	a5,a5,1029 # 10203405 <.L4+0x102033c5>
   a:	07c2                	slli	a5,a5,0x10
   c:	60878793          	addi	a5,a5,1544
  10:	02f50533          	mul	a0,a0,a5
  14:	9161                	srli	a0,a0,0x38
  16:	8082                	ret

33 instructions vs 8 instructions!

And this kind of instructions reducing dramatically improves the
performance of below micro-benchmark:

 $ cat tt.c
 #inlcude <stdio.h>
 #inlcude "word-at-a-time.h" // copy and modify, eg. remove other headers
 int main()
 {
 	int i;
 	unsigned long ret = 0;

	for (i = 0; i < 100000000; i++)
		ret |= find_zero(0xabcd123 + i);

	printf("%ld\n", ret);
 }
 $ gcc -O tt.c
 $ time ./a.out

Per my test, the above micro-benchmark is improved by about 1150%!

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
Previous commit improved the find_zero() performance for !RISCV_ISA_ZBB.
What about RISCV_ISA_ZBB=y but the HW doesn't support Zbb? We have the
same heavy generic fls64() issue.

Let's improve this situation by checking Zbb extension and fall back
to generic count_masked_bytes() if Zbb isn't supported.

To remove non-necessary zero bits couting on RV32, we also replace the
'fls64(mask) >> 3' with '!mask ? 0 : ((__fls(mask) + 1) >> 3);'

We will get similar performance improvement as previous commit for
RISCV_ISA_ZBB=y but HW doesn't support Zbb.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
In commit f915a3e ("arm64: word-at-a-time: improve byte count
calculations for LE"), Linus improved the find_zero() for arm64 LE.
Do the same optimization as he did: "do __ffs() on the intermediate value
that found whether there is a zero byte, before we've actually computed
the final byte mask.", so that we share the similar improvements:

"The difference between the old and the new implementation is that
"count_zero()" ends up scheduling better because it is being done on a
value that is available earlier (before the final mask).

But more importantly, it can be implemented without the insane semantics
of the standard bit finding helpers that have the off-by-one issue and
have to special-case the zero mask situation."

Before the patch:
0000000000000000 <find_zero>:
   0:	c909                	beqz	a0,12 <.L1>
   2:	60051793          	clz	a5,a0
   6:	03f00513          	li	a0,63
   a:	8d1d                	sub	a0,a0,a5
   c:	2505                	addiw	a0,a0,1
   e:	4035551b          	sraiw	a0,a0,0x3

0000000000000012 <.L1>:
  12:	8082                	ret

After the patch:

0000000000000000 <find_zero>:
   0:	60151513          	ctz	a0,a0
   4:	810d                	srli	a0,a0,0x3
   6:	8082                	ret

7 instructions vs 3 instructions!

As can be seen, on RV64 w/ Zbb, the new "find_zero()" ends up just
"ctz" plus the shift right that then ends up being subsumed by the
"add to final length".

But I have no HW platform which supports Zbb, so I can't get the
performance improvement numbers by the last patch, only built and
tested the patch on QEMU.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
Signed-off-by: Linux RISC-V bot <linux.riscv.bot@gmail.com>
@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
build-rv32-defconfig
Desc: Builds riscv32 defconfig
Duration: 145.15 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
build-rv64-clang-allmodconfig
Desc: Builds riscv64 allmodconfig with Clang, and checks for errors and added warnings
Duration: 1469.81 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
build-rv64-gcc-allmodconfig
Desc: Builds riscv64 allmodconfig with GCC, and checks for errors and added warnings
Duration: 1803.70 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
build-rv64-nommu-k210-defconfig
Desc: Builds riscv64 defconfig with NOMMU for K210
Duration: 27.32 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
build-rv64-nommu-k210-virt
Desc: Builds riscv64 defconfig with NOMMU for the virt platform
Duration: 28.17 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
checkpatch
Desc: Runs checkpatch.pl on the patch
Duration: 0.90 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
dtb-warn-rv64
Desc: Checks for Device Tree warnings/errors
Duration: 91.55 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
header-inline
Desc: Detects static functions without inline keyword in header files
Duration: 0.25 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
kdoc
Desc: Detects for kdoc errors
Duration: 0.91 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
module-param
Desc: Detect module_param changes
Duration: 0.27 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
verify-fixes
Desc: Verifies that the Fixes: tags exist
Duration: 0.24 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 1: "[RESEND,1/3] riscv: word-at-a-time: improve find_zero() for !RISCV_ISA_ZBB"
verify-signedoff
Desc: Verifies that Signed-off-by: tags are correct
Duration: 0.32 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
build-rv32-defconfig
Desc: Builds riscv32 defconfig
Duration: 144.37 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
build-rv64-clang-allmodconfig
Desc: Builds riscv64 allmodconfig with Clang, and checks for errors and added warnings
Duration: 1493.83 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
build-rv64-gcc-allmodconfig
Desc: Builds riscv64 allmodconfig with GCC, and checks for errors and added warnings
Duration: 1808.41 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
build-rv64-nommu-k210-defconfig
Desc: Builds riscv64 defconfig with NOMMU for K210
Duration: 26.91 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
build-rv64-nommu-k210-virt
Desc: Builds riscv64 defconfig with NOMMU for the virt platform
Duration: 28.84 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
checkpatch
Desc: Runs checkpatch.pl on the patch
Duration: 2.23 seconds
Result: WARNING
Output:

CHECK: spaces preferred around that '*' (ctx:VxV)
#42: FILE: arch/riscv/include/asm/word-at-a-time.h:54:
+	return mask*0x0001020304050608ul >> 56;
 	           ^

CHECK: spaces preferred around that '+' (ctx:VxV)
#51: FILE: arch/riscv/include/asm/word-at-a-time.h:63:
+	long a = (0x0ff0001+mask) >> 23;
 	                   ^

total: 0 errors, 0 warnings, 2 checks, 37 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

Commit 46ebcb11b06b ("riscv: word-at-a-time: improve find_zero() without Zbb") has style problems, please review.

NOTE: Ignored message types: ALLOC_SIZEOF_STRUCT CAMELCASE COMMIT_LOG_LONG_LINE GIT_COMMIT_ID MACRO_ARG_REUSE NO_AUTHOR_SIGN_OFF

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.
total: 0 errors, 0 warnings, 2 checks, 37 lines checked
CHECK: spaces preferred around that '*' (ctx:VxV)
CHECK: spaces preferred around that '+' (ctx:VxV)


@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
dtb-warn-rv64
Desc: Checks for Device Tree warnings/errors
Duration: 92.01 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
header-inline
Desc: Detects static functions without inline keyword in header files
Duration: 0.23 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
kdoc
Desc: Detects for kdoc errors
Duration: 0.87 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
module-param
Desc: Detect module_param changes
Duration: 0.24 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
verify-fixes
Desc: Verifies that the Fixes: tags exist
Duration: 0.22 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 2: "[RESEND,2/3] riscv: word-at-a-time: improve find_zero() without Zbb"
verify-signedoff
Desc: Verifies that Signed-off-by: tags are correct
Duration: 0.36 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
build-rv32-defconfig
Desc: Builds riscv32 defconfig
Duration: 149.80 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
build-rv64-clang-allmodconfig
Desc: Builds riscv64 allmodconfig with Clang, and checks for errors and added warnings
Duration: 1481.53 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
build-rv64-gcc-allmodconfig
Desc: Builds riscv64 allmodconfig with GCC, and checks for errors and added warnings
Duration: 1822.22 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
build-rv64-nommu-k210-defconfig
Desc: Builds riscv64 defconfig with NOMMU for K210
Duration: 26.49 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
build-rv64-nommu-k210-virt
Desc: Builds riscv64 defconfig with NOMMU for the virt platform
Duration: 27.60 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
checkpatch
Desc: Runs checkpatch.pl on the patch
Duration: 0.78 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
dtb-warn-rv64
Desc: Checks for Device Tree warnings/errors
Duration: 92.00 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
header-inline
Desc: Detects static functions without inline keyword in header files
Duration: 0.26 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
kdoc
Desc: Detects for kdoc errors
Duration: 0.83 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
module-param
Desc: Detect module_param changes
Duration: 0.27 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
verify-fixes
Desc: Verifies that the Fixes: tags exist
Duration: 0.25 seconds
Result: PASS

@linux-riscv-bot

Copy link
Copy Markdown
Author

Patch 3: "[RESEND,3/3] riscv: word-at-a-time: improve find_zero() for Zbb"
verify-signedoff
Desc: Verifies that Signed-off-by: tags are correct
Duration: 0.33 seconds
Result: PASS

@linux-riscv-bot
linux-riscv-bot deleted the pw1155023 branch September 1, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants