Skip to content

Instantly share code, notes, and snippets.

@cstockton
Created October 9, 2017 15:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cstockton/2c7e9346af7b7daad11bf9a754a3716e to your computer and use it in GitHub Desktop.
Save cstockton/2c7e9346af7b7daad11bf9a754a3716e to your computer and use it in GitHub Desktop.
BenchmarkSend/128-24 200000 5788 ns/op
BenchmarkSend/128#01-24 1000000 2053 ns/op
BenchmarkSend/256-24 100000 10465 ns/op
BenchmarkSend/256#01-24 500000 3311 ns/op
BenchmarkSend/512-24 100000 18025 ns/op
BenchmarkSend/512#01-24 200000 6123 ns/op
BenchmarkSend/1024-24 30000 36596 ns/op
BenchmarkSend/1024#01-24 100000 11584 ns/op
BenchmarkSend/2048-24 20000 64805 ns/op
BenchmarkSend/2048#01-24 50000 22978 ns/op
BenchmarkSend/4096-24 10000 140308 ns/op
BenchmarkSend/4096#01-24 30000 40229 ns/op
BenchmarkSend/8192-24 5000 284343 ns/op
BenchmarkSend/8192#01-24 20000 66941 ns/op
BenchmarkSend/16384-24 2000 527173 ns/op
BenchmarkSend/16384#01-24 10000 153594 ns/op
//go:nosplit
func chansendn1(c *hchan, n int, elem unsafe.Pointer) {
chansendn(c, elem, n, true, getcallerpc(unsafe.Pointer(&c)))
}
func chansendn(c *hchan, ep unsafe.Pointer, n int, block bool, callerpc uintptr) bool {
if c == nil {
if !block {
return false
}
gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2)
throw("unreachable")
}
if raceenabled {
racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend))
}
if !block && c.closed == 0 && ((c.dataqsiz == 0 && c.recvq.first == nil) ||
(c.dataqsiz > 0 && c.qcount == c.dataqsiz)) {
return false
}
lock(&c.lock)
if c.closed != 0 {
unlock(&c.lock)
panic(plainError("send on closed channel"))
}
for ; n > 0; n-- {
for sg := c.recvq.dequeue(); sg != nil; sg = c.recvq.dequeue() {
// Found a waiting receiver. We pass the value we want to send
// directly to the receiver, bypassing the channel buffer (if any).
send(c, sg, ep, func() { unlock(&c.lock) }, 3)
continue
}
if c.qcount < c.dataqsiz {
// Space is available in the channel buffer. Enqueue the element to send.
qp := chanbuf(c, c.sendx)
if raceenabled {
raceacquire(qp)
racerelease(qp)
}
typedmemmove(c.elemtype, qp, ep)
c.sendx++
if c.sendx == c.dataqsiz {
c.sendx = 0
}
c.qcount++
continue
}
}
unlock(&c.lock)
return n == 0
}
package chansendn
import (
"unsafe"
)
//go:linkname chansend1 runtime.chansend1
func chansend1(ch unsafe.Pointer, val unsafe.Pointer) bool
//go:linkname chansendn1 runtime.chansendn1
func chansendn1(ch unsafe.Pointer, n int, elem unsafe.Pointer) uintptr
func sendLoop(ch chan struct{}, n int) {
if n > cap(ch) {
panic(`end-start > cap(ch)`)
}
for ; n > 0; n-- {
ch <- struct{}{}
}
}
func sendN(ch chan struct{}, n int) {
if n > cap(ch) {
panic(`end-start > cap(ch)`)
}
var val struct{}
chansendn1(chanOf(ch), n, unsafe.Pointer(&val))
}
package event
import (
"fmt"
"testing"
)
func BenchmarkSend(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for count := 128; count < 32768; count *= 2 {
b.Run(fmt.Sprint(count), func(b *testing.B) {
for i := 0; i < b.N; i++ {
ch := make(chan struct{}, count)
sendLoop(ch, count)
}
})
b.Run(fmt.Sprint(count), func(b *testing.B) {
for i := 0; i < b.N; i++ {
ch := make(chan struct{}, count)
sendN(ch, count)
}
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment