Commit 6f5fc437 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Add more timing hooks to TimingPathFilesystem.

parent b1becd41
...@@ -10,8 +10,12 @@ import ( ...@@ -10,8 +10,12 @@ import (
"flag" "flag"
"runtime" "runtime"
"sort" "sort"
"log"
) )
var _ = runtime.GOMAXPROCS
var _ = log.Print
func PrintMap(m map[string]float64) { func PrintMap(m map[string]float64) {
keys := make([]string, len(m)) keys := make([]string, len(m))
for k, _ := range m { for k, _ := range m {
...@@ -43,15 +47,16 @@ func main() { ...@@ -43,15 +47,16 @@ func main() {
var opts fuse.PathFileSystemConnectorOptions var opts fuse.PathFileSystemConnectorOptions
opts.AttrTimeout = 1.0 opts.AttrTimeout = 0.0
opts.EntryTimeout = 1.0 opts.EntryTimeout = 0.0
opts.NegativeTimeout = 1.0 opts.NegativeTimeout = 0.0
fs.SetOptions(&opts) fs.FillOptions(&opts)
conn := fuse.NewPathFileSystemConnector(timing) conn := fuse.NewPathFileSystemConnector(timing)
rawTiming := fuse.NewTimingRawFilesystem(conn) rawTiming := fuse.NewTimingRawFilesystem(conn)
conn.SetOptions(opts)
state := fuse.NewMountState(rawTiming) state := fuse.NewMountState(rawTiming)
state.Debug = *debug state.Debug = *debug
...@@ -61,27 +66,34 @@ func main() { ...@@ -61,27 +66,34 @@ func main() {
fmt.Printf("MountFuse fail: %v\n", err) fmt.Printf("MountFuse fail: %v\n", err)
os.Exit(1) os.Exit(1)
} }
// TODO - figure out what a good value is.
cpus := 1
// cpus := fuse.CountCpus()
if cpus > 1 {
runtime.GOMAXPROCS(cpus)
}
fmt.Printf("Mounted %s on %s (threaded=%v, debug=%v, cpus=%v)\n", orig, mountPoint, *threaded, *debug, cpus) fmt.Printf("Mounted %s on %s (threaded=%v, debug=%v)\n", orig, mountPoint, *threaded, *debug)
state.Loop(*threaded) state.Loop(*threaded)
fmt.Println("Finished", state.Stats()) fmt.Println("Finished", state.Stats())
fmt.Println("\n\nMountState statistics\n")
counts := state.OperationCounts() counts := state.OperationCounts()
fmt.Println("Counts: ", counts) fmt.Println("Counts: ", counts)
latency := state.Latencies() latency := state.Latencies()
fmt.Println("MountState latency (ms):") fmt.Println("Operation latency (ms):")
PrintMap(latency) PrintMap(latency)
latency = rawTiming.Latencies()
fmt.Println("\n\nRaw FS (ms):", latency)
fmt.Println("\n\nLoopback FS statistics\n")
latency = timing.Latencies() latency = timing.Latencies()
fmt.Println("Path ops (ms):", latency) fmt.Println("Latency (ms):", latency)
latency = rawTiming.Latencies() fmt.Println("Operation counts:", timing.OperationCounts())
fmt.Println("Raw FS (ms):", latency)
hot, unique := timing.HotPaths("GetAttr")
top := 200
start := len(hot)-top
if start < 0 {
start = 0
}
fmt.Printf("Unique GetAttr paths: %d\n", unique)
fmt.Printf("Top %d GetAttr paths: %v", top, hot[start:])
} }
...@@ -4,9 +4,12 @@ import ( ...@@ -4,9 +4,12 @@ import (
"sync" "sync"
"time" "time"
"log" "log"
"fmt"
"sort"
) )
var _ = log.Print var _ = log.Print
var _ = fmt.Print
// TimingPathFilesystem is a wrapper to collect timings for a PathFilesystem // TimingPathFilesystem is a wrapper to collect timings for a PathFilesystem
type TimingPathFilesystem struct { type TimingPathFilesystem struct {
...@@ -15,6 +18,7 @@ type TimingPathFilesystem struct { ...@@ -15,6 +18,7 @@ type TimingPathFilesystem struct {
statisticsLock sync.Mutex statisticsLock sync.Mutex
latencies map[string]int64 latencies map[string]int64
counts map[string]int64 counts map[string]int64
pathCounts map[string]map[string]int64
} }
func NewTimingPathFilesystem(fs PathFilesystem) *TimingPathFilesystem { func NewTimingPathFilesystem(fs PathFilesystem) *TimingPathFilesystem {
...@@ -22,10 +26,11 @@ func NewTimingPathFilesystem(fs PathFilesystem) *TimingPathFilesystem { ...@@ -22,10 +26,11 @@ func NewTimingPathFilesystem(fs PathFilesystem) *TimingPathFilesystem {
t.original = fs t.original = fs
t.latencies = make(map[string]int64) t.latencies = make(map[string]int64)
t.counts = make(map[string]int64) t.counts = make(map[string]int64)
t.pathCounts = make(map[string]map[string]int64)
return t return t
} }
func (me *TimingPathFilesystem) startTimer(name string) (closure func()) { func (me *TimingPathFilesystem) startTimer(name string, arg string) (closure func()) {
start := time.Nanoseconds() start := time.Nanoseconds()
return func() { return func() {
...@@ -35,9 +40,27 @@ func (me *TimingPathFilesystem) startTimer(name string) (closure func()) { ...@@ -35,9 +40,27 @@ func (me *TimingPathFilesystem) startTimer(name string) (closure func()) {
me.counts[name] += 1 me.counts[name] += 1
me.latencies[name] += dt me.latencies[name] += dt
m, ok := me.pathCounts[name]
if !ok {
m = make(map[string]int64)
me.pathCounts[name] = m
}
m[arg] += 1
} }
} }
func (me *TimingPathFilesystem) OperationCounts() map[string]int64 {
me.statisticsLock.Lock()
defer me.statisticsLock.Unlock()
r := make(map[string]int64)
for k, v := range me.counts {
r[k] = v
}
return r
}
func (me *TimingPathFilesystem) Latencies() map[string]float64 { func (me *TimingPathFilesystem) Latencies() map[string]float64 {
me.statisticsLock.Lock() me.statisticsLock.Lock()
defer me.statisticsLock.Unlock() defer me.statisticsLock.Unlock()
...@@ -49,103 +72,116 @@ func (me *TimingPathFilesystem) Latencies() map[string]float64 { ...@@ -49,103 +72,116 @@ func (me *TimingPathFilesystem) Latencies() map[string]float64 {
return r return r
} }
func (me *TimingPathFilesystem) HotPaths(operation string) (paths []string, uniquePaths int) {
me.statisticsLock.Lock()
defer me.statisticsLock.Unlock()
counts := me.pathCounts[operation]
results := make([]string, 0, len(counts))
for k, v := range counts {
results = append(results, fmt.Sprintf("% 9d %s", v, k))
}
sort.SortStrings(results)
return results, len(counts)
}
func (me *TimingPathFilesystem) GetAttr(name string) (*Attr, Status) { func (me *TimingPathFilesystem) GetAttr(name string) (*Attr, Status) {
defer me.startTimer("GetAttr")() defer me.startTimer("GetAttr", name)()
return me.original.GetAttr(name) return me.original.GetAttr(name)
} }
func (me *TimingPathFilesystem) GetXAttr(name string, attr string) ([]byte, Status) { func (me *TimingPathFilesystem) GetXAttr(name string, attr string) ([]byte, Status) {
defer me.startTimer("GetXAttr")() defer me.startTimer("GetXAttr", name)()
return me.original.GetXAttr(name, attr) return me.original.GetXAttr(name, attr)
} }
func (me *TimingPathFilesystem) Readlink(name string) (string, Status) { func (me *TimingPathFilesystem) Readlink(name string) (string, Status) {
defer me.startTimer("Readlink")() defer me.startTimer("Readlink", name)()
return me.original.Readlink(name) return me.original.Readlink(name)
} }
func (me *TimingPathFilesystem) Mknod(name string, mode uint32, dev uint32) Status { func (me *TimingPathFilesystem) Mknod(name string, mode uint32, dev uint32) Status {
defer me.startTimer("Mknod")() defer me.startTimer("Mknod", name)()
return me.original.Mknod(name, mode, dev) return me.original.Mknod(name, mode, dev)
} }
func (me *TimingPathFilesystem) Mkdir(name string, mode uint32) Status { func (me *TimingPathFilesystem) Mkdir(name string, mode uint32) Status {
defer me.startTimer("Mkdir")() defer me.startTimer("Mkdir", name)()
return me.original.Mkdir(name, mode) return me.original.Mkdir(name, mode)
} }
func (me *TimingPathFilesystem) Unlink(name string) (code Status) { func (me *TimingPathFilesystem) Unlink(name string) (code Status) {
defer me.startTimer("Unlink")() defer me.startTimer("Unlink", name)()
return me.original.Unlink(name) return me.original.Unlink(name)
} }
func (me *TimingPathFilesystem) Rmdir(name string) (code Status) { func (me *TimingPathFilesystem) Rmdir(name string) (code Status) {
defer me.startTimer("Rmdir")() defer me.startTimer("Rmdir", name)()
return me.original.Rmdir(name) return me.original.Rmdir(name)
} }
func (me *TimingPathFilesystem) Symlink(value string, linkName string) (code Status) { func (me *TimingPathFilesystem) Symlink(value string, linkName string) (code Status) {
defer me.startTimer("Symlink")() defer me.startTimer("Symlink", linkName)()
return me.original.Symlink(value, linkName) return me.original.Symlink(value, linkName)
} }
func (me *TimingPathFilesystem) Rename(oldName string, newName string) (code Status) { func (me *TimingPathFilesystem) Rename(oldName string, newName string) (code Status) {
defer me.startTimer("Rename")() defer me.startTimer("Rename", oldName)()
return me.original.Rename(oldName, newName) return me.original.Rename(oldName, newName)
} }
func (me *TimingPathFilesystem) Link(oldName string, newName string) (code Status) { func (me *TimingPathFilesystem) Link(oldName string, newName string) (code Status) {
defer me.startTimer("Link")() defer me.startTimer("Link", newName)()
return me.original.Link(oldName, newName) return me.original.Link(oldName, newName)
} }
func (me *TimingPathFilesystem) Chmod(name string, mode uint32) (code Status) { func (me *TimingPathFilesystem) Chmod(name string, mode uint32) (code Status) {
defer me.startTimer("Chmod")() defer me.startTimer("Chmod", name)()
return me.original.Chmod(name, mode) return me.original.Chmod(name, mode)
} }
func (me *TimingPathFilesystem) Chown(name string, uid uint32, gid uint32) (code Status) { func (me *TimingPathFilesystem) Chown(name string, uid uint32, gid uint32) (code Status) {
defer me.startTimer("Chown")() defer me.startTimer("Chown", name)()
return me.original.Chown(name, uid, gid) return me.original.Chown(name, uid, gid)
} }
func (me *TimingPathFilesystem) Truncate(name string, offset uint64) (code Status) { func (me *TimingPathFilesystem) Truncate(name string, offset uint64) (code Status) {
defer me.startTimer("Truncate")() defer me.startTimer("Truncate", name)()
return me.original.Truncate(name, offset) return me.original.Truncate(name, offset)
} }
func (me *TimingPathFilesystem) Open(name string, flags uint32) (file RawFuseFile, code Status) { func (me *TimingPathFilesystem) Open(name string, flags uint32) (file RawFuseFile, code Status) {
defer me.startTimer("Open")() defer me.startTimer("Open", name)()
return me.original.Open(name, flags) return me.original.Open(name, flags)
} }
func (me *TimingPathFilesystem) OpenDir(name string) (stream chan DirEntry, status Status) { func (me *TimingPathFilesystem) OpenDir(name string) (stream chan DirEntry, status Status) {
defer me.startTimer("OpenDir")() defer me.startTimer("OpenDir", name)()
return me.original.OpenDir(name) return me.original.OpenDir(name)
} }
func (me *TimingPathFilesystem) Mount(conn *PathFileSystemConnector) Status { func (me *TimingPathFilesystem) Mount(conn *PathFileSystemConnector) Status {
defer me.startTimer("Mount")() defer me.startTimer("Mount", "")()
return me.original.Mount(conn) return me.original.Mount(conn)
} }
func (me *TimingPathFilesystem) Unmount() { func (me *TimingPathFilesystem) Unmount() {
defer me.startTimer("Unmount")() defer me.startTimer("Unmount", "")()
me.original.Unmount() me.original.Unmount()
} }
func (me *TimingPathFilesystem) Access(name string, mode uint32) (code Status) { func (me *TimingPathFilesystem) Access(name string, mode uint32) (code Status) {
defer me.startTimer("Access")() defer me.startTimer("Access", name)()
return me.original.Access(name, mode) return me.original.Access(name, mode)
} }
func (me *TimingPathFilesystem) Create(name string, flags uint32, mode uint32) (file RawFuseFile, code Status) { func (me *TimingPathFilesystem) Create(name string, flags uint32, mode uint32) (file RawFuseFile, code Status) {
defer me.startTimer("Create")() defer me.startTimer("Create", name)()
return me.original.Create(name, flags, mode) return me.original.Create(name, flags, mode)
} }
func (me *TimingPathFilesystem) Utimens(name string, AtimeNs uint64, CtimeNs uint64) (code Status) { func (me *TimingPathFilesystem) Utimens(name string, AtimeNs uint64, CtimeNs uint64) (code Status) {
defer me.startTimer("Utimens")() defer me.startTimer("Utimens", name)()
return me.original.Utimens(name, AtimeNs, CtimeNs) return me.original.Utimens(name, AtimeNs, CtimeNs)
} }
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