| // Copyright 2022 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build linux |
| |
| package net |
| |
| import ( |
| "io" |
| "os" |
| "strconv" |
| "testing" |
| ) |
| |
| func BenchmarkSendFile(b *testing.B) { |
| b.Run("file-to-tcp", func(b *testing.B) { benchmarkSendFile(b, "tcp") }) |
| b.Run("file-to-unix", func(b *testing.B) { benchmarkSendFile(b, "unix") }) |
| } |
| |
| func benchmarkSendFile(b *testing.B, proto string) { |
| for i := 0; i <= 10; i++ { |
| size := 1 << (i + 10) |
| bench := sendFileBench{ |
| proto: proto, |
| chunkSize: size, |
| } |
| b.Run(strconv.Itoa(size), bench.benchSendFile) |
| } |
| } |
| |
| type sendFileBench struct { |
| proto string |
| chunkSize int |
| } |
| |
| func (bench sendFileBench) benchSendFile(b *testing.B) { |
| fileSize := b.N * bench.chunkSize |
| f := createTempFile(b, fileSize) |
| |
| client, server := spliceTestSocketPair(b, bench.proto) |
| defer server.Close() |
| |
| cleanUp, err := startSpliceClient(client, "r", bench.chunkSize, fileSize) |
| if err != nil { |
| client.Close() |
| b.Fatal(err) |
| } |
| defer cleanUp() |
| |
| b.ReportAllocs() |
| b.SetBytes(int64(bench.chunkSize)) |
| b.ResetTimer() |
| |
| // Data go from file to socket via sendfile(2). |
| sent, err := io.Copy(server, f) |
| if err != nil { |
| b.Fatalf("failed to copy data with sendfile, error: %v", err) |
| } |
| if sent != int64(fileSize) { |
| b.Fatalf("bytes sent mismatch, got: %d, want: %d", sent, fileSize) |
| } |
| } |
| |
| func createTempFile(b *testing.B, size int) *os.File { |
| f, err := os.CreateTemp(b.TempDir(), "linux-sendfile-bench") |
| if err != nil { |
| b.Fatalf("failed to create temporary file: %v", err) |
| } |
| b.Cleanup(func() { |
| f.Close() |
| }) |
| |
| data := make([]byte, size) |
| if _, err := f.Write(data); err != nil { |
| b.Fatalf("failed to create and feed the file: %v", err) |
| } |
| if err := f.Sync(); err != nil { |
| b.Fatalf("failed to save the file: %v", err) |
| } |
| if _, err := f.Seek(0, io.SeekStart); err != nil { |
| b.Fatalf("failed to rewind the file: %v", err) |
| } |
| |
| return f |
| } |