Commit 21e01a3c authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Refactor benchmark/

parent d98de7e2
package fuse package benchmark
// Routines for benchmarking fuse. // Routines for benchmarking fuse.
import ( import (
"bufio"
"fmt" "fmt"
"log" "log"
"math" "math"
...@@ -12,6 +13,33 @@ import ( ...@@ -12,6 +13,33 @@ import (
"time" "time"
) )
func ReadLines(name string) []string {
f, err := os.Open(name)
if err != nil {
log.Fatal("ReadLines: ", err)
}
defer f.Close()
r := bufio.NewReader(f)
l := []string{}
for {
line, _, err := r.ReadLine()
if line == nil || err != nil {
break
}
fn := string(line)
l = append(l, fn)
}
if len(l) == 0 {
log.Fatal("no files added")
}
log.Printf("Read %d file names", len(l))
return l
}
// Used for benchmarking. Returns milliseconds. // Used for benchmarking. Returns milliseconds.
func BulkStat(parallelism int, files []string) float64 { func BulkStat(parallelism int, files []string) float64 {
todo := make(chan string, len(files)) todo := make(chan string, len(files))
......
package fuse package benchmark
import ( import (
"bufio"
"fmt" "fmt"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"io/ioutil" "io/ioutil"
...@@ -11,68 +10,18 @@ import ( ...@@ -11,68 +10,18 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"sort" "sort"
"strings"
"testing" "testing"
"time" "time"
) )
var CheckSuccess = fuse.CheckSuccess var CheckSuccess = fuse.CheckSuccess
var delay = 0 * time.Microsecond
func setupFs(fs fuse.FileSystem) (string, func()) {
type StatFs struct { opts := &fuse.FileSystemOptions{
fuse.DefaultFileSystem EntryTimeout: 0.0,
entries map[string]*fuse.Attr AttrTimeout: 0.0,
dirs map[string][]fuse.DirEntry NegativeTimeout: 0.0,
delay time.Duration
}
func (me *StatFs) add(name string, a *fuse.Attr) {
name = strings.TrimRight(name, "/")
_, ok := me.entries[name]
if ok {
return
}
me.entries[name] = a
if name == "/" || name == "" {
return
}
dir, base := filepath.Split(name)
dir = strings.TrimRight(dir, "/")
me.dirs[dir] = append(me.dirs[dir], fuse.DirEntry{Name: base, Mode: a.Mode})
me.add(dir, &fuse.Attr{Mode: fuse.S_IFDIR | 0755})
}
func (me *StatFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
e := me.entries[name]
if e == nil {
return nil, fuse.ENOENT
}
if me.delay > 0 {
time.Sleep(me.delay)
}
return e, fuse.OK
}
func (me *StatFs) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
entries := me.dirs[name]
if entries == nil {
return nil, fuse.ENOENT
}
return entries, fuse.OK
}
func NewStatFs() *StatFs {
return &StatFs{
entries: make(map[string]*fuse.Attr),
dirs: make(map[string][]fuse.DirEntry),
} }
}
func setupFs(fs fuse.FileSystem, opts *fuse.FileSystemOptions) (string, func()) {
mountPoint, _ := ioutil.TempDir("", "stat_test") mountPoint, _ := ioutil.TempDir("", "stat_test")
nfs := fuse.NewPathNodeFs(fs, nil) nfs := fuse.NewPathNodeFs(fs, nil)
state, _, err := fuse.MountNodeFileSystem(mountPoint, nfs, opts) state, _, err := fuse.MountNodeFileSystem(mountPoint, nfs, opts)
...@@ -97,10 +46,10 @@ func TestNewStatFs(t *testing.T) { ...@@ -97,10 +46,10 @@ func TestNewStatFs(t *testing.T) {
for _, n := range []string{ for _, n := range []string{
"file.txt", "sub/dir/foo.txt", "file.txt", "sub/dir/foo.txt",
"sub/dir/bar.txt", "sub/marine.txt"} { "sub/dir/bar.txt", "sub/marine.txt"} {
fs.add(n, &fuse.Attr{Mode: fuse.S_IFREG | 0644}) fs.AddFile(n)
} }
wd, clean := setupFs(fs, nil) wd, clean := setupFs(fs)
defer clean() defer clean()
names, err := ioutil.ReadDir(wd) names, err := ioutil.ReadDir(wd)
...@@ -132,51 +81,18 @@ func TestNewStatFs(t *testing.T) { ...@@ -132,51 +81,18 @@ func TestNewStatFs(t *testing.T) {
} }
} }
func GetTestLines() []string {
wd, _ := os.Getwd()
// Names from OpenJDK 1.6
fn := wd + "/testpaths.txt"
f, err := os.Open(fn)
CheckSuccess(err)
defer f.Close()
r := bufio.NewReader(f)
l := []string{}
for {
line, _, err := r.ReadLine()
if line == nil || err != nil {
break
}
fn := string(line)
l = append(l, fn)
}
return l
}
func BenchmarkGoFuseThreadedStat(b *testing.B) { func BenchmarkGoFuseThreadedStat(b *testing.B) {
b.StopTimer() b.StopTimer()
fs := NewStatFs() fs := NewStatFs()
fs.delay = delay fs.delay = delay
files := GetTestLines()
wd, _ := os.Getwd()
files := ReadLines(wd + "/testpaths.txt")
for _, fn := range files { for _, fn := range files {
fs.add(fn, &fuse.Attr{Mode: fuse.S_IFREG | 0644}) fs.AddFile(fn)
}
if len(files) == 0 {
log.Fatal("no files added")
} }
log.Printf("Read %d file names", len(files)) wd, clean := setupFs(fs)
ttl := 100 * time.Millisecond
opts := fuse.FileSystemOptions{
EntryTimeout: 0.0,
AttrTimeout: 0.0,
NegativeTimeout: 0.0,
}
wd, clean := setupFs(fs, &opts)
defer clean() defer clean()
for i, l := range files { for i, l := range files {
...@@ -184,13 +100,14 @@ func BenchmarkGoFuseThreadedStat(b *testing.B) { ...@@ -184,13 +100,14 @@ func BenchmarkGoFuseThreadedStat(b *testing.B) {
} }
threads := runtime.GOMAXPROCS(0) threads := runtime.GOMAXPROCS(0)
results := TestingBOnePass(b, threads, time.Duration((ttl*120)/100), files) results := TestingBOnePass(b, threads, files)
AnalyzeBenchmarkRuns("Go-FUSE", results) AnalyzeBenchmarkRuns("Go-FUSE", results)
} }
func TestingBOnePass(b *testing.B, threads int, sleepTime time.Duration, files []string) (results []float64) { func TestingBOnePass(b *testing.B, threads int, files []string) (results []float64) {
runtime.GC() runtime.GC()
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]
...@@ -207,7 +124,8 @@ func TestingBOnePass(b *testing.B, threads int, sleepTime time.Duration, files [ ...@@ -207,7 +124,8 @@ func TestingBOnePass(b *testing.B, threads int, sleepTime time.Duration, files [
func BenchmarkCFuseThreadedStat(b *testing.B) { func BenchmarkCFuseThreadedStat(b *testing.B) {
b.StopTimer() b.StopTimer()
lines := GetTestLines() wd, _ := os.Getwd()
lines := ReadLines(wd + "/testpaths.txt")
unique := map[string]int{} unique := map[string]int{}
for _, l := range lines { for _, l := range lines {
unique[l] = 1 unique[l] = 1
...@@ -233,7 +151,6 @@ func BenchmarkCFuseThreadedStat(b *testing.B) { ...@@ -233,7 +151,6 @@ func BenchmarkCFuseThreadedStat(b *testing.B) {
f.Close() f.Close()
mountPoint, _ := ioutil.TempDir("", "stat_test") mountPoint, _ := ioutil.TempDir("", "stat_test")
wd, _ := os.Getwd()
cmd := exec.Command(wd+"/cstatfs", cmd := exec.Command(wd+"/cstatfs",
"-o", "-o",
"entry_timeout=0.0,attr_timeout=0.0,ac_attr_timeout=0.0,negative_timeout=0.0", "entry_timeout=0.0,attr_timeout=0.0,ac_attr_timeout=0.0,negative_timeout=0.0",
...@@ -253,10 +170,10 @@ func BenchmarkCFuseThreadedStat(b *testing.B) { ...@@ -253,10 +170,10 @@ func BenchmarkCFuseThreadedStat(b *testing.B) {
lines[i] = filepath.Join(mountPoint, l) lines[i] = filepath.Join(mountPoint, l)
} }
// Wait for the daemon to mount. time.Sleep(10 * time.Millisecond)
time.Sleep(200 * time.Millisecond) os.Lstat(mountPoint)
ttl := time.Millisecond * 100
threads := runtime.GOMAXPROCS(0) threads := runtime.GOMAXPROCS(0)
results := TestingBOnePass(b, threads, time.Duration((ttl*12)/10), lines) results := TestingBOnePass(b, threads, lines)
AnalyzeBenchmarkRuns("CFuse", results) AnalyzeBenchmarkRuns("CFuse", results)
} }
package benchmark
import (
"github.com/hanwen/go-fuse/fuse"
"path/filepath"
"strings"
"time"
)
var delay = 0 * time.Microsecond
type StatFs struct {
fuse.DefaultFileSystem
entries map[string]*fuse.Attr
dirs map[string][]fuse.DirEntry
delay time.Duration
}
func (me *StatFs) Add(name string, a *fuse.Attr) {
name = strings.TrimRight(name, "/")
_, ok := me.entries[name]
if ok {
return
}
me.entries[name] = a
if name == "/" || name == "" {
return
}
dir, base := filepath.Split(name)
dir = strings.TrimRight(dir, "/")
me.dirs[dir] = append(me.dirs[dir], fuse.DirEntry{Name: base, Mode: a.Mode})
me.Add(dir, &fuse.Attr{Mode: fuse.S_IFDIR | 0755})
}
func (me *StatFs) AddFile(name string) {
me.Add(name, &fuse.Attr{Mode: fuse.S_IFREG | 0644})
}
func (me *StatFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
e := me.entries[name]
if e == nil {
return nil, fuse.ENOENT
}
if me.delay > 0 {
time.Sleep(me.delay)
}
return e, fuse.OK
}
func (me *StatFs) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
entries := me.dirs[name]
if entries == nil {
return nil, fuse.ENOENT
}
return entries, fuse.OK
}
func NewStatFs() *StatFs {
return &StatFs{
entries: make(map[string]*fuse.Attr),
dirs: make(map[string][]fuse.DirEntry),
}
}
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