如何在 ARM 嵌入式 Rust 中用更少的内存进行取模

How to do modulo with less memory in ARM embedded Rust

我在 STM32F446 MCU 上有一个 Rust 嵌入式项目。考虑下一行:

leds::set_g(self.next_update_time % 2000 == 0)

用了取模,网上看,Cortex M4好像没有取模指令。相反,一个函数被添加到二进制文件中,在软件中执行此操作。使用cargo bloat(基于Google的Bloaty),可以找到

File  .text    Size                 Crate Name
...
0.1%   6.9%    990B     compiler_builtins __udivmoddi4
...

令我惊讶的是,它只需要不到 1 KB 的内存。我认为这很多。它背后的代码也很长,参见 this link。我假设此实现速度很快。还好我还有内存。

使用 opt-level = 'z' 不会改变这一点。

但是如果我买不起怎么办,我怎么能让它占用更少的内存呢?

当然可以使用 this 这样的解决方案,但那样我就无法使用 % 运算符了。

不确定 Rust 链接器有多聪明,但在许多嵌入式链接器实现中,您可以交换自己的 __udivmodi4 实现,它使用更小(但更慢)的方法优先于版本由编译器提供。

一般来说,泛型除法和模运算在嵌入式平台上的开销很大,但常量除法通常可以通过智能编译器 "fixed" 实现进行专门化(通常有公约数的特殊情况 - 3、5 、7、10 等)。

如果您可以控制应用程序,那么将代码更改为除法或取模 2^N 显然更可取(它会折叠为 "right shift" 除法指令,或 "and"模指令)。例如。在这种情况下,2048 可能接近 2000,并且可以将 1 KB 的代码转换为 4 字节的代码。

FWIW 这个 Rust 版本看起来有点胖——例如 GCC implementation 小得多。