Skip to content

Commit

Permalink
runtime: measure speed of procyield and osyield
Browse files Browse the repository at this point in the history
These are delay primitives for lock2. If a mutex isn't immediately
available, we can use procyield to tell the processor to wait for a
moment, or osyield to allow the OS to run a different process or thread
if one is waiting. We expect a processor-level yield to be faster than
an os-level yield, and for both of them to be fast relative to entering
a full sleep (via futexsleep or semasleep).

Each architecture has its own way of hinting to the processor that it's
in a spin-wait loop, so procyield presents an architecture-independent
interface for use in lock_futex.go and lock_sema.go.

Measure the (single-threaded) speed of these to confirm.

For #68578

Change-Id: I90cd46ea553f2990395aceb048206285558c877e
Reviewed-on: https://go-review.googlesource.com/c/go/+/601396
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Dmitri Shuralyov <[email protected]>
Reviewed-by: Michael Knyszek <[email protected]>
  • Loading branch information
rhysh authored and odeke-em committed Aug 1, 2024
1 parent bd85a3b commit 6ac87aa
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/runtime/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,9 @@ func PageCachePagesLeaked() (leaked uintptr) {
return
}

var ProcYield = procyield
var OSYield = osyield

type Mutex = mutex

var Lock = lock
Expand Down
22 changes: 22 additions & 0 deletions src/runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,3 +539,25 @@ func TestTimediv(t *testing.T) {
})
}
}

func BenchmarkProcYield(b *testing.B) {
benchN := func(n uint32) func(*testing.B) {
return func(b *testing.B) {
for i := 0; i < b.N; i++ {
ProcYield(n)
}
}
}

b.Run("1", benchN(1))
b.Run("10", benchN(10))
b.Run("30", benchN(30)) // active_spin_cnt in lock_sema.go and lock_futex.go
b.Run("100", benchN(100))
b.Run("1000", benchN(1000))
}

func BenchmarkOSYield(b *testing.B) {
for i := 0; i < b.N; i++ {
OSYield()
}
}

0 comments on commit 6ac87aa

Please sign in to comment.