package benchmark import ( "bytes" "context" "crypto/tls" "fmt" "io" "math/rand" "net" quic "github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/testdata" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Benchmarks", func() { for i := range protocol.SupportedVersions { version := protocol.SupportedVersions[i] Context(fmt.Sprintf("with version %s", version), func() { var data []byte var dataLen int BeforeEach(func() { dataLen = size * /* MB */ 1e6 data = make([]byte, dataLen) rand.Read(data) // no need to check for an error. math.Rand.Read never errors }) Measure("transferring a file", func(b Benchmarker) { var ln quic.Listener serverAddr := make(chan net.Addr) handshakeChan := make(chan struct{}) // start the server go func() { defer GinkgoRecover() var err error tlsConf := testdata.GetTLSConfig() tlsConf.NextProtos = []string{"benchmark"} ln, err = quic.ListenAddr( "localhost:0", tlsConf, &quic.Config{Versions: []protocol.VersionNumber{version}}, ) Expect(err).ToNot(HaveOccurred()) serverAddr <- ln.Addr() sess, err := ln.Accept(context.Background()) Expect(err).ToNot(HaveOccurred()) // wait for the client to complete the handshake before sending the data // this should not be necessary, but due to timing issues on the CIs, this is necessary to avoid sending too many undecryptable packets <-handshakeChan str, err := sess.OpenStream() Expect(err).ToNot(HaveOccurred()) _, err = str.Write(data) Expect(err).ToNot(HaveOccurred()) err = str.Close() Expect(err).ToNot(HaveOccurred()) }() // start the client addr := <-serverAddr sess, err := quic.DialAddr( addr.String(), &tls.Config{InsecureSkipVerify: true, NextProtos: []string{"benchmark"}}, &quic.Config{Versions: []protocol.VersionNumber{version}}, ) Expect(err).ToNot(HaveOccurred()) close(handshakeChan) str, err := sess.AcceptStream(context.Background()) Expect(err).ToNot(HaveOccurred()) buf := &bytes.Buffer{} // measure the time it takes to download the dataLen bytes // note we're measuring the time for the transfer, i.e. excluding the handshake runtime := b.Time("transfer time", func() { _, err := io.Copy(buf, str) Expect(err).NotTo(HaveOccurred()) }) Expect(buf.Bytes()).To(Equal(data)) b.RecordValue("transfer rate [MB/s]", float64(dataLen)/1e6/runtime.Seconds()) ln.Close() sess.CloseWithError(0, "") }, 3) }) } })