Commit 4d95f545 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Add benchmark for readdir.

Surpress benchmark if -v is not given.
parent ac3dcb75
...@@ -34,7 +34,6 @@ func ReadLines(name string) []string { ...@@ -34,7 +34,6 @@ func ReadLines(name string) []string {
if len(l) == 0 { if len(l) == 0 {
log.Fatal("no files added") log.Fatal("no files added")
} }
log.Printf("Read %d file names", len(l))
return l return l
} }
...@@ -99,6 +98,7 @@ func AnalyzeBenchmarkRuns(label string, times []float64) { ...@@ -99,6 +98,7 @@ func AnalyzeBenchmarkRuns(label string, times []float64) {
perc90 := sorted[int(n*0.9)] perc90 := sorted[int(n*0.9)]
perc10 := sorted[int(n*0.1)] perc10 := sorted[int(n*0.1)]
if VerboseTest() {
fmt.Printf( fmt.Printf(
"%s: %d samples\n"+ "%s: %d samples\n"+
"avg %.3fms +/- %.0f%% "+ "avg %.3fms +/- %.0f%% "+
...@@ -106,6 +106,7 @@ func AnalyzeBenchmarkRuns(label string, times []float64) { ...@@ -106,6 +106,7 @@ func AnalyzeBenchmarkRuns(label string, times []float64) {
label, label,
len(times), avg, 100.0*2*stddev/avg, len(times), avg, 100.0*2*stddev/avg,
median, 100*(median-perc10)/median, 100*(perc90-median)/median) median, 100*(median-perc10)/median, 100*(perc90-median)/median)
}
} }
func RunBulkStat(runs int, threads int, sleepTime time.Duration, files []string) (results []float64) { func RunBulkStat(runs int, threads int, sleepTime time.Duration, files []string) (results []float64) {
......
...@@ -25,6 +25,10 @@ func (m *LatencyMap) Get(name string) (count int, dt time.Duration) { ...@@ -25,6 +25,10 @@ func (m *LatencyMap) Get(name string) (count int, dt time.Duration) {
m.Mutex.Lock() m.Mutex.Lock()
l := m.stats[name] l := m.stats[name]
m.Mutex.Unlock() m.Mutex.Unlock()
if l == nil {
return 0, 0
}
return l.count, l.dur return l.count, l.dur
} }
......
...@@ -16,6 +16,14 @@ import ( ...@@ -16,6 +16,14 @@ import (
"github.com/hanwen/go-fuse/fuse/pathfs" "github.com/hanwen/go-fuse/fuse/pathfs"
) )
import "flag"
// VerboseTest returns true if the testing framework is run with -v.
func VerboseTest() bool {
flag := flag.Lookup("test.v")
return flag != nil && flag.Value.String() == "true"
}
func setupFs(fs pathfs.FileSystem) (string, func()) { func setupFs(fs pathfs.FileSystem) (string, func()) {
opts := &nodefs.Options{ opts := &nodefs.Options{
EntryTimeout: 0.0, EntryTimeout: 0.0,
...@@ -29,16 +37,22 @@ func setupFs(fs pathfs.FileSystem) (string, func()) { ...@@ -29,16 +37,22 @@ func setupFs(fs pathfs.FileSystem) (string, func()) {
panic(fmt.Sprintf("cannot mount %v", err)) // ugh - benchmark has no error methods. panic(fmt.Sprintf("cannot mount %v", err)) // ugh - benchmark has no error methods.
} }
lmap := NewLatencyMap() lmap := NewLatencyMap()
if VerboseTest() {
state.RecordLatencies(lmap) state.RecordLatencies(lmap)
}
go state.Serve() go state.Serve()
return mountPoint, func() { return mountPoint, func() {
lc, lns := lmap.Get("LOOKUP") if VerboseTest() {
gc, gns := lmap.Get("GETATTR") for _, n := range []string{"LOOKUP", "GETATTR", "OPENDIR", "READDIR",
fmt.Printf("GETATTR %v/call n=%d, LOOKUP %v/call n=%d\n", "READDIRPLUS",
gns/time.Duration(gc), gc, } {
lns/time.Duration(lc), lc) if count, dt := lmap.Get(n); count > 0 {
log.Printf("%s %v/call n=%d", n,
dt/time.Duration(count), count)
}
}
}
err := state.Unmount() err := state.Unmount()
if err != nil { if err != nil {
...@@ -46,6 +60,7 @@ func setupFs(fs pathfs.FileSystem) (string, func()) { ...@@ -46,6 +60,7 @@ func setupFs(fs pathfs.FileSystem) (string, func()) {
} else { } else {
os.RemoveAll(mountPoint) os.RemoveAll(mountPoint)
} }
} }
} }
...@@ -118,8 +133,54 @@ func BenchmarkGoFuseThreadedStat(b *testing.B) { ...@@ -118,8 +133,54 @@ func BenchmarkGoFuseThreadedStat(b *testing.B) {
} }
threads := runtime.GOMAXPROCS(0) threads := runtime.GOMAXPROCS(0)
results := TestingBOnePass(b, threads, files) TestingBOnePass(b, threads, files)
AnalyzeBenchmarkRuns(fmt.Sprintf("Go-FUSE %d CPUs", threads), results) }
func readdir(d string) error {
f, err := os.Open(d)
if err != nil {
return err
}
if _, err := f.Readdirnames(-1); err != nil {
return err
}
return f.Close()
}
func BenchmarkGoFuseReaddir(b *testing.B) {
b.StopTimer()
fs := NewStatFs()
fs.delay = delay
wd, _ := os.Getwd()
dirSet := map[string]struct{}{}
for _, fn := range ReadLines(wd + "/testpaths.txt") {
fs.AddFile(fn)
dirSet[filepath.Dir(fn)] = struct{}{}
}
wd, clean := setupFs(fs)
defer clean()
var dirs []string
for dir := range dirSet {
dirs = append(dirs, filepath.Join(wd, dir))
}
b.StartTimer()
todo := b.N
for todo > 0 {
if len(dirs) > todo {
dirs = dirs[:todo]
}
for _, d := range dirs {
if err := readdir(d); err != nil {
b.Fatal(err)
}
}
todo -= len(dirs)
}
b.StopTimer()
} }
func TestingBOnePass(b *testing.B, threads int, files []string) (results []float64) { func TestingBOnePass(b *testing.B, threads int, files []string) (results []float64) {
...@@ -127,21 +188,24 @@ func TestingBOnePass(b *testing.B, threads int, files []string) (results []float ...@@ -127,21 +188,24 @@ func TestingBOnePass(b *testing.B, threads int, files []string) (results []float
var before, after runtime.MemStats var before, after runtime.MemStats
runtime.ReadMemStats(&before) runtime.ReadMemStats(&before)
b.StartTimer()
todo := b.N todo := b.N
for todo > 0 { for todo > 0 {
if len(files) > todo { if len(files) > todo {
files = files[:todo] files = files[:todo]
} }
b.StartTimer()
result := BulkStat(threads, files) result := BulkStat(threads, files)
todo -= len(files) todo -= len(files)
b.StopTimer()
results = append(results, result) results = append(results, result)
} }
b.StopTimer()
runtime.ReadMemStats(&after) runtime.ReadMemStats(&after)
if VerboseTest() {
fmt.Printf("GC count %d, total GC time: %d ns/file\n", fmt.Printf("GC count %d, total GC time: %d ns/file\n",
after.NumGC-before.NumGC, (after.PauseTotalNs-before.PauseTotalNs)/uint64(b.N)) after.NumGC-before.NumGC, (after.PauseTotalNs-before.PauseTotalNs)/uint64(b.N))
AnalyzeBenchmarkRuns(fmt.Sprintf("Go-FUSE %d CPUs", threads), results)
}
return results return results
} }
......
...@@ -41,6 +41,9 @@ func (me *StatFs) AddFile(name string) { ...@@ -41,6 +41,9 @@ func (me *StatFs) AddFile(name string) {
} }
func (me *StatFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { func (me *StatFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
if d := me.dirs[name]; d != nil {
return &fuse.Attr{Mode: 0755 | fuse.S_IFDIR}, fuse.OK
}
e := me.entries[name] e := me.entries[name]
if e == nil { if e == nil {
return nil, fuse.ENOENT return nil, fuse.ENOENT
......
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