Commit ab014071 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

benchmark: introduce benchmark for loopback reads

Loopback (file backed by some other file on disk) is an important
use-case, and FUSE features such as passthrough and splicing aim to
reduce overhead.

Example: 

    Splice disabled:

    $ go test -bench FD -test.cpu=1,2
    goos: linux
    goarch: amd64
    pkg: github.com/hanwen/go-fuse/v2/benchmark
    cpu: Intel(R) Core(TM) i5-8350U CPU @ 1.70GHz
    BenchmarkGoFuseFDRead     	    1929	    597942 ns/op	3507.28 MB/s	    4290 B/op	     129 allocs/op
    BenchmarkGoFuseFDRead-2   	    2497	    421856 ns/op	4971.26 MB/s	   62500 B/op	     177 allocs/op
    PASS
    ok  	github.com/hanwen/go-fuse/v2/benchmark	3.510s

    Splice enabled:

    $ go test -bench FD -test.cpu=1,2
    goos: linux
    goarch: amd64
    pkg: github.com/hanwen/go-fuse/v2/benchmark
    cpu: Intel(R) Core(TM) i5-8350U CPU @ 1.70GHz
    BenchmarkGoFuseFDRead     	    1524	    750249 ns/op	2795.28 MB/s	    4132 B/op	      98 allocs/op
    BenchmarkGoFuseFDRead-2   	    2364	    463522 ns/op	4524.39 MB/s	   11719 B/op	     106 allocs/op
    PASS

in other words, the API complexity that splicing introduced was not
worth it: it actually slows down things.

Change-Id: I4f7519ab2cc5b0145d0f7f81f55ad20d544e9d87
parent 6a08a74a
...@@ -5,25 +5,30 @@ ...@@ -5,25 +5,30 @@
package benchmark package benchmark
import ( import (
"bytes"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"testing" "testing"
"github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/internal/testutil" "github.com/hanwen/go-fuse/v2/internal/testutil"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
func BenchmarkGoFuseRead(b *testing.B) { func BenchmarkGoFuseMemoryRead(b *testing.B) {
fs := &readFS{} root := &readFS{}
wd, clean := setupFs(fs, b.N) benchmarkGoFuseRead(root, b)
}
const blockSize = 64 * 1024
func benchmarkGoFuseRead(root fs.InodeEmbedder, b *testing.B) {
wd, clean := setupFs(root, b.N)
defer clean() defer clean()
jobs := 32 jobs := 32
blockSize := 64 * 1024
cmds := make([]*exec.Cmd, jobs) cmds := make([]*exec.Cmd, jobs)
for i := 0; i < jobs; i++ { for i := 0; i < jobs; i++ {
cmds[i] = exec.Command("dd", cmds[i] = exec.Command("dd",
fmt.Sprintf("if=%s/foo.txt", wd), fmt.Sprintf("if=%s/foo.txt", wd),
...@@ -42,7 +47,6 @@ func BenchmarkGoFuseRead(b *testing.B) { ...@@ -42,7 +47,6 @@ func BenchmarkGoFuseRead(b *testing.B) {
b.ResetTimer() b.ResetTimer()
var eg errgroup.Group var eg errgroup.Group
for i := 0; i < jobs; i++ { for i := 0; i < jobs; i++ {
i := i i := i
eg.Go(func() error { eg.Go(func() error {
...@@ -56,3 +60,32 @@ func BenchmarkGoFuseRead(b *testing.B) { ...@@ -56,3 +60,32 @@ func BenchmarkGoFuseRead(b *testing.B) {
b.StopTimer() b.StopTimer()
} }
func BenchmarkGoFuseFDRead(b *testing.B) {
orig := b.TempDir()
fn := orig + "/foo.txt"
f, err := os.Create(fn)
if err != nil {
b.Fatal(err)
}
defer f.Close()
if err := f.Chmod(0777); err != nil {
b.Fatal(err)
}
data := bytes.Repeat([]byte{42}, blockSize)
for i := 0; i < b.N; i++ {
_, err := f.Write(data)
if err != nil {
b.Fatal(err)
}
}
if err := f.Close(); err != nil {
b.Fatal(err)
}
root, err := fs.NewLoopbackRoot(orig)
if err != nil {
b.Fatal(err)
}
benchmarkGoFuseRead(root, b)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment