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]

Reply via email to