PicoLibc support as alternative to Newlib(-nano)#12305
PicoLibc support as alternative to Newlib(-nano)#12305bergzand wants to merge 29 commits intoRIOT-OS:masterfrom
Conversation
|
Some benchmarks on a samr21-xpro:
bench_runtime_coreapisPicolibc: Newlib-Nano: |
|
Would it be possible to include picolibc in https://github.com/RIOT-OS/toolchains ? |
Definitely, if that needs special toolchain support! |
|
Looks like we'll also need thread-local storage - zephyrproject-rtos/zephyr#26545 |
You can build picolibc without TLS, but that means all libc calls with persistent state will share that across threads, including errno. Note that picolibc can only support TLS if the C compiler it was built with supports TLS, so make sure TLS is enabled in your compiler build (it used to be disabled in a bunch of toolchain releases for ARM). |
I've got something working here: https://github.com/keith-packard/RIOT/tree/picolibc_initial This is based off this PR with some additional fixes added. |
|
Those commits are exactly what we need here. Do you mind if I pull them into this PR, of course keeping your commit authorship for those? |
That would be awesome. |
|
Now includes the commits from @keith-packard |
|
Now this needs a rebase. |
a5c765b to
77d6c83
Compare
Rebased and updated |
benpicco
left a comment
There was a problem hiding this comment.
I gave it a quick test on samr21-xpro and for the gnrc_networking it sheds ~7k off .text compared to newlib 😃
Since it requires some adaption to the platform code, this could be modeled as a FEATURE until all platforms have support for it.
picolibc_syscalls_default/syscalls.c and newlib_syscalls_default/syscalls.c can probably share some code, e.g. no need to implement _sbrk_r twice.
This would also give us the VFS integration.
| return 1; | ||
| } | ||
| FILE picolibc_stdio = | ||
| FDEV_SETUP_STREAM(picolibc_put, picolibc_get, NULL, _FDEV_SETUP_RW); |
There was a problem hiding this comment.
Will there be a flush function in case of CDC ACM stdio?
There was a problem hiding this comment.
Yes, what's the API for that? I didn't see one in the newlib code.
There was a problem hiding this comment.
Ok, I reviewed the CDC ACM implementation and that doesn't have any buffering internally; each call to stdio_write causes a separate USB transaction. So, the current code will 'work', although output will be slow. I've added a buffer for output, and also a pile of additional picolibc bits at
https://github.com/keith-packard/RIOT/tree/pr/libc/picolibc_initial
There was a problem hiding this comment.
Want to push that pile of additional picolibc bits again? :D
Or do you want to pull them @bergzand ?
I kind of missed this comment here, I see you hooked up VFS too now.
For the buffering, I wonder if CDC ACM should handle this, but that can be changed later.
There was a problem hiding this comment.
I've rebased my changes on top of @bergzand's current branch and pushed them to my branch again.
https://github.com/keith-packard/RIOT/tree/pr/libc/picolibc_initial
I also added a config option so that by default the integer-only printf/scanf code is use, but the full float code can be selected.
There was a problem hiding this comment.
As for the CDC ACM buffering, it would be nice to include that in the underlying implementation, but that would require exposing a flush function that all users called as needed.
There was a problem hiding this comment.
I've rebased my changes on top of @bergzand's current branch and pushed them to my branch again.
And pulled them in.
There was a problem hiding this comment.
I note that you left out the stdout buffering code. That makes USB performance pretty poor; it might be nice to add that back in and plan on removing it if/when the underlying ACM code adds buffering. I'm not really sure it should though -- you'd have to modify all users of that code to know about the buffering so that they could flush when needed.
aabadie
left a comment
There was a problem hiding this comment.
Some small comments regarding the build system.
The integration in the build system can certainly be improved. Using the FEATURES is appealing but that is not meant for that normally (it related to features are provided by the hardware). One could argue that cpp support is using this mechanism though.
For the moment, we should keep it simple.
|
Compiling and testing on the nrf52dk these are resulting failures: failuresMost of the compile-time failures are related to C++ issues, |
02926c8 to
ad2620f
Compare
Rebased! |
|
With GCC there is still an issue with CPP code: |
That's because your libstdc++ is built against newlib instead of picolibc and ends up referencing symbols found in newlib but not in picolibc. I've spent a bit of time adjusting the libstdc++ code that comes with gcc to make it work with picolibc, but that will still require building it correctly and using the right library. The whole libstdc++ issue is a mess -- it should not be included with GCC as that creates circular build dependencies. |
|
So when using picolib, we could still provide the |
Sounds about right. I've got patches for GCC which build libstdc++ against picolibc; perhaps I should start building the Debian embedded toolchains to use those, which would enable libstdc++ with picolibc. |
Signal that this function will never return Signed-off-by: Keith Packard <keithp@keithp.com>
This provides the POSIX api used by picolibc stdio Signed-off-by: Keith Packard <keithp@keithp.com>
In most places, picolibc and newlib are the same, so use the existing newlib code when compiling with picolibc. Signed-off-by: Keith Packard <keithp@keithp.com>
This makes RIOT use the integer-only printf/scanf code by default and includes a new make parameter to select the full floating point version. This saves about 6kB of text space when building hello-world for the microbit board. Signed-off-by: Keith Packard <keithp@keithp.com>
There was a problem hiding this comment.
Now with the last changes this looks like a pretty simple addition!
As for the buffering, I think we can do that as a separate PR.
Right now no applications will call flush as it's a no-op.
The sooner we can get this in, the sooner we will be able to iron out such kinks.
Some numbers for examples/gnrc_networking:
master
text data bss dec hex filename
97352 184 19236 116772 1c824 /home/benpicco/dev/RIOT/examples/gnrc_networking/bin/samr21-xpro/gnrc_networking.elf
PICOLIBC=1
text data bss dec hex filename
90064 464 19228 109756 1acbc /home/benpicco/dev/RIOT/examples/gnrc_networking/bin/samr21-xpro/gnrc_networking.elf
PICOLIBC=1 LTO=1
text data bss dec hex filename
83864 464 19224 103552 19480 /home/benpicco/dev/RIOT/examples/gnrc_networking/bin/samr21-xpro/gnrc_networking.elf
Needs a rebase btw 😉
| * @return 0 on success | ||
| * @return -1 on error, @c errno set to a constant from errno.h to indicate the error | ||
| */ | ||
| int fcntl (int fd, int cmd, int arg) |
There was a problem hiding this comment.
| int fcntl (int fd, int cmd, int arg) | |
| int fcntl(int fd, int cmd, int arg) |
| } > rom | ||
| __tls_size = __tbss_end - __tdata_start; | ||
| __tbss_size = __tls_size - __tdata_size; | ||
|
|
There was a problem hiding this comment.
lpc23xx.ld will need that block too, but I can add in in a follow-up PR if you don't have the hardware to test.
There was a problem hiding this comment.
lpc23xx.ldwill need that block too, but I can add in in a follow-up PR if you don't have the hardware to test.
Sounds like a plan -- I've tested the series I've posted, you can create another PR with the lpc23xx.ld fixes after testing those :-)
|
I've rebased and then also squashed these patches so that the series looks a little cleaner. I've filed #14827 with that branch. |
|
Closing this one |
Contribution description
This PR adds support to use PicoLibc as libc implementation on RIOT. PicoLibc at the moment uses Newlib as a basis with the stdio implementation from avr-libc strapped on. For the installation of PicoLibc I'd like to refer to the build guide. For RIOT the default build settings should work fine.
Main advantage of PicoLibc is that it shaves approximately 3KB from the flash footprint of a binary. In case of the hello-world example on a samr21-xpro:
Testing procedure
Enable with:
make PICOLIBC=1such as:
make -C examples/gnrc_networking BOARD=samr21-xpro PICOLIBC=1For now only the Cortex-m and RISC-V MCUs are supported.
Issues/PRs references
None
Todo:
printf_float