Swap buffer write and flush check in stdio_buffered_printer (saves 10 cyc/char) #3054

Merged
Wren6991 merged 1 commit from buffered-printer-speedup into develop 2026-07-02 08:06:24 -05:00
Wren6991 commented 2026-07-02 06:31:50 -05:00 (Migrated from github.com)

We use raw SDK printf() in a lot of sim testcases. I was looking into why it's slow and a lot of time is actually spent repeatedly calling stdio_buffered_printer() (once per char, outline call through function pointer, from tight loop inside vfctprintf()).

The printf integration is quite involved, so to improve things somewhat without getting into the weeds, this patch swaps the buffer write and the flush check in stdio_buffered_printer() to get better codegen for the common case of writing to a non-full buffer.

Original disasm, arm-gnu-toolchain-15.2.rel1 with default SDK flags:

20002dd4 <stdio_buffered_printer>:
20002dd4:	b570      	push	{r4, r5, r6, lr}
20002dd6:	680b      	ldr	r3, [r1, #0]
20002dd8:	460c      	mov	r4, r1
20002dda:	2b80      	cmp	r3, #128	@ 0x80
20002ddc:	4605      	mov	r5, r0
20002dde:	b082      	sub	sp, #8
20002de0:	d005      	beq.n	20002dee <stdio_buffered_printer+0x1a>
20002de2:	1c5a      	adds	r2, r3, #1
20002de4:	4423      	add	r3, r4
20002de6:	6022      	str	r2, [r4, #0]
20002de8:	711d      	strb	r5, [r3, #4]
20002dea:	b002      	add	sp, #8
20002dec:	bd70      	pop	{r4, r5, r6, pc}     <- common case exits HERE
... handle flush

With this change:


20002dd4 <stdio_buffered_printer>:
20002dd4:	680b      	ldr	r3, [r1, #0]
20002dd6:	1c5a      	adds	r2, r3, #1
20002dd8:	2a80      	cmp	r2, #128	@ 0x80
20002dda:	440b      	add	r3, r1
20002ddc:	600a      	str	r2, [r1, #0]
20002dde:	7118      	strb	r0, [r3, #4]
20002de0:	d000      	beq.n	20002de4 <stdio_buffered_printer+0x10>
20002de2:	4770      	bx	lr   <- common case exits HERE
... handle flush

Original code has to setup a stack frame and save its args over the outline calls inside of the flush. New code doesn't have to do this, so saves 10 cycles per character.

Correctness: I added a comment with an argument for why this swap is safe. There are currently no other users of the stack buffer struct as far as I could tell.

We use raw SDK `printf()` in a lot of sim testcases. I was looking into why it's slow and a lot of time is actually spent repeatedly calling `stdio_buffered_printer()` (once per char, outline call through function pointer, from tight loop inside `vfctprintf()`). The printf integration is quite involved, so to improve things somewhat without getting into the weeds, this patch swaps the buffer write and the flush check in `stdio_buffered_printer()` to get better codegen for the common case of writing to a non-full buffer. Original disasm, `arm-gnu-toolchain-15.2.rel1` with default SDK flags: ``` 20002dd4 <stdio_buffered_printer>: 20002dd4: b570 push {r4, r5, r6, lr} 20002dd6: 680b ldr r3, [r1, #0] 20002dd8: 460c mov r4, r1 20002dda: 2b80 cmp r3, #128 @ 0x80 20002ddc: 4605 mov r5, r0 20002dde: b082 sub sp, #8 20002de0: d005 beq.n 20002dee <stdio_buffered_printer+0x1a> 20002de2: 1c5a adds r2, r3, #1 20002de4: 4423 add r3, r4 20002de6: 6022 str r2, [r4, #0] 20002de8: 711d strb r5, [r3, #4] 20002dea: b002 add sp, #8 20002dec: bd70 pop {r4, r5, r6, pc} <- common case exits HERE ... handle flush ``` With this change: ``` 20002dd4 <stdio_buffered_printer>: 20002dd4: 680b ldr r3, [r1, #0] 20002dd6: 1c5a adds r2, r3, #1 20002dd8: 2a80 cmp r2, #128 @ 0x80 20002dda: 440b add r3, r1 20002ddc: 600a str r2, [r1, #0] 20002dde: 7118 strb r0, [r3, #4] 20002de0: d000 beq.n 20002de4 <stdio_buffered_printer+0x10> 20002de2: 4770 bx lr <- common case exits HERE ... handle flush ``` Original code has to setup a stack frame and save its args over the outline calls inside of the flush. New code doesn't have to do this, so saves 10 cycles per character. Correctness: I added a comment with an argument for why this swap is safe. There are *currently* no other users of the stack buffer struct as far as I could tell.
kilograham (Migrated from github.com) approved these changes 2026-07-02 08:06:17 -05:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk!3054
No description provided.