-
-
Notifications
You must be signed in to change notification settings - Fork 655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Investigate how to save flash space #1947
Comments
We can save some space by compressing the embedded bootloader (using the same method as we do for TOIF): >>> from trezorlib.toif import _compress
>>> d = open("bootloader.bin","rb").read()
>>> c = _compress(d)
>>> len(d)
94208
>>> len(c)
61366 This will save us around 33KB of Flash space, but increases the complexity of critical part of the firmware - updating the bootloader. |
I experimented with |
As agreed with @matejcik and @mmilata, I am adding my small research into the flash space problem. Main goal is to determine how much space does the So far I was analyzing only Without very much knowledge about it, I found the nm command, which shows statistics about our emulator file ... Example output showing the biggest >>> nm --radix=dec --size-sort -r build/unix/trezor-emu-core | grep trezor_lib | head
0000000000001056 t _ZN10trezor_lib8protobuf6encode7Encoder12encode_field17h0c2e867b86c32001E
0000000000001056 t _ZN10trezor_lib8protobuf6decode7Decoder19message_from_stream17h4bb4c11a91701f11E
0000000000000972 t _ZN10trezor_lib8protobuf6encode7Encoder12encode_field17hd93211b0080da8c9E
0000000000000877 t _ZN10trezor_lib8protobuf6decode7Decoder12decode_field17h9001d46bd02924c3E
0000000000000789 t _ZN10trezor_lib13storagedevice15recovery_shares33storagerecoveryshares_fetch_group17h398d0865cc93c90dE
0000000000000771 t _ZN10trezor_lib13storagedevice14storage_device27storagedevice_get_device_id17h32ffd1bd4f49a0a5E
0000000000000762 t _ZN10trezor_lib13storagedevice14storage_device33storagedevice_set_mnemonic_secret17he01f740c7cf66eefE
0000000000000652 t _ZN10trezor_lib8protobuf3obj12msg_obj_attr17h33d14d544c65bc45E
0000000000000547 t _ZN10trezor_lib8protobuf6decode7Decoder20decode_defaults_into17h4a0faec11a9c7b1fE
0000000000000486 t _ZN10trezor_lib8protobuf6encode7Encoder14encode_message17h3fe64bdc4994692cE To get user-friendly results out of it, I made a small script parsing the Rust function information, comparing the results etc.: https://gist.github.com/grdddj/b2cc8846e3f76608a8f6d948b6f1b0f9 (it needs some manual changes before running, to setup binary locations and the build command) Example output from this script, looking at all >>> python get_function_size_from_binary.py --no-compare
...
486: protobuf :: encode :: Encoder :: encode_message (1)
547: protobuf :: decode :: Decoder :: decode_defaults_into
652: protobuf :: obj :: msg_obj_attr
762: storagedevice :: storage_device :: storagedevice_set_mnemonic_secret
771: storagedevice :: storage_device :: storagedevice_get_device_id
789: storagedevice :: recovery_shares :: storagerecoveryshares_fetch_group
877: protobuf :: decode :: Decoder :: decode_field
972: protobuf :: encode :: Encoder :: encode_field
1056: protobuf :: decode :: Decoder :: message_from_stream
1056: protobuf :: encode :: Encoder :: encode_field (1)
27448: total
234: total_amount This shows that there is around Running the script for everything (not just
which means there is almost Conclusion: |
Running (could be replicated by passing
|
For the same space-issue I cannot From these unsuccessful builds only |
I continued with analyzing Helper script for analysis is at https://gist.github.com/grdddj/5aeb38f17713f038639dde1c667dbd21 Notable results and examples: >>> python get_apps_size_from_binary.py --statistics
...
11_876: apps/stellar
11_987: trezor/crypto
14_849: apps/nem
20_187: apps/management
27_881: apps/webauthn
29_693: apps/common
35_966: apps/cardano
59_706: apps/bitcoin
59_985: trezor/ui
63_002: apps/monero
101_749: apps/ethereum
516_077: total >>> python get_apps_size_from_binary.py --lines
...
1092: core/src/apps/webauthn/fido2.py
1098: core/src/apps/monero/signing/step_09_sign_input.py:28 ... sign_input (1)
1175: core/src/apps/monero/xmr/mlsag.py:342 ... _generate_clsag
1371: core/src/apps/webauthn/knownapps.py:20 ... by_rp_id_hash
1379: core/src/trezor/ui/layouts/tt/__init__.py
1392: mp_frozen_mpy_content
1493: core/src/trezor/enums/MessageType.py
1691: core/src/apps/cardano/sign_tx.py
2378: core/src/apps/monero/xmr/bulletproof.py:1509 ... BulletProofBuilder.verify_batch (1) (1)
7176: core/src/apps/ethereum/networks.py:44 ... _networks_iterator
7561: core/src/all_modules.py
8092: core/src/apps/ethereum/tokens.py:14 ... token_by_chain_address - CONST_TABLE_DATA (SPECIAL)
8361: core/src/apps/common/coininfo.py:92 ... by_name
10241: mp_frozen_mpy_names
27184: mp_qstr_frozen_const_pool
37077: core/src/apps/ethereum/tokens.py:14 ... token_by_chain_address
555386: total
13369: total_amount >>> python get_apps_size_from_binary.py --app ethereum --lines
...
304: core/src/apps/ethereum/sign_tx_eip1559.py
305: core/src/apps/ethereum/sign_tx.py
368: core/src/apps/ethereum/sign_typed_data.py:443 ... validate_field_type
406: core/src/apps/ethereum/layout.py
427: core/src/apps/ethereum/sign_typed_data.py
428: core/src/apps/ethereum/networks.py:44 ... _networks_iterator - CONST_TABLE_DATA (SPECIAL)
451: core/src/apps/ethereum/sign_tx_eip1559.py:55 ... sign_tx_eip1559
455: core/src/apps/ethereum/sign_tx.py:35 ... sign_tx
650: core/src/apps/ethereum/sign_typed_data.py:227 ... TypedDataEnvelope.get_and_encode_data
7176: core/src/apps/ethereum/networks.py:44 ... _networks_iterator
8092: core/src/apps/ethereum/tokens.py:14 ... token_by_chain_address - CONST_TABLE_DATA (SPECIAL)
37077: core/src/apps/ethereum/tokens.py:14 ... token_by_chain_address
101749: total
2493: total_amount >>> python get_apps_size_from_binary.py --file-name ethereum/sign_typed_data.py --lines
...
81: core/src/apps/ethereum/sign_typed_data.py:392 ... write_leftpad32
119: core/src/apps/ethereum/sign_typed_data.py:204 ... TypedDataEnvelope.find_typed_dependencies
121: core/src/apps/ethereum/sign_typed_data.py:183 ... TypedDataEnvelope.encode_type (1)
125: core/src/apps/ethereum/sign_typed_data.py:41 ... sign_typed_data
126: core/src/apps/ethereum/sign_typed_data.py:516 ... get_name_and_version_for_domain
148: core/src/apps/ethereum/sign_typed_data.py:141 ... TypedDataEnvelope._collect_types
173: core/src/apps/ethereum/sign_typed_data.py:350 ... encode_field
230: core/src/apps/ethereum/sign_typed_data.py:414 ... validate_value
234: core/src/apps/ethereum/sign_typed_data.py:61 ... generate_typed_data_hash
368: core/src/apps/ethereum/sign_typed_data.py:443 ... validate_field_type
427: core/src/apps/ethereum/sign_typed_data.py
650: core/src/apps/ethereum/sign_typed_data.py:227 ... TypedDataEnvelope.get_and_encode_data
4428: total
94: total_amount >>> python get_apps_size_from_binary.py --grep trezor_ui --lines
...
415: core/src/trezor/ui/components/tt/scroll.py:352 ... paginate_paragraphs
428: core/src/trezor/ui/layouts/tt/reset.py:26 ... show_share_words
431: core/src/trezor/ui/components/tt/passphrase.py
447: core/src/trezor/ui/layouts/tt/__init__.py:794 ... confirm_properties (1)
458: core/src/trezor/ui/layouts/tt/__init__.py:617 ... confirm_blob (1) (1)
533: core/src/trezor/ui/components/tt/scroll.py
537: core/src/trezor/ui/__init__.py
657: core/src/trezor/ui/style.py
662: core/src/trezor/ui/components/common/text.py:180 ... render_text
809: core/src/trezor/ui/components/tt/reset.py:42 ... Slip39NumInput.on_render
1379: core/src/trezor/ui/layouts/tt/__init__.py
59985: total
1556: total_amount There could be a lot of conclusions from this, I would note the size of |
We can save 12KiB by using different implementation of blake2b. The reference implementation we use does some manual inlining that can be turned into loop, slowing the function down somewhat. This one doesn't use such inlining. |
Two observations: The Clang compiler has significant problems to optimize the blake2b/blake2s code if compiler sanitizers are present, up to the point of crashing during compilation, see here. GCC, which is used for the firmware builds does not have these apparent issues, and the issues in clang only show up in the presence of sanitizers, but it's possible that the compilers produces sub-standard results in other ways even during "normal" builds. It may be helpful to experiment with |
it appears that a lot of debug dump functionality from Rust is getting into the builds. we might want to keep an eye on that. things that seemed to help locally:
more generally, we need to watch for the presence of these things in the binaries. Another thing to work on is some sort of dependency tracker for included symbols. This is more important for the bootloader usecase, where just plain including Rust costs us over 10 kB of space. Using One more thing to watch out for is generic instance explosion -- code that is succinct in Rust might end up generating a lot of needless repetitions in the binary. A thing we should investigate: whenever const generics are used (such as |
Investigated a bit and it appears that all generic parameters get monomorphized, including consts. Assembly output seems to confirm this. So I'd consider de-constifying the parameter. |
For issue-tracking purposes, mentioning that there is an open PR with the tool generating the size statistics of We agreed to keep this issue open with low priority for next sprints. |
Summary of ideas to increase available flash memory:
|
We are now doing reasonably well on flash space. This issue is not actionable and once we dump all relevant info into Notion we will close it. |
We are slowly running out of Flash space. Let's collect some ideas how to save it:
The greatest offenders (generated by
bloaty -d sections,symbols build/firmware/firmware.elf
)The text was updated successfully, but these errors were encountered: