golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/bench_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.21 6 7 package quic 8 9 import ( 10 "context" 11 "fmt" 12 "io" 13 "math" 14 "sync" 15 "testing" 16 ) 17 18 // BenchmarkThroughput is based on the crypto/tls benchmark of the same name. 19 func BenchmarkThroughput(b *testing.B) { 20 for size := 1; size <= 64; size <<= 1 { 21 name := fmt.Sprintf("%dMiB", size) 22 b.Run(name, func(b *testing.B) { 23 throughput(b, int64(size<<20)) 24 }) 25 } 26 } 27 28 func throughput(b *testing.B, totalBytes int64) { 29 // Same buffer size as crypto/tls's BenchmarkThroughput, for consistency. 30 const bufsize = 32 << 10 31 32 cli, srv := newLocalConnPair(b, &Config{}, &Config{}) 33 34 go func() { 35 buf := make([]byte, bufsize) 36 for i := 0; i < b.N; i++ { 37 sconn, err := srv.AcceptStream(context.Background()) 38 if err != nil { 39 panic(fmt.Errorf("AcceptStream: %v", err)) 40 } 41 if _, err := io.CopyBuffer(sconn, sconn, buf); err != nil { 42 panic(fmt.Errorf("CopyBuffer: %v", err)) 43 } 44 sconn.Close() 45 } 46 }() 47 48 b.SetBytes(totalBytes) 49 buf := make([]byte, bufsize) 50 chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf)))) 51 for i := 0; i < b.N; i++ { 52 cconn, err := cli.NewStream(context.Background()) 53 if err != nil { 54 b.Fatalf("NewStream: %v", err) 55 } 56 closec := make(chan struct{}) 57 go func() { 58 defer close(closec) 59 buf := make([]byte, bufsize) 60 if _, err := io.CopyBuffer(io.Discard, cconn, buf); err != nil { 61 panic(fmt.Errorf("Discard: %v", err)) 62 } 63 }() 64 for j := 0; j < chunks; j++ { 65 _, err := cconn.Write(buf) 66 if err != nil { 67 b.Fatalf("Write: %v", err) 68 } 69 } 70 cconn.CloseWrite() 71 <-closec 72 cconn.Close() 73 } 74 } 75 76 func BenchmarkReadByte(b *testing.B) { 77 cli, srv := newLocalConnPair(b, &Config{}, &Config{}) 78 79 var wg sync.WaitGroup 80 defer wg.Wait() 81 82 wg.Add(1) 83 go func() { 84 defer wg.Done() 85 buf := make([]byte, 1<<20) 86 sconn, err := srv.AcceptStream(context.Background()) 87 if err != nil { 88 panic(fmt.Errorf("AcceptStream: %v", err)) 89 } 90 for { 91 if _, err := sconn.Write(buf); err != nil { 92 break 93 } 94 sconn.Flush() 95 } 96 }() 97 98 b.SetBytes(1) 99 cconn, err := cli.NewStream(context.Background()) 100 if err != nil { 101 b.Fatalf("NewStream: %v", err) 102 } 103 cconn.Flush() 104 for i := 0; i < b.N; i++ { 105 _, err := cconn.ReadByte() 106 if err != nil { 107 b.Fatalf("ReadByte: %v", err) 108 } 109 } 110 cconn.Close() 111 } 112 113 func BenchmarkWriteByte(b *testing.B) { 114 cli, srv := newLocalConnPair(b, &Config{}, &Config{}) 115 116 var wg sync.WaitGroup 117 defer wg.Wait() 118 119 wg.Add(1) 120 go func() { 121 defer wg.Done() 122 sconn, err := srv.AcceptStream(context.Background()) 123 if err != nil { 124 panic(fmt.Errorf("AcceptStream: %v", err)) 125 } 126 n, err := io.Copy(io.Discard, sconn) 127 if n != int64(b.N) || err != nil { 128 b.Errorf("server io.Copy() = %v, %v; want %v, nil", n, err, b.N) 129 } 130 }() 131 132 b.SetBytes(1) 133 cconn, err := cli.NewStream(context.Background()) 134 if err != nil { 135 b.Fatalf("NewStream: %v", err) 136 } 137 cconn.Flush() 138 for i := 0; i < b.N; i++ { 139 if err := cconn.WriteByte(0); err != nil { 140 b.Fatalf("WriteByte: %v", err) 141 } 142 } 143 cconn.Close() 144 } 145 146 func BenchmarkStreamCreation(b *testing.B) { 147 cli, srv := newLocalConnPair(b, &Config{}, &Config{}) 148 149 go func() { 150 for i := 0; i < b.N; i++ { 151 sconn, err := srv.AcceptStream(context.Background()) 152 if err != nil { 153 panic(fmt.Errorf("AcceptStream: %v", err)) 154 } 155 sconn.Close() 156 } 157 }() 158 159 buf := make([]byte, 1) 160 for i := 0; i < b.N; i++ { 161 cconn, err := cli.NewStream(context.Background()) 162 if err != nil { 163 b.Fatalf("NewStream: %v", err) 164 } 165 cconn.Write(buf) 166 cconn.Flush() 167 cconn.Read(buf) 168 cconn.Close() 169 } 170 }