4 ms·
If you're asking why do coroutines exist, it's because context switching in kernel space and synchronization have very high overhead by comparison. You use thos
by Conscat 3y ago
If you're asking why do coroutines exist, it's because context switching in kernel space and synchronization have very high overhead by comparison. You use those features when you want parallelism, not concurrency.
For parallelism, you also usually want a userspace task scheduler because simply spawning threads in kernelspace is much slower. Cilk and Go provide this built into their language runtime.
- kevin_thibedeau 3y agoContext switches on Cortex-M are relatively cheap with optimizations to limit the amount of data that has to be stacked.
- lmm 3y agoRelative to what? They might be cheaper than some architectures, but they're still a hell of a lot more expensive than not doing them.
- kragen 3y agowe seem to be talking about cooperative multitasking here correct me if i'm wrong, but i think that even with an almost standard abi it's five instructions and 27 cortex-m3 clock cycles; here we reserve r10 for the current task pointer (with the bonus that you can use it for a tls base register) and round-robin among the tasks in a circularly linked list: yield: push {r4-r9, r11, lr} @ save all callee-saved regs except r10 str sp, [r10], #4 @ save stack pointer in current task ldr r10, [r10] @ load pointer to next task ldr sp, [r10] @ switch to next task's stack pop {r4-r9, r11, pc} @ return into yielded context there i think in gcc that's more or less -mpic-register=r10 -msingle-pic-base, though that isn't what those options are meant for if you're willing and able to deform the abi a little by having less callee-saved registers, something you might want to do anyway for efficiency, you can cut r4-r9 down to r4-r5 and shave that down to i think 19 clocks? if you're willing to eliminate callee-saved registers entirely you can get to 15, but that seems like a heavy price to pay if you have to use the standard abi it's i think 37 clocks on a cortex-m3 or better: yield: push {r4-r12, lr} ldr r9, =current_task_pointer ldr r10, [r9] str sp, [r10], #4 ldr r10, [r10] str r10, [r9] ldr sp, [r10] pop {r4-r12, pc} i feel like something in the range of 20-40 clocks is really not that expensive? i mean an ldr or str is 3 or 4 clocks if it's not accessing tcm, right? and on cortex-m0 every taken branch is 3 clocks because you don't have branch prediction? i mean it's not going to compete with barrel processors on context switch time, but if it's really the cost of accessing seven fields of structs on the heap, it hardly seems like it's "a hell of a lot more expensive" than even zero if we're talking about preemptive context switching, that's a different ball of wax; you have to save all the registers that you use at all, not just callee-saved registers, and depending on your application maybe vfp registers as well as integer registers
- kragen 3y agoi should clarify that while i have tested both of these context-switching subroutines, and they do seem to work in simple programs, i haven't tested them on actual cortex-m hardware, much less measured their real-world performance