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

Optimize pathInode.GetPath().

* Hand code a reverse string join.
* Do not use defer.

Speed up: 7%
parent fff4a3ab
......@@ -4,9 +4,8 @@ GO-FUSE: native bindings for the FUSE kernel module.
HIGHLIGHTS
* High speed: about 50% slower than libfuse, using the gc
compiler. For most real world applications, the difference will be
negligible.
* High speed: as fast as libfuse using the gc compiler for single
threaded loads.
* Supports in-process mounting of different FileSystems onto
subdirectories of the FUSE mount.
......@@ -80,9 +79,9 @@ interface, all kernel caching turned off, median stat time:
platform libfuse Go-FUSE difference (%)
Lenovo T60/Fedora17 (1cpu) 349us 379us 9% slower
Lenovo T400/Lucid (1cpu) 133us 140us 5% slower
Dell T3500/Lucid (1cpu) 78us 78us 0%
Lenovo T60/Fedora17 (1cpu) 349us 355us 2% slower
//Lenovo T400/Lucid (1cpu) 133us 140us 5% slower
//Dell T3500/Lucid (1cpu) 78us 78us 0%
CREDITS
......
......@@ -8,7 +8,6 @@ import (
"log"
"os"
"reflect"
"strings"
"syscall"
"time"
"unsafe"
......@@ -88,14 +87,6 @@ func Version() string {
return "unknown"
}
func ReverseJoin(rev_components []string, sep string) string {
components := make([]string, len(rev_components))
for i, v := range rev_components {
components[len(rev_components)-i-1] = v
}
return strings.Join(components, sep)
}
func CurrentOwner() *Owner {
return &Owner{
Uid: uint32(os.Getuid()),
......
......@@ -49,3 +49,4 @@ func TestLinkAt(t *testing.T) {
t.Fatal("Ino mismatch", s1, s2)
}
}
......@@ -219,18 +219,42 @@ func (n *pathInode) RLockTree() func() {
// GetPath returns the path relative to the mount governing this
// inode. It returns nil for mount if the file was deleted or the
// filesystem unmounted.
func (n *pathInode) GetPath() (path string) {
defer n.RLockTree()()
func (n *pathInode) GetPath() string {
if n == n.pathFs.root {
return ""
}
pathLen := 0
// The simple solution is to collect names, and reverse join
// them, them, but since this is a hot path, we take some
// effort to avoid allocations.
rev_components := make([]string, 0, 10)
n.pathFs.pathLock.RLock()
p := n
for ; p.Parent != nil; p = p.Parent {
rev_components = append(rev_components, p.Name)
pathLen += len(p.Name) + 1
}
pathLen--
if p != p.pathFs.root {
n.pathFs.pathLock.RUnlock()
return ".deleted"
}
path = ReverseJoin(rev_components, "/")
pathBytes := make([]byte, pathLen)
end := len(pathBytes)
for p = n; p.Parent != nil; p = p.Parent {
l := len(p.Name)
copy(pathBytes[end - l:], p.Name)
end -= len(p.Name) + 1
if end > 0 {
pathBytes[end] = '/'
}
}
n.pathFs.pathLock.RUnlock()
path := string(pathBytes)
if n.pathFs.Debug {
log.Printf("Inode %d = %q (%s)", n.Inode().nodeId, path, n.fs.String())
}
......
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