Closed georgik closed 3 years ago
cargo-bloat will show the storage requirements per crate in the resulting executable.
Looking a bit closer, I'm not sure cargo bloat will suffice.
It doesn't seem to work when building C libraries, i.e output from running it in rust-esp32-std-hello
is:
1) for version 0.9:
Finished dev [optimized + debuginfo] target(s) in 0.07s
Analyzing target/xtensa-esp32-espidf/debug/rust-esp32-std-hello
File .text Size Crate Name
0.0% NaN% 0B And 0 smaller methods. Use -n N to show more.
0.0% 100.0% 0B .text section size, the file size is 16.8MiB
2) For version 0.10: Error: parsing failed cause 'symbols section is missing'.
After discussions with @igrr, it doesn't fully analyze the binary only the .text
section
Perhaps we should explore using idf_size.py?
For anyone wanting to look into this, to get cargo
to produce a map file, you'll need to add the following linker arguments:
rustflags = [
"-C", "link-arg=-Wl,-Map=target/build.map",
]
After which, the produced map file will still have mangled names, so you'll need to run it through rustfilt
.
Just for clarification:
For MSVC:
rustflags = [ "-C", "link-arg=/MAP:build.map", ]
For GCC:
rustflags = [ "-C", "link-arg=-Wl,-Map=build.map", ]
For LLD:
rustflags = [ "-C", "link-arg=-Map=build.map", ]
Just a note for cargo bloat
: You can specify the symbols section that it's going to look at, so that would be .iram0.text
and .flash.text
(you can only specify one section right now).
I've been playing with idf_size.py.
The memory statistics of ( https://github.com/espressif/rust-esp32-example ) with per-archive contributions to ELF file looks like this:
python $IDF_PATH\tools\idf_size.py --archives build\esp32-hello-rust.map (Windows)
$IDF_PATH/tools/idf_size.py --archives build/esp32-hello-rust.map (Linux)
Total sizes:
Used static DRAM: 11332 bytes ( 169404 remain, 6.3% used)
.data size: 9068 bytes
.bss size: 2264 bytes
Used static IRAM: 44415 bytes ( 86657 remain, 33.9% used)
.text size: 43388 bytes
.vectors size: 1027 bytes
Used stat D/IRAM: 55747 bytes ( 256061 remain, 17.9% used)
.data size: 9068 bytes
.bss size: 2264 bytes
.text size: 43388 bytes
.vectors size: 1027 bytes
Used Flash size : 113691 bytes
.text : 84103 bytes
.rodata : 29332 bytes
Total image size: 220657 bytes (.bin may be padded larger)
Per-archive contributions to ELF file:
Archive File DRAM .bss & 0.data Flash .appdesc & .rodata & .text IRAM0 .text & 0.vectors .rtc.data flash_total ram_st_total
(exe) 0 0 0 12 3 0 3 0 18 3
libapp_update.a 12 1 256 129 174 194 0 0 754 207
libbootloader_support.a 0 0 0 0 115 1421 0 0 1536 1421
libc.a 0 4 0 4270 55038 0 0 0 59312 4
libclib.a 0 0 0 28 24 0 0 0 52 0
libcxx.a 0 0 0 0 5 0 0 0 5 0
libdriver.a 53 72 0 601 3435 0 0 0 4108 125
libefuse.a 4 28 0 780 1339 0 0 0 2147 32
libesp_common.a 0 0 0 7287 53 0 0 0 7340 0
libesp_hw_support.a 30 176 0 387 2950 3953 0 16 7482 4175
libesp_ipc.a 88 28 0 273 539 714 0 0 1554 830
libesp_ringbuf.a 0 0 0 512 0 854 0 0 1366 854
libesp_rom.a 0 0 0 0 0 112 0 0 112 112
libesp_system.a 210 205 0 3809 5936 2901 0 0 12851 3316
libesp_timer.a 24 32 0 574 893 894 0 0 2393 950
libfreertos.a 740 3104 0 3516 237 13064 425 0 20346 17333
libhal.a 0 287 0 936 1514 4165 0 0 6902 4452
libheap.a 8 1962 0 2320 1661 5039 0 0 10982 7009
liblog.a 272 8 0 123 488 238 0 0 857 518
libmain.a 0 0 0 288 256 0 0 0 544 0
libnewlib.a 440 237 0 340 1009 1408 0 0 2994 2085
libpthread.a 12 8 0 0 264 0 0 0 272 20
librustlib.a 0 0 0 0 53 0 0 0 53 0
libspi_flash.a 294 1492 0 2198 1449 7360 0 0 12499 9146
libvfs.a 48 308 0 468 6121 0 0 0 6897 356
libxt_hal.a 0 0 0 32 0 443 0 0 475 443
libxtensa.a 0 1024 0 35 126 77 0 0 1262 1101
For even more detailed statistics, use --files
argument. It's also able to compare two binaries with --diff
argument. For more information, please refer to ( https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/performance/size.html ).
idf_size.py also works on the ( https://github.com/ivmarkov/rust-esp32-std-hello ) but fails on the ( https://github.com/esp-rs/esp32-hal ) with error:
Traceback (most recent call last):
File "/home/juraj/esp-idf/tools/idf_size.py", line 1185, in <module>
main()
File "/home/juraj/esp-idf/tools/idf_size.py", line 522, in main
detected_target, segments, sections = load_map_data(args.map_file)
File "/home/juraj/esp-idf/tools/idf_size.py", line 274, in load_map_data
detected_chip = detect_target_chip(map_file)
File "/home/juraj/esp-idf/tools/idf_size.py", line 333, in detect_target_chip
raise RuntimeError('Target not detected')
RuntimeError: Target not detected
@JurajSadel good results so far! The list doesn't seem to include any Rust crates, only C static libraries which come from IDF. Can you look if Rust crates are reflected in the map file somehow, and if yes, what prevents idf_size.py from identifying them?
Regarding RuntimeError: Target not detected
, can we work around this by using the target specified by idf_size.py's --target
argument, if it is provided, and only call detect_target_chip
if it isn't?
@igrr thank you!
I used the --files
argument on https://github.com/ivmarkov/rust-esp32-std-hello and the small sample of the memory statistics looks like this:
Per-file contributions to ELF file:
Object File DRAM .bss & 0.data Flash .rodata & .text IRAM0 .text & 0.vectors .rtc.data flash_total ram_st_total
libcompiler_builtins-687 0 0 0 148 0 0 0 148 0
libcompiler_builtins-687 0 0 160 150 0 0 0 310 0
libcompiler_builtins-687 0 0 0 95 0 0 0 95 0
libcompiler_builtins-687 0 0 158 469 0 0 0 627 0
libcompiler_builtins-687 0 0 0 185 0 0 0 185 0
libcore-7a2cc5bd9998b496 0 0 309 3227 0 0 0 3536 0
libcore-7a2cc5bd9998b496 0 0 462 2028 0 0 0 2490 0
libcore-7a2cc5bd9998b496 0 0 0 987 0 0 0 987 0
libcore-7a2cc5bd9998b496 0 0 0 721 0 0 0 721 0
libcore-7a2cc5bd9998b496 0 0 32 211 0 0 0 243 0
libcore-7a2cc5bd9998b496 0 0 0 631 0 0 0 631 0
libcore-7a2cc5bd9998b496 0 0 1907 1445 0 0 0 3352 0
libcore-7a2cc5bd9998b496 0 0 855 643 0 0 0 1498 0
libcore-7a2cc5bd9998b496 0 0 143 904 0 0 0 1047 0
libcore-7a2cc5bd9998b496 0 0 179 4416 0 0 0 4595 0
libcore-7a2cc5bd9998b496 0 0 281 129 0 0 0 410 0
libcore-7a2cc5bd9998b496 0 0 255 2004 0 0 0 2259 0
libcstr_core-011728cd952 0 0 176 292 0 0 0 468 0
libembedded_graphics-652 0 0 16 61 0 0 0 77 0
libembedded_graphics_cor 0 0 0 5 0 0 0 5 0
libembedded_svc-3abf7236 0 0 518 1488 0 0 0 2006 0
libembedded_svc-3abf7236 0 0 276 370 0 0 0 646 0
libembedded_svc-3abf7236 0 0 68 433 0 0 0 501 0
libembedded_svc-3abf7236 0 0 173 551 0 0 0 724 0
libembedded_svc-3abf7236 0 0 382 796 0 0 0 1178 0
libembedded_svc-3abf7236 0 0 878 2469 0 0 0 3347 0
libembedded_svc-3abf7236 0 0 570 1362 0 0 0 1932 0
libembedded_svc-3abf7236 0 0 211 912 0 0 0 1123 0
libembedded_svc-3abf7236 0 0 280 1118 0 0 0 1398 0
libembedded_svc-3abf7236 0 0 0 525 0 0 0 525 0
libembedded_svc-3abf7236 0 0 109 349 0 0 0 458 0
libembedded_svc-3abf7236 0 0 250 400 0 0 0 650 0
libenumset-f4236ef035df1 0 0 144 228 0 0 0 372 0
libesp_idf_svc-4f2f734d1 0 8 4422 9276 0 0 0 13706 8
libesp_idf_svc-4f2f734d1 0 0 605 732 0 0 0 1337 0
libesp_idf_svc-4f2f734d1 0 0 64 566 0 0 0 630 0
libesp_idf_svc-4f2f734d1 0 0 276 706 0 0 0 982 0
libesp_idf_svc-4f2f734d1 0 0 334 611 0 0 0 945 0
libesp_idf_svc-4f2f734d1 0 0 51 157 0 0 0 208 0
libesp_idf_svc-4f2f734d1 0 8 466 689 0 0 0 1163 8
libesp_idf_svc-4f2f734d1 0 0 1565 5388 0 0 0 6953 0
libesp_idf_svc-4f2f734d1 0 0 1440 2422 0 0 0 3862 0
libesp_idf_svc-4f2f734d1 0 0 173 1216 0 0 0 1389 0
libesp_idf_svc-4f2f734d1 0 8 813 1864 0 0 0 2685 8
libesp_idf_svc-4f2f734d1 0 8 748 1145 0 0 0 1901 8
libesp_idf_svc-4f2f734d1 0 0 345 429 0 0 0 774 0
libesp_idf_svc-4f2f734d1 0 0 442 277 0 0 0 719 0
libesp_idf_svc-4f2f734d1 0 0 0 236 0 0 0 236 0
libesp_idf_sys-f33521328 0 0 0 29 0 0 0 29 0
libesp_idf_sys-f33521328 0 0 0 17 0 0 0 17 0
libesp_idf_sys-f33521328 0 0 0 181 0 0 0 181 0
libesp_idf_sys-f33521328 0 0 397 258 0 0 0 655 0
libhashbrown-22bf0ba8d89 0 0 143 60 0 0 0 203 0
libhashbrown-22bf0ba8d89 0 0 0 12 0 0 0 12 0
libhttp_auth_basic-14612 0 0 0 19 0 0 0 19 0
liblog-ce623a4a2b171506. 8 8 78 285 0 0 0 371 16
libmemchr-a04c63f4a3f2a2 0 0 377 430 0 0 0 807 0
librustc_demangle-f2e98b 0 0 0 28 0 0 0 28 0
librustc_demangle-f2e98b 0 0 0 5 0 0 0 5 0
librustc_demangle-f2e98b 0 0 831 2134 0 0 0 2965 0
librustc_demangle-f2e98b 0 0 153 118 0 0 0 271 0
librustc_demangle-f2e98b 0 0 1176 4095 0 0 0 5271 0
librustc_demangle-f2e98b 0 0 1758 9541 0 0 0 11299 0
librustc_demangle-f2e98b 0 0 0 17 0 0 0 17 0
libserde_json-7dc1d58f59 0 0 0 26 0 0 0 26 0
libserde_json-7dc1d58f59 0 0 0 22 0 0 0 22 0
libserde_json-7dc1d58f59 0 0 0 17 0 0 0 17 0
libserde_json-7dc1d58f59 0 0 0 11 0 0 0 11 0
libstd-06b540ec5a53d87e. 4 8 1604 4752 0 0 0 6364 12
libstd-06b540ec5a53d87e. 0 0 927 2360 0 0 0 3287 0
libstd-06b540ec5a53d87e. 41 8 495 2036 0 0 0 2539 49
libstd-06b540ec5a53d87e. 0 0 827 1299 0 0 0 2126 0
libstd-06b540ec5a53d87e. 4 0 1268 2032 0 0 0 3300 4
libstd-06b540ec5a53d87e. 0 12 1381 3706 0 0 0 5099 12
libstd-06b540ec5a53d87e. 0 56 918 3589 0 0 0 4563 56
libstd-06b540ec5a53d87e. 4 0 963 1442 0 0 0 2405 4
libstd-06b540ec5a53d87e. 0 12 1500 3182 0 0 0 4694 12
libstd-06b540ec5a53d87e. 0 4 664 1777 0 0 0 2445 4
libstd-06b540ec5a53d87e. 4 8 1781 3414 0 0 0 5203 12
libstd-06b540ec5a53d87e. 4 0 580 2899 0 0 0 3479 4
libstd-06b540ec5a53d87e. 0 0 1462 4768 0 0 0 6230 0
libstd-06b540ec5a53d87e. 0 0 1531 5029 0 0 0 6560 0
liburl-85cbd9ea3b680d28. 0 0 230 120 0 0 0 350 0
liburl-85cbd9ea3b680d28. 0 0 0 21 0 0 0 21 0
liburl-85cbd9ea3b680d28. 0 0 173 341 0 0 0 514 0
It looks like idf_size
is analyzing the Rust crates as well. Complete text output is here:
idf_size --files rust-std-hello.txt
idf_size
also allows to save the memory statistics as json file with --json
and -o OUT_FILE
arguments.
Regarding the RuntimeError: Target not detected
I tried the --target
argument for the esp32-hal
project but it didn't resolve the problem with target chip detection. However, I found that https://github.com/ivmarkov/rust-esp32-std-hello has some additional generated lines, which https://github.com/esp-rs/esp32-hal doesn't have in Linker script and memory map section in the map file:
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/lib/no-rtti/crt0.o
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crti.o
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtbegin.o
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/lib/no-rtti/libm.a
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/libgcc.a
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/lib/no-rtti/libstdc++.a
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/libgcov.a
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/lib/no-rtti/libc.a
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtend.o
LOAD /home/juraj/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/no-rtti/crtn.o
If there is just one of these platformio/packages/toolchain-xtensa32/....
, the detect_target_chip()
and idf_size
works fine, otherwise it ends with RuntimeError: Target not detected
just like esp32-hal
example.
Next steps:
esp-idf
based projects. rust
project but only bin
, dylib
and cdylib
crate types are supported.
Story: As a user, I'd like to know footprint of a create used in my project, so that I can decide whether to use the crate or not in my embedded project.
With Rust it's easy to add dependency like std or some crate. The embedded devices has limited resources and it's important to identify impact of adding a big crate. Adding big dependency might generate application which is not possible to deploy.
Explore and identify methods for measuring footprint of the code / Rust library. Dimensions to consider: memory consumption, storage space.
@JurajSadel PTAL