Skip to content

Conversation

ivmarkov
Copy link
Contributor

@ivmarkov ivmarkov commented Sep 14, 2024

This is a rather large PR, so let me explain what is going on here:

The TLV improvements introduced here can be classified in five main areas (listed in order of importance):

1. Shorten TLVElement (and related types) from 40 bytes to 8 bytes (32 bit archs) or 16 bytes (64 bit archs)

While it might look like a minimal gain, let's not forget that the size of individual TLV elements can quickly add-up in structure size. Take the IM structure ReadReq for example:

  • 4 of its 5 members are TLVArrays (and thus have a hidden TLVElement)
  • Structure size currently: 168 bytes; after this change: 72 bytes (64bit arch) and almost 2x less for 32 bits arch
  • Ditto for WriteReq, InvokeReq etc.

Worst offender: Cert

  • Currently 648 bytes (!!) for 64 bit archs (bigger than the TLV bytes' payload of a TLV-encoded Matter certificate!!)
  • After the change (with CertRef though, read on): 16 bytes (or even 8 for 32 bit archs)

How?

We get smaller memory size by delaying computations.

After this PR TLVElement is simply a newtype over &[u8]. All parsing is done post-creation of the TLVElement, when its various methods are invoked.

Would that have any performance implications on an MCU?

  • I haven't seen any. While I've tested only with the Espressif ones, I don't expect Cortex ones to be any slower.

Note that the same size reduction is now applicable for container types which also before were just wrappers over TLVElement: like TLVContainer and its concrete instantiations TLVArray, TLVList and TLVStructure.

2. Support for on-the-fly TLV structures (newtypes over TLVElement)

Bringing the "delay the TLV computations" idea to the extreme gives us TLV structures which are also just newtype wrappers over TLVElement (and are thus only 16 / 8 bytes in size):

  • E.g. compare IM ReadReq with the new ReadReqRef
  • E.g. compare IM WriteReq with the new WriteReqRef
  • E.g. compare the (no longer existing Cert) with CertRef

The FromTLV / ToTLV proc-macros are extended to support these "on-the-fly" TLV structures.
Granted, these structures are not "self-descriptive" as the existing ones, so the user has to manually implement their fields in the form of methods. The question is though, would that be a big issue once we have the IDL framework generating these structures (and their methods) from IDL? Probably not.

3. FromTLV extended to support an extra method - init_from_tlv

This is one application of the new "in-place-init" from the previous PR.

This is useful when e.g. de-serializing "owned" large objects, like Fabric from a TLV byte-slice, at it allows the TLV byte-slice to be converted to the Fabric struct directly in-place, without first materializing the Fabric struct on-stack, and only then copying it to the final Vec of fabrics.

4. ToTLV extended to support an extra method - to_tlv_iter

This extra method allow the TLV stream to be consumed not by supplying a TLV "writer", but "iterator style", as a sequence of bytes.

Its usage is currently limited and - as its documentation says - it should be used with care, because the resulting iterator - which is really generated as a monadic combination of map, flat_map etc. can grow big real quick, thus rendering the whole "iterator based" approach less efficient (w.r.t. memory consumption!) than just using a buffer and serializing in there.

5. While at it: ToTLV::to_tlv generified over W: TLVWrite

TLVWriter is still there for backwards compatibility, but now the user can plug anything that implements TLVWrite as the TLV serialization target. Including e.g. a WriteBuf without wrapping it with a TLVWriter.

Scope of changes:

  • Module crate::tlv is completely redesigned in that I've tried to split the code into smaller modules, and properly document the complete API
  • I've introduced a number of type aliases for backwards compatibility, like OctetStr = Octets, Utf8Str = &str, ElementType = TLVValue, TagType = TLVTag and so on

I also re-desgned the so called ImEngine by renaming it (and its modules) to E2E as we can use this module not just for IM tests in future, as it actually is no longer IM-specific.

I do realize that there's the ChipTool Python XML E2E tests too (and I'm btw working on getting these to run against rs-matter) - yet - our E2E tests are much, much faster, as they are essentially executed as in-process unit tests, so I'm not sure these don't have a future.

Copy link

semanticdiff-com bot commented Sep 14, 2024

Review changes with SemanticDiff.

Analyzed 46 of 74 files.

Overall, the semantic diff is 33% smaller than the GitHub diff.

File Information
Filename Status
✔️ tools/tlv/src/main.rs Analyzed
✔️ rs-matter-macros-impl/src/tlv.rs 38.06% smaller
rs-matter/Cargo.toml Unsupported file format
✔️ rs-matter/tests/data_model_tests.rs 21.53% smaller
✔️ rs-matter/tests/tlv_encoding.rs 42.58% smaller
✔️ rs-matter/tests/data_model/acl_and_dataver.rs 40.17% smaller
✔️ rs-matter/tests/data_model/attribute_lists.rs 60.07% smaller
✔️ rs-matter/tests/data_model/attributes.rs 57.64% smaller
✔️ rs-matter/tests/data_model/commands.rs 14.49% smaller
✔️ rs-matter/tests/data_model/long_reads.rs 67.5% smaller
rs-matter/tests/data_model/mod.rs Unsupported file format
✔️ rs-matter/tests/data_model/timed_requests.rs 6.68% smaller
rs-matter/tests/common/commands.rs Unsupported file format
rs-matter/tests/common/e2e.rs Unsupported file format
rs-matter/tests/common/handlers.rs Unsupported file format
✔️ rs-matter/tests/common/mod.rs 20.39% smaller
rs-matter/tests/common/e2e/im.rs Unsupported file format
rs-matter/tests/common/e2e/test.rs Unsupported file format
rs-matter/tests/common/e2e/tlv.rs Unsupported file format
rs-matter/tests/common/e2e/im/attributes.rs Unsupported file format
rs-matter/tests/common/e2e/im/commands.rs Unsupported file format
✔️ rs-matter/tests/common/e2e/im/echo_cluster.rs 32.28% smaller
rs-matter/tests/common/e2e/im/handler.rs Unsupported file format
✔️ rs-matter/src/acl.rs 32.9% smaller
✔️ rs-matter/src/fabric.rs 30.93% smaller
✔️ rs-matter/src/group_keys.rs Analyzed
✔️ rs-matter/src/lib.rs Analyzed
rs-matter/src/tlv.rs Unsupported file format
✔️ rs-matter/src/utils/init.rs Analyzed
rs-matter/src/utils/iter.rs Unsupported file format
✔️ rs-matter/src/utils/mod.rs Analyzed
✔️ rs-matter/src/utils/storage/writebuf.rs 0.36% smaller
✔️ rs-matter/src/transport/core.rs Analyzed
rs-matter/src/tlv/mod.rs Unsupported file format
rs-matter/src/tlv/parser.rs Unsupported file format
rs-matter/src/tlv/read.rs Unsupported file format
rs-matter/src/tlv/toiter.rs Unsupported file format
✔️ rs-matter/src/tlv/traits.rs 9.03% smaller
rs-matter/src/tlv/write.rs Unsupported file format
rs-matter/src/tlv/writer.rs Unsupported file format
rs-matter/src/tlv/traits/array.rs Unsupported file format
rs-matter/src/tlv/traits/bitflags.rs Unsupported file format
rs-matter/src/tlv/traits/container.rs Unsupported file format
rs-matter/src/tlv/traits/maybe.rs Unsupported file format
rs-matter/src/tlv/traits/octets.rs Unsupported file format
rs-matter/src/tlv/traits/primitive.rs Unsupported file format
rs-matter/src/tlv/traits/slice.rs Unsupported file format
rs-matter/src/tlv/traits/str.rs Unsupported file format
rs-matter/src/tlv/traits/vec.rs Unsupported file format
✔️ rs-matter/src/secure_channel/case.rs 46.14% smaller
✔️ rs-matter/src/secure_channel/core.rs 4.76% smaller
✔️ rs-matter/src/secure_channel/pake.rs 30.02% smaller
✔️ rs-matter/src/pairing/mod.rs 64.75% smaller
✔️ rs-matter/src/pairing/qr.rs 25.63% smaller
✔️ rs-matter/src/interaction_model/core.rs 25.7% smaller
✔️ rs-matter/src/interaction_model/messages.rs 7.5% smaller
✔️ rs-matter/src/data_model/core.rs 44.73% smaller
✔️ rs-matter/src/data_model/system_model/access_control.rs 57.25% smaller
✔️ rs-matter/src/data_model/system_model/descriptor.rs 34.73% smaller
✔️ rs-matter/src/data_model/sdm/admin_commissioning.rs 78.57% smaller
✔️ rs-matter/src/data_model/sdm/dev_att.rs 12.02% smaller
✔️ rs-matter/src/data_model/sdm/general_commissioning.rs 32.46% smaller
✔️ rs-matter/src/data_model/sdm/noc.rs 27.24% smaller
✔️ rs-matter/src/data_model/sdm/nw_commissioning.rs 25.03% smaller
✔️ rs-matter/src/data_model/sdm/wifi_nw_diagnostics.rs Analyzed
✔️ rs-matter/src/data_model/objects/cluster.rs 36.02% smaller
✔️ rs-matter/src/data_model/objects/encoder.rs 1.76% smaller
✔️ rs-matter/src/data_model/objects/node.rs Analyzed
✔️ rs-matter/src/data_model/objects/privilege.rs 13.78% smaller
✔️ rs-matter/src/crypto/crypto_rustcrypto.rs 50.05% smaller
✔️ rs-matter/src/crypto/mod.rs 39.62% smaller
✔️ rs-matter/src/cert/mod.rs 51.22% smaller
✔️ examples/onoff_light_bt/src/comm.rs 65.05% smaller
✔️ examples/onoff_light/src/main.rs Analyzed

@ivmarkov
Copy link
Contributor Author

CI should be fine now.

@ivmarkov ivmarkov merged commit 93d2082 into project-chip:main Sep 17, 2024
12 checks passed
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.

2 participants