Fishwaldo commented on PR #19735:
URL: https://github.com/apache/nuttx/pull/19735#issuecomment-5225656969
Thanks - both comments land on the same question, and the answer to each is
different.
**`arch_strchr.c`: you're right, and it's gone.** Along with `strchrnul`,
`strlen` and `strrchr`.
I had missed the newlib implementations entirely, and went a long way down a
rabbit hole on the assumption that only the default byte-at-a-time ones
existed. Once I benchmarked against `CONFIG_LIBC_NEWLIB_OPTSPEED`, those four
had nothing to add: `strlen` 1.02x, `strchr` 1.01x, `strrchr` 0.97x over twenty
runs. So they are dropped, and RISC-V uses whichever implementation the libc
build selects. The branch and the PR description are updated.
**`arch_strcpy.c`: kept, and the reason is the alignment condition, not the
loop.**
`lib_bsdstrcpy.c` takes its word path only when *both* pointers are already
word-aligned:
```c
#define UNALIGNED(x, y) \
(((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) &
(sizeof(long) - 1)))
if (!UNALIGNED(src0, dst0))
```
Anything else copies the whole string a byte at a time. The RISC-V machine
version instead asks whether the two pointers *agree* about where boundaries
fall, walks up to the boundary bytewise, and takes words from there:
```c
if ((((uintptr_t)d ^ (uintptr_t)src) & (WORD_BYTES - 1)) == 0)
```
For random pointers on RV64 the newlib condition holds about 1 in 64 times;
this one about 1 in 8. And the common case in practice, strings carved out of
the same larger buffer or a struct copied field by field, is exactly the one
where both pointers share an offset but neither is aligned.
Measured on 1.4 GHz RV64 silicon, twenty runs per configuration, MB/s with
95% confidence intervals. **default** is neither option set, **newlib** is
`CONFIG_LIBC_NEWLIB_OPTSPEED=y`, **riscv machine** is
`CONFIG_RISCV_STRING_FUNCTION=y`, this work.
```
default newlib riscv machine
strcpy aligned 609 +-1 2110 +-14 1962 +-9
strcpy same offset 616 +-1 617 +-1 1813 +-8
```
With both pointers aligned, newlib is marginally ahead of the RISC-V version
and I would not argue for replacing it on those numbers alone. With the
pointers merely *agreeing*, newlib is at byte pace, 617 MB/s, and the RISC-V
version is 1813. That second row is the entire justification.
The same pattern decides the other retained routines:
```
memcpy mismatched 410 +-1 322 +-0 3073 +-3
memcmp same offset 30 +-0 38 +-0 420 +-1
strncmp same offset 32 +-0 27 +-0 253 +-0
```
`memcpy` mismatched is the strongest case: newlib is *slower than the
default byte loop* there, 322 against 410, because it detects misalignment and
falls back after paying for the check. The RISC-V version shifts two aligned
loads together to form each store, so nothing misaligned is ever issued.
Where newlib is genuinely competitive I have removed the RISC-V copy. Where
it degrades to bytes on alignments that occur constantly, I have kept it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]