Skip to content

Cpy rust - #11393

Draft
fede2cr wants to merge 3 commits into
adafruit:mainfrom
fede2cr:cpy-rust
Draft

Cpy rust#11393
fede2cr wants to merge 3 commits into
adafruit:mainfrom
fede2cr:cpy-rust

Conversation

@fede2cr

@fede2cr fede2cr commented Sep 15, 2026

Copy link
Copy Markdown

Adding support for circuitpython.

Testing against fede2cr/cpy-rust-examples which include a very basic calculator + string managment as proof of concept, ports of (only as demos) adafruit_debounce and adafruit_ticks, showing that bundle modules can be ported. I have also ported pixels (viper demo) with perfomance of 4.6x for nrf, 4.77x for esp32-s3, and 7.56x fo M7.

In includes two new tools that need to be integrated into mpy-cross (probably), but for now are kept as separate tools to understand what is different while working on rust code.

The goal of this project is not enable rust inside of code.py, but for modules to be written in rust, compiled as .mpy files, copied to lib/ and imported and called like you would a circuitpython function.

As the basic demos and mandelbrot (pixel_rs) show, you have available data types for fp such as f32, f64, for ints like i64, u64, i128, plus structs, slices, enums, strings, etc.

Please help with benchmarking and add any opinions at all of usage, mpy building, ports you'd like to see, and help to get it out of draft PR mode.

@fede2cr

fede2cr commented Sep 15, 2026

Copy link
Copy Markdown
Author

Today I saw turbo-cli tools in Tim's live Deep dive, and it does seems that this is the correct place or at least form that mpy-tool.py and mpy_ld.py should probably go to.

Also, as discussed in last week's meeting, what I'm testing now is benchmarking. When I started the project I wasn't aware of turbo, but it seems like the code to bench against.

code board result
mandelbrot row metro m7 7.56x
mandelbrot row esp32-s3 qtpy 4.76x
mandelbrot row muzi base duo nrf 4.60x
sands metro m7 6.21x
sands esp32-s3 qtpy 4.59x
ulab sqrt(64) metro m7 9.17x
ulab sqrt(256) metro m7 14.69x
ulab sqrt(1024) metro m7 17.85x
ulab sqrt(1024) esp32-s3 qtpy 1.19x

This simple ulab sqrt() is also a very good pointer to moving to rust for native C code, with that 17.85x result!

Note: esp32-s3 sqrt() seems closer in performance. It looks that llvm just moves everything to vsqrt.f32 so it runs on hardware rather than software.

@tannewt

tannewt commented Sep 15, 2026

Copy link
Copy Markdown
Member

@mikeysklar should see this too and coordinate wrt Turbo. Totally happy to have it work with a rust module too.

@mikeysklar

Copy link
Copy Markdown
Collaborator

fede2cr and I have been comparing benchmarks.

The numbers from Rust are impressive. Another ~10x over turbo across the benchmarks.

It looks like a rust or C compiled code will be many times faster than machine code that viper offers. I'm running some tests now of my own on this topic. More to come.

@mikeysklar

Copy link
Copy Markdown
Collaborator

I ran my own benchmarks on this draft: viper, C and Rust, same kernel, eight boards. C was fastest on six of seven, and its toolchain was the more dependable one. Rust stayed close

Board MHz viper C (GCC) Rust C vs viper
ESP32-C5 DevKitC 240 158.3 23.4 not run 6.8x
Metro RP2350 150 260.1 44.1 52.0 5.9x
Metro ESP32-S3 240 171.4 28.3 36.9 6.1x
Metro ESP32-S2 240 205.8 30.7 39.1 6.7x
Metro RP2040 125 382.4 63.7 not run 6.0x
Metro M4 AirLift 120 420.2 84.3 83.5 5.0x
Feather nRF52840 64 778.7 162.5 182.2 4.8x
Feather STM32F405 168 414.9 62.2 69.9 6.7x

Some PR changes you will want to consider:

The loader design does not use the emitter. Code is generated on a host, not on the board.

The ESP32 PRs are merged, so you can rebase on main and drop that code.

The M7 native enable needs its own PR.

@dhalbert

Copy link
Copy Markdown
Collaborator

I would be interested in knowing what optimization flags are being used on rust and gcc.

@mikeysklar

mikeysklar commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

The flags play a roll.

Switching from the CP default gcc flag for size optimization -Os to -O2 with -funroll-loops boosted performance by 17%.

The above table was using optimized options like this:

arm-none-eabi-gcc -I. -I/home/sklarm/cp-1030 -std=c99 -Os -Wall -Werror -DNDEBUG -DNO_QSTR -DMICROPY_ENABLE_DYNRUNTIME -DMP_CONFIGFILE='<build/armv7emsp/pixels_c.config.h>' -fpic -fno-common -U_FORTIFY_SOURCE  -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT  -O2 -funroll-loops -o build/armv7emsp/pixels_c.o -c pixels_c.c

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.

4 participants