Skip to content
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

Need "lighter weight" ETL_ASSERT #993

Open
pwsoftwaredesigns opened this issue Dec 13, 2024 · 11 comments
Open

Need "lighter weight" ETL_ASSERT #993

pwsoftwaredesigns opened this issue Dec 13, 2024 · 11 comments

Comments

@pwsoftwaredesigns
Copy link

I am using ETL on an MCU with a decently small flash size (64KB). I have bee digging through the compiler MAP file to decrease the size as much as possible for my debug build. I still want to have minimal optimization (achieved by -Og) and still have some form of assert

During my investigation, I cam across a whole chunk of functions that were larger than I expected. Looking into the list file (annotated assembly output), I found (one of many as an example) the following that uses an ETL data structure (a variant_pool in this case):

08001b10 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)>:
 8001b10:	b570      	push	{r4, r5, r6, lr}
 8001b12:	b084      	sub	sp, #16
 8001b14:	0004      	movs	r4, r0
 8001b16:	000d      	movs	r5, r1
class ETemp3: public ::tw::hsm::Event<ETemp3>
 8001b18:	4b38      	ldr	r3, [pc, #224]	; (8001bfc <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xec>)
 8001b1a:	610b      	str	r3, [r1, #16]
 8001b1c:	4b38      	ldr	r3, [pc, #224]	; (8001c00 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xf0>)
 8001b1e:	610b      	str	r3, [r1, #16]
 8001b20:	4b38      	ldr	r3, [pc, #224]	; (8001c04 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xf4>)
 8001b22:	610b      	str	r3, [r1, #16]
      intptr_t distance = p - p_buffer;
 8001b24:	6803      	ldr	r3, [r0, #0]
 8001b26:	1ac8      	subs	r0, r1, r3
      bool is_within_range = (distance >= 0) && (distance <= intptr_t((Item_Size * Max_Size) - Item_Size));
 8001b28:	d407      	bmi.n	8001b3a <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x2a>
 8001b2a:	6963      	ldr	r3, [r4, #20]
 8001b2c:	3b01      	subs	r3, #1
 8001b2e:	6922      	ldr	r2, [r4, #16]
 8001b30:	4353      	muls	r3, r2
 8001b32:	4298      	cmp	r0, r3
 8001b34:	dd0b      	ble.n	8001b4e <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x3e>
 8001b36:	2600      	movs	r6, #0
 8001b38:	e000      	b.n	8001b3c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x2c>
 8001b3a:	2600      	movs	r6, #0
      bool is_valid_address = ((distance % Item_Size) == 0);
 8001b3c:	6921      	ldr	r1, [r4, #16]
 8001b3e:	f7fe fb69 	bl	8000214 <__aeabi_uidivmod>
      return is_within_range && is_valid_address;
 8001b42:	2e00      	cmp	r6, #0
 8001b44:	d005      	beq.n	8001b52 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x42>
 8001b46:	2900      	cmp	r1, #0
 8001b48:	d004      	beq.n	8001b54 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x44>
 8001b4a:	2600      	movs	r6, #0
 8001b4c:	e002      	b.n	8001b54 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x44>
      bool is_within_range = (distance >= 0) && (distance <= intptr_t((Item_Size * Max_Size) - Item_Size));
 8001b4e:	2601      	movs	r6, #1
 8001b50:	e7f4      	b.n	8001b3c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x2c>
      return is_within_range && is_valid_address;
 8001b52:	2600      	movs	r6, #0
      ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool));
 8001b54:	2e00      	cmp	r6, #0
 8001b56:	d00c      	beq.n	8001b72 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x62>
      if (items_allocated > 0) 
 8001b58:	68a3      	ldr	r3, [r4, #8]
 8001b5a:	2b00      	cmp	r3, #0
 8001b5c:	d02d      	beq.n	8001bba <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xaa>
        if (p_next != ETL_NULLPTR)
 8001b5e:	6863      	ldr	r3, [r4, #4]
 8001b60:	2b00      	cmp	r3, #0
 8001b62:	d027      	beq.n	8001bb4 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xa4>
          *(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next);
 8001b64:	602b      	str	r3, [r5, #0]
        p_next = p_value;
 8001b66:	6065      	str	r5, [r4, #4]
        --items_allocated;
 8001b68:	68a3      	ldr	r3, [r4, #8]
 8001b6a:	3b01      	subs	r3, #1
 8001b6c:	60a3      	str	r3, [r4, #8]
 8001b6e:	b004      	add	sp, #16
 8001b70:	bd70      	pop	{r4, r5, r6, pc}
 8001b72:	4b25      	ldr	r3, [pc, #148]	; (8001c08 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xf8>)
 8001b74:	9302      	str	r3, [sp, #8]
 8001b76:	2390      	movs	r3, #144	; 0x90
 8001b78:	33ff      	adds	r3, #255	; 0xff
 8001b7a:	9303      	str	r3, [sp, #12]
 8001b7c:	4b23      	ldr	r3, [pc, #140]	; (8001c0c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xfc>)
 8001b7e:	781b      	ldrb	r3, [r3, #0]
 8001b80:	f3bf 8f5b 	dmb	ish
 8001b84:	07db      	lsls	r3, r3, #31
 8001b86:	d508      	bpl.n	8001b9a <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x8a>
      if (invocation.stub != ETL_NULLPTR)
 8001b88:	4b21      	ldr	r3, [pc, #132]	; (8001c10 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x100>)
 8001b8a:	685b      	ldr	r3, [r3, #4]
 8001b8c:	2b00      	cmp	r3, #0
 8001b8e:	d0e3      	beq.n	8001b58 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x48>
        (*invocation.stub)(invocation.object, e);
 8001b90:	4a1f      	ldr	r2, [pc, #124]	; (8001c10 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x100>)
 8001b92:	6810      	ldr	r0, [r2, #0]
 8001b94:	a902      	add	r1, sp, #8
 8001b96:	4798      	blx	r3
 8001b98:	e7de      	b.n	8001b58 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x48>
      static invocation_element invocation;
 8001b9a:	481c      	ldr	r0, [pc, #112]	; (8001c0c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xfc>)
 8001b9c:	f009 f815 	bl	800abca <__cxa_guard_acquire>
 8001ba0:	2800      	cmp	r0, #0
 8001ba2:	d0f1      	beq.n	8001b88 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x78>
        , stub(ETL_NULLPTR)
 8001ba4:	4b1a      	ldr	r3, [pc, #104]	; (8001c10 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x100>)
 8001ba6:	2200      	movs	r2, #0
 8001ba8:	601a      	str	r2, [r3, #0]
 8001baa:	605a      	str	r2, [r3, #4]
      static invocation_element invocation;
 8001bac:	4817      	ldr	r0, [pc, #92]	; (8001c0c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xfc>)
 8001bae:	f009 f819 	bl	800abe4 <__cxa_guard_release>
 8001bb2:	e7e9      	b.n	8001b88 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x78>
          *((uintptr_t*)p_value) = 0;
 8001bb4:	2300      	movs	r3, #0
 8001bb6:	602b      	str	r3, [r5, #0]
 8001bb8:	e7d5      	b.n	8001b66 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x56>
 8001bba:	4b16      	ldr	r3, [pc, #88]	; (8001c14 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x104>)
 8001bbc:	9300      	str	r3, [sp, #0]
 8001bbe:	23d2      	movs	r3, #210	; 0xd2
 8001bc0:	005b      	lsls	r3, r3, #1
 8001bc2:	9301      	str	r3, [sp, #4]
 8001bc4:	4b11      	ldr	r3, [pc, #68]	; (8001c0c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xfc>)
 8001bc6:	781b      	ldrb	r3, [r3, #0]
 8001bc8:	f3bf 8f5b 	dmb	ish
 8001bcc:	07db      	lsls	r3, r3, #31
 8001bce:	d508      	bpl.n	8001be2 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xd2>
      if (invocation.stub != ETL_NULLPTR)
 8001bd0:	4b0f      	ldr	r3, [pc, #60]	; (8001c10 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x100>)
 8001bd2:	685b      	ldr	r3, [r3, #4]
 8001bd4:	2b00      	cmp	r3, #0
 8001bd6:	d0ca      	beq.n	8001b6e <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x5e>
        (*invocation.stub)(invocation.object, e);
 8001bd8:	4a0d      	ldr	r2, [pc, #52]	; (8001c10 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x100>)
 8001bda:	6810      	ldr	r0, [r2, #0]
 8001bdc:	4669      	mov	r1, sp
 8001bde:	4798      	blx	r3
 8001be0:	e7c5      	b.n	8001b6e <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x5e>
      static invocation_element invocation;
 8001be2:	480a      	ldr	r0, [pc, #40]	; (8001c0c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xfc>)
 8001be4:	f008 fff1 	bl	800abca <__cxa_guard_acquire>
 8001be8:	2800      	cmp	r0, #0
 8001bea:	d0f1      	beq.n	8001bd0 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xc0>
        , stub(ETL_NULLPTR)
 8001bec:	4b08      	ldr	r3, [pc, #32]	; (8001c10 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x100>)
 8001bee:	2200      	movs	r2, #0
 8001bf0:	601a      	str	r2, [r3, #0]
 8001bf2:	605a      	str	r2, [r3, #4]
      static invocation_element invocation;
 8001bf4:	4805      	ldr	r0, [pc, #20]	; (8001c0c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xfc>)
 8001bf6:	f008 fff5 	bl	800abe4 <__cxa_guard_release>
 8001bfa:	e7e9      	b.n	8001bd0 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0xc0>
 8001bfc:	0800b22c 	.word	0x0800b22c
 8001c00:	0800b218 	.word	0x0800b218
 8001c04:	0800b0b8 	.word	0x0800b0b8
 8001c08:	0800b0a4 	.word	0x0800b0a4
 8001c0c:	20000090 	.word	0x20000090
 8001c10:	20000094 	.word	0x20000094
 8001c14:	0800b0a8 	.word	0x0800b0a8

My main concern is the last part of this code which has a lot of references to invocation_element, invocation.stub, etc. Upon further investigation, I discovered that this is related to how ETL implements ETL_ASSERT.

Reading through the documentation on ETL's error handling here: https://www.etlcpp.com/error_handler.html and here: https://www.etlcpp.com/macros.html, I determine that, if I am not using exceptions nor the C standard assert macro, I want to use ETL_LOG_ERRORS.

However, if looks like the implementation of error logging is what generates all this extra code.

So, my question is, is there a way (or can there by a way) to implement a lightweight assert for ETL?

For example, in most of my code, I defined my own assert macro like so:

#define MY_ASSERT(x) if (!(x)) { assert_function(); }

You don't get much debugging information, but I tend to use the debugger to back trace where an assert occurred.

@jwellbelove
Copy link
Contributor

The invocation element is static and there should be only one in existence for the whole application.

It is accessed within the error handler via a static member function.

static invocation_element& get_invocation_element()
{
  static invocation_element invocation;

  return invocation;
}

The invocation code in etl::error_handler is a much cut-down version of what goes on inside of etl::delegate.

@jwellbelove
Copy link
Contributor

For example, in most of my code, I defined my own assert macro like so:
#define MY_ASSERT(x) if (!(x)) { assert_function(); }

We would need to define a standard 'assert_function' name for this to work with the syntax of ETL_ASSERT.

@jwellbelove
Copy link
Contributor

jwellbelove commented Dec 14, 2024

Or require a macro to be defined by the user?

#define ETL_ASSERT_FUNCTION(e) my_assert_function((e))

Then have an option for the macros in error_handler.h that defines this.

#define ETL_ASSERT(b, e) {if(!(b)) {ETL_ASSERT_FUNCTION((e));}}
etc.

@jwellbelove
Copy link
Contributor

I've just remembered that the error handler (which contains static invocation_element invocation;) is not defined unless ETL_LOG_ERRORS is defined.

@pwsoftwaredesigns
Copy link
Author

Or require a macro to be defined by the user?

#define ETL_ASSERT_FUNCTION(e) my_assert_function((e))

Then have an option for the macros in error_handler.h that defines this.

#define ETL_ASSERT(b, e) {if(!(b)) {ETL_ASSERT_FUNCTION((e));}} etc.

Perhaps it is simple as wrapping the definitions of ETL_ASSERT into a ifndef guard so that the user can optionally redefine the whole macro.

@pwsoftwaredesigns
Copy link
Author

I've just remembered that the error handler (which contains static invocation_element invocation;) is not defined unless ETL_LOG_ERRORS is defined.

For my "debug" builds I have been defining ETL_LOG_ERRORS and for my "release" builds I have been defining ETL_NO_CHECKS.

The problem comes when using ETL_LOG_ERRORS which enables ETL_ASSERT. Based upon your description of how invocation_element is implemented, I would expect places where ETL_ASSERT is used to be compiled to only a few instructions (e.g., a conditional branch and a function call), however, as you can see from the assembly I posted, the compiler seems to be inlining quite a bit of the invocation code.

Normally I wouldn't have a problem with this, except that all this code is inlined every time I call an ETL method that uses ETL_ASSERT (in this case it's when calling etl::variant_pool::destroy).

I think what I will do as an experiment is temporarily overwrite ETL_ASSERT as I have suggested to see if that truly has an effect on the overall code size.

@pwsoftwaredesigns
Copy link
Author

This is slightly off topic but still related.

It looks as if (in my example) the compiler chooses to inline ipool::release_item (and ipool::is_item_in_pool). I believe it chooses to do this because all the methods in ipool are defined inline in the class declaration (I have seen this often in my own code). Since this function is called quite often and it is not a trivial function, it gets inlined quite often, thus leading to bloated code size. But, it's not templated so there's no reason there can't be a single definition and a branch instead of inlining.

@pwsoftwaredesigns
Copy link
Author

pwsoftwaredesigns commented Dec 20, 2024

For my tests, I added the following lines to the bottom of error_handler.h:

#undef ETL_ASSERT
#undef ETL_ASSERT_FAIL

#include <tw/assert.h>
#define ETL_ASSERT(b, e) TW_ASSERT(b)
#define ETL_ASSERT_FAIL(e) TW_ASSERT(false)

TW_ASSERT is the suggested "simple" assert macro I alluded to that simple is an if statement that calls a static/free function.

After compiling, here is the assembly for the same function I showed in my original question:

08001854 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)>:
 8001854:	b570      	push	{r4, r5, r6, lr}
 8001856:	0004      	movs	r4, r0
 8001858:	000d      	movs	r5, r1
class ETemp3: public ::tw::hsm::Event<ETemp3>
 800185a:	4b1a      	ldr	r3, [pc, #104]	; (80018c4 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x70>)
 800185c:	610b      	str	r3, [r1, #16]
 800185e:	4b1a      	ldr	r3, [pc, #104]	; (80018c8 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x74>)
 8001860:	610b      	str	r3, [r1, #16]
 8001862:	4b1a      	ldr	r3, [pc, #104]	; (80018cc <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x78>)
 8001864:	610b      	str	r3, [r1, #16]
      intptr_t distance = p - p_buffer;
 8001866:	6803      	ldr	r3, [r0, #0]
 8001868:	1ac8      	subs	r0, r1, r3
      bool is_within_range = (distance >= 0) && (distance <= intptr_t((Item_Size * Max_Size) - Item_Size));
 800186a:	d407      	bmi.n	800187c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x28>
 800186c:	6963      	ldr	r3, [r4, #20]
 800186e:	3b01      	subs	r3, #1
 8001870:	6922      	ldr	r2, [r4, #16]
 8001872:	4353      	muls	r3, r2
 8001874:	4298      	cmp	r0, r3
 8001876:	dd0b      	ble.n	8001890 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x3c>
 8001878:	2600      	movs	r6, #0
 800187a:	e000      	b.n	800187e <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x2a>
 800187c:	2600      	movs	r6, #0
      bool is_valid_address = ((distance % Item_Size) == 0);
 800187e:	6921      	ldr	r1, [r4, #16]
 8001880:	f7fe fcc8 	bl	8000214 <__aeabi_uidivmod>
      return is_within_range && is_valid_address;
 8001884:	2e00      	cmp	r6, #0
 8001886:	d005      	beq.n	8001894 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x40>
 8001888:	2900      	cmp	r1, #0
 800188a:	d004      	beq.n	8001896 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x42>
 800188c:	2600      	movs	r6, #0
 800188e:	e002      	b.n	8001896 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x42>
      bool is_within_range = (distance >= 0) && (distance <= intptr_t((Item_Size * Max_Size) - Item_Size));
 8001890:	2601      	movs	r6, #1
 8001892:	e7f4      	b.n	800187e <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x2a>
      return is_within_range && is_valid_address;
 8001894:	2600      	movs	r6, #0
      ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool));
 8001896:	2e00      	cmp	r6, #0
 8001898:	d00b      	beq.n	80018b2 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x5e>
      if (items_allocated > 0) 
 800189a:	68a3      	ldr	r3, [r4, #8]
 800189c:	2b00      	cmp	r3, #0
 800189e:	d00e      	beq.n	80018be <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x6a>
        if (p_next != ETL_NULLPTR)
 80018a0:	6863      	ldr	r3, [r4, #4]
 80018a2:	2b00      	cmp	r3, #0
 80018a4:	d008      	beq.n	80018b8 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x64>
          *(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next);
 80018a6:	602b      	str	r3, [r5, #0]
        p_next = p_value;
 80018a8:	6065      	str	r5, [r4, #4]
        --items_allocated;
 80018aa:	68a3      	ldr	r3, [r4, #8]
 80018ac:	3b01      	subs	r3, #1
 80018ae:	60a3      	str	r3, [r4, #8]
 80018b0:	bd70      	pop	{r4, r5, r6, pc}
      ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool));
 80018b2:	f007 fd89 	bl	80093c8 <doAssert>
 80018b6:	e7f0      	b.n	800189a <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x46>
          *((uintptr_t*)p_value) = 0;
 80018b8:	2300      	movs	r3, #0
 80018ba:	602b      	str	r3, [r5, #0]
 80018bc:	e7f4      	b.n	80018a8 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x54>
        ETL_ASSERT_FAIL(ETL_ERROR(pool_no_allocation));
 80018be:	f007 fd83 	bl	80093c8 <doAssert>
 80018c2:	e7f5      	b.n	80018b0 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x5c>
 80018c4:	0800a438 	.word	0x0800a438
 80018c8:	0800a424 	.word	0x0800a424
 80018cc:	0800a2c4 	.word	0x0800a2c4

The quantitative improvement for me is the final binary size. Using ETL_ASSERT as is (without exceptions but with ETL_LOG_ERRORS defined), my binary compiled to 49232 bytes. With ETL_ASSERT and ETL_ASSERT_FAIL defined as above, the binary size dropped to 44044 bytes (a decrease of ~5KB). On a chip with only 64KB of flash, this is pretty significant (and only a problem on debug builds that have all the extra error checking added in without heavy compiler optimizations enabled).

To take this one step further, if I add __attribute__((noinline)) to ipool::release_item, the binary drops even further to 42580 bytes and the assembly for the same function is:

08001558 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)>:
 8001558:	b510      	push	{r4, lr}
class ETemp3: public ::tw::hsm::Event<ETemp3>
 800155a:	4b04      	ldr	r3, [pc, #16]	; (800156c <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x14>)
 800155c:	610b      	str	r3, [r1, #16]
 800155e:	4b04      	ldr	r3, [pc, #16]	; (8001570 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x18>)
 8001560:	610b      	str	r3, [r1, #16]
 8001562:	4b04      	ldr	r3, [pc, #16]	; (8001574 <tw::SmartPool<32u, led::EExtSyncRise, led::EExtSyncFall, led::EExtSyncHeartbeat, led::ESyncStart, led::EMagnetTest, led::EStrobeSync, led::EToneSilence, led::EToneSync, led::EToneReset, led::ETimeout, led::ETemp4, led::ETemp3>::makeUnique<led::ETemp3>()::{lambda(void*, void const*)#1}::_FUN(void*, void const*)+0x1c>)
 8001564:	610b      	str	r3, [r1, #16]
 8001566:	f7ff f89d 	bl	80006a4 <etl::ipool::release_item(char*)>
 800156a:	bd10      	pop	{r4, pc}
 800156c:	08009e80 	.word	0x08009e80
 8001570:	08009e6c 	.word	0x08009e6c
 8001574:	08009d0c 	.word	0x08009d0c

@jwellbelove
Copy link
Contributor

Perhaps it is simple as wrapping the definitions of ETL_ASSERT into a ifndef guard so that the user can optionally redefine the whole macro.

There are actually six macros to redefine, which can make it a little error prone.

In my code, I added this to the macro definitions:-

#elif defined(ETL_USE_ASSERT_FUNCTION)
  #define ETL_ASSERT(b, e) {if(!(b)) {ETL_ASSERT_FUNCTION((e));}}                                 // If the condition fails, calls the assert handler
  #define ETL_ASSERT_OR_RETURN(b, e) {if(!(b)) {ETL_ASSERT_FUNCTION((e)); return;}}               // If the condition fails, calls the assert handler and return
  #define ETL_ASSERT_OR_RETURN_VALUE(b, e, v) {if(!(b)) {ETL_ASSERT_FUNCTION((e)); return (v);}}  // If the condition fails, calls the assert handler and return a value

  #define ETL_ASSERT_FAIL(e) {ETL_ASSERT_FUNCTION((e));}                                          // Calls the assert handler
  #define ETL_ASSERT_FAIL_AND_RETURN(e) {ETL_ASSERT_FUNCTION((e)); return;}                       // Calls the assert handler and return
  #define ETL_ASSERT_FAIL_AND_RETURN_VALUE(e, v) {ETL_ASSERT_FUNCTION((e)); return (v);}          // Calls the assert handler and return a value

@pwsoftwaredesigns
Copy link
Author

If ETL_USE_ASSERT_FUNCTION is added, would the ETL_ASSERT_FUNCTION then be defined in a user-provided etl_profile.h?

@jwellbelove
Copy link
Contributor

Mmm, this is not as straightforward as I first thought.

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

No branches or pull requests

2 participants