The code generated by #[derive(Debug)] uses core::fmt::DebugStruct and its siblings: DebugList, DebugMap, DebugSet, and DebugTuple. Internally, these types use &dyn fmt::Debug, and it appears that in Rust userspace apps this defeats LLVM's devirtualization. This causes most or all of the Debug implementations (including Debug implementations for types from libcore) to be compiled in.
I ran some tests on a stripped-down libtock-rs that removes all of its #[derive(Debug)] instances. In these tests, I manually derived Debug using the core::fmt::Debug* types as well as implemented it entirely manually. Here are the resulting sizes of .text (in bytes):
- DebugStruct: 15664
- DebugTuple: 15504
- DebugList: 15584
- DebugSet: 15584
- DebugMap: 16576
- Manual implementation (no Debug*): 504
Based on this test, I think it may be wise to avoid #[derive(Debug)] in libtock-rs and instead derive Debug manually. I count 12 uses of #[derive(Debug)] in libtock-rs so this seems reasonable.
Any comments before I make this change?
The code generated by
#[derive(Debug)]usescore::fmt::DebugStructand its siblings:DebugList,DebugMap,DebugSet, andDebugTuple. Internally, these types use&dyn fmt::Debug, and it appears that in Rust userspace apps this defeats LLVM's devirtualization. This causes most or all of theDebugimplementations (includingDebugimplementations for types from libcore) to be compiled in.I ran some tests on a stripped-down libtock-rs that removes all of its
#[derive(Debug)]instances. In these tests, I manually derived Debug using the core::fmt::Debug* types as well as implemented it entirely manually. Here are the resulting sizes of .text (in bytes):Based on this test, I think it may be wise to avoid
#[derive(Debug)]in libtock-rs and instead derive Debug manually. I count 12 uses of#[derive(Debug)]in libtock-rs so this seems reasonable.Any comments before I make this change?