Skip to content

Instantly share code, notes, and snippets.

@lesismal
Last active December 13, 2023 18:11
Show Gist options
  • Save lesismal/a40c420511252aa79b054cbd2acc896e to your computer and use it in GitHub Desktop.
Save lesismal/a40c420511252aa79b054cbd2acc896e to your computer and use it in GitHub Desktop.
go net.Buffers vs user buffer append
package test
import (
"bufio"
"io"
"log"
"net"
"sync"
"testing"
"time"
)
var (
listener net.Listener
headSize = 64
bodySize = 1024 * 4
totalSize = headSize + bodySize
loop = 100
)
func startServer(addr string) {
if listener != nil {
return
}
var err error
listener, err = net.Listen("tcp", addr)
if err != nil {
log.Fatal(err)
}
go func() {
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
return
}
go func() {
defer conn.Close()
buf := make([]byte, totalSize)
for {
n, err := conn.Read(buf)
if err != nil {
return
}
conn.Write(buf[:n])
}
}()
}
}()
time.Sleep(time.Second / 100)
}
func stopServer() {
listener.Close()
listener = nil
}
func BenchmarkNetBuffers(b *testing.B) {
addr := "127.0.0.1:8080"
startServer(addr)
defer stopServer()
b.ReportAllocs()
b.ResetTimer()
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
head := make([]byte, headSize)
body := make([]byte, bodySize)
buf := make([]byte, totalSize)
for i := 0; i < b.N; i++ {
for j := 0; j < loop; j++ {
buffers := net.Buffers([][]byte{head, body})
nw, err := buffers.WriteTo(conn)
if err != nil {
b.Fatal(err)
}
n := int(nw)
if n != totalSize {
b.Fatalf("write less than totalSize")
}
n, err = io.ReadFull(conn, buf)
if err != nil {
b.Fatal(err)
}
if n != totalSize {
b.Fatalf("read less than totalSize")
}
}
}
}
func BenchmarkUserBuffers(b *testing.B) {
addr := "127.0.0.1:8081"
startServer(addr)
defer stopServer()
b.ReportAllocs()
b.ResetTimer()
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
pool := &sync.Pool{
New: func() interface{} {
buf := make([]byte, totalSize)
return &buf
},
}
head := make([]byte, headSize)
body := make([]byte, bodySize)
buf := make([]byte, totalSize)
for i := 0; i < b.N; i++ {
for j := 0; j < loop; j++ {
wbuf := (*pool.Get().(*[]byte))[:0]
wbuf = append(wbuf, head...)
wbuf = append(wbuf, body...)
n, err := conn.Write(wbuf)
if err != nil {
b.Fatal(err)
}
if n != totalSize {
b.Fatalf("write less than totalSize")
}
n, err = io.ReadFull(conn, buf)
if err != nil {
b.Fatal(err)
}
if n != totalSize {
b.Fatalf("read less than totalSize")
}
pool.Put(&wbuf)
}
}
}
func BenchmarkUserBuffersReuse(b *testing.B) {
addr := "127.0.0.1:8082"
startServer(addr)
defer stopServer()
b.ReportAllocs()
b.ResetTimer()
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
pool := &sync.Pool{
New: func() interface{} {
buf := make([]byte, totalSize)
return &buf
},
}
head := make([]byte, headSize)
body := make([]byte, bodySize)
buf := make([]byte, totalSize)
wbuf := make([]byte, totalSize)
for i := 0; i < b.N; i++ {
for j := 0; j < loop; j++ {
// copy(wbuf, head)
// copy(wbuf[len(head):], body)
wbuf = wbuf[:0]
wbuf = append(wbuf, head...)
wbuf = append(wbuf, body...)
n, err := conn.Write(wbuf)
if err != nil {
b.Fatal(err)
}
if n != totalSize {
b.Fatalf("write less than totalSize")
}
n, err = io.ReadFull(conn, buf)
if err != nil {
b.Fatal(err)
}
if n != totalSize {
b.Fatalf("read less than totalSize")
}
pool.Put(&wbuf)
}
}
}
func BenchmarkBufioWriter(b *testing.B) {
addr := "127.0.0.1:8083"
startServer(addr)
defer stopServer()
b.ReportAllocs()
b.ResetTimer()
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
head := make([]byte, headSize)
body := make([]byte, bodySize)
buf := make([]byte, totalSize)
writer := bufio.NewWriterSize(conn, totalSize)
for i := 0; i < b.N; i++ {
for j := 0; j < loop; j++ {
n1, err := writer.Write(head)
if err != nil {
b.Fatal(err)
}
n2, err := writer.Write(body)
if err != nil {
b.Fatal(err)
}
err = writer.Flush()
if err != nil {
b.Fatal(err)
}
n := n1 + n2
if err != nil {
b.Fatal(err)
}
if n != totalSize {
b.Fatalf("write less than totalSize")
}
n, err = io.ReadFull(conn, buf)
if err != nil {
b.Fatal(err)
}
if n != totalSize {
b.Fatalf("read less than totalSize")
}
}
}
}
@lesismal
Copy link
Author

output:

root@ubuntu:~/netbuffers# go test -v -bench .
goos: linux
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
BenchmarkNetBuffers
BenchmarkNetBuffers-12     	     831	   1448544 ns/op	    7218 B/op	     200 allocs/op
BenchmarkUserBuffers
BenchmarkUserBuffers-12    	     848	   1421244 ns/op	    2425 B/op	     100 allocs/op
PASS
ok  	test	2.778s
root@ubuntu:~/netbuffers# go test -v -bench .
goos: linux
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
BenchmarkNetBuffers
BenchmarkNetBuffers-12     	     818	   1496528 ns/op	    7221 B/op	     200 allocs/op
BenchmarkUserBuffers
BenchmarkUserBuffers-12    	     825	   1459183 ns/op	    2426 B/op	     100 allocs/op
PASS
ok  	test	2.812s
root@ubuntu:~/netbuffers# go test -v -bench .
goos: linux
goarch: amd64
pkg: test
cpu: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
BenchmarkNetBuffers
BenchmarkNetBuffers-12     	     818	   1443584 ns/op	    7218 B/op	     200 allocs/op
BenchmarkUserBuffers
BenchmarkUserBuffers-12    	     848	   1418082 ns/op	    2425 B/op	     100 allocs/op
PASS
ok  	test	2.753s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment