Repository navigation
runtime: standardize meaning of procyield argument across architectures #81304
Description
The runtime's platform-independent code uses procyield when it needs to briefly delay a thread while another makes progress. It takes an argument, which it calls "cycles". It's called in lock2, casgstatus, suspendG, lfstack.pop, spanSet.pop, and internal/sync.Mutex.lockSlow.
The implementations in procyieldAsm result in very much architecture-dependent behavior:
- On GOARCH=amd64 and GOARCH=386, the
PAUSEinstruction provides delay for this purpose and when called with an argument of N, procyieldAsm will loop to execute the instruction N times. The latency of the instruction varies between microarchitectures, and even between cores in heterogenous chips. The wall-clock duration of the delay varies with the processor's current operating frequency. - Prior to CL 654895 (part of Go 1.26), the GOARCH=arm64 implementation used the
YIELDinstruction, which has meaning for SMT processors but ends up as aNOPon processors that have only one thread per core. - There are also architecture-specific looping implementations on loong64 and ppc64.
- On mips, mips64, riscv64, s390x, and wasm,
procyieldAsmis a simpleRETwith no loop at all.
CL 654895 changed procyieldAsm on GOARCH=arm64 to treat the argument as the number of nanoseconds to wait before returning, consulting a fast clock while looping to run ISB SY. That shows a path to a platform-independent contract.
What we have today is that a procyield(30) call on amd64 can be ~2 µs (or longer, if the CPU frequency has scaled down), or ~30 ns on arm64, or faster still on riscv64 (where the argument is ignored). The pop methods have platform-specific behavior (to only call procyield at all on arm64) since the contract isn't stable elsewhere.
Since no other platforms have attempted this sort of stability (across architectures, or across µarches / hardware generations), and since nanoseconds is a fine choice anyway, I propose that we adopt it as the contract. This will require updating the arch-specific implementations to interpret the argument as "nanoseconds", and re-tuning the arch-independent callers to expect a pause of that magnitude.
CC @golang/runtime
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity
prattmic commentedon Sep 4, 2026
cc @golang/runtime
cherrymui commentedon Sep 15, 2026
Discussed during triage. This sounds reasonable. We don't need to be very precise, maybe within 2x is good enough. Thanks.