Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Levin Zimmermann
go-fuse
Commits
ea239fe1
Commit
ea239fe1
authored
Sep 05, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a C baseline for the benchmark.
parent
3583ef4b
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
183 additions
and
22 deletions
+183
-22
README
README
+8
-8
all.bash
all.bash
+2
-0
benchmark/Makefile
benchmark/Makefile
+3
-0
benchmark/benchmark.go
benchmark/benchmark.go
+8
-4
benchmark/stat_test.go
benchmark/stat_test.go
+74
-10
benchmark/statfs.cc
benchmark/statfs.cc
+88
-0
No files found.
README
View file @
ea239fe1
...
...
@@ -39,7 +39,7 @@ EXAMPLES
* fuse/loopback.go mounts another piece of the filesystem.
Functionally, it is similar to a symlink. A binary to run is in
example/loopback/ . For example
i
example/loopback/ . For example
mkdir /tmp/mountpoint
example/loopback/loopback -debug /tmp/mountpoint /some/other/directory &
...
...
@@ -69,18 +69,18 @@ Tested on:
BENCHMARKS
We use threaded stats over a read-only filesystem for benchmarking. A
script to do this is in example/benchmark.sh. A libfuse baseline is
given by running the same test against archivemount
(http://www.cybernoia.de/software/archivemount/), with the locks in
its GetAttr implementation removed.
We use threaded stats over a read-only filesystem for benchmarking.
Automated code is under benchmark/ .sh. A simple C version of the
same FS gives a FUSe baselin
Data points (time per stat, Go-FUSE version
May 1
), using java 1.6
Data points (time per stat, Go-FUSE version
Sep 3
), using java 1.6
src.zip (7000 files).
platform libfuse Go-FUSE difference (%)
Lenovo T60 (2cpu) 83us 99us 19%
Lenovo T60 (2cpu) 106us 125us 18%
(todo - revise timings below: )
Lenovo T400 (2cpu) 38us 58us 52%
DellT3500/Lucid (2cpu) 34us(*) 35us 3%
DellT3500/Lucid (6cpu) 59us 76us 28%
...
...
all.bash
View file @
ea239fe1
...
...
@@ -3,6 +3,7 @@ set -eux
rm
-f
fuse/version.gen.go
for
target
in
"clean"
""
"
$@
"
;
do
for
d
in
fuse benchmark zipfs unionfs
\
example/hello example/loopback example/zipfs
\
...
...
@@ -18,6 +19,7 @@ do
(
cd
$d
&&
gotest
)
done
gomake
-C
benchmark cstatfs
for
d
in
benchmark
do
(
cd
$d
&&
gotest
-test
.bench
'.*'
-test
.cpu 1,2
)
...
...
benchmark/Makefile
View file @
ea239fe1
...
...
@@ -6,3 +6,6 @@ TARG=github.com/hanwen/go-fuse/benchmark
GOFILES
=
benchmark.go
include
$(GOROOT)/src/Make.pkg
cstatfs
:
statfs.cc
g++
-Wall
-std
=
c++0x
`
pkg-config fuse
--cflags
--libs
`
$<
-o
$@
benchmark/benchmark.go
View file @
ea239fe1
...
...
@@ -4,6 +4,7 @@ package fuse
import
(
"fmt"
"log"
"math"
"os"
"regexp"
...
...
@@ -28,7 +29,10 @@ func BulkStat(parallelism int, files []string) float64 {
}
t
:=
time
.
Nanoseconds
()
os
.
Lstat
(
fn
)
_
,
err
:=
os
.
Lstat
(
fn
)
if
err
!=
nil
{
log
.
Fatal
(
"All stats should succeed:"
,
err
)
}
dts
<-
time
.
Nanoseconds
()
-
t
}
}()
...
...
@@ -77,9 +81,9 @@ func AnalyzeBenchmarkRuns(times []float64) {
fmt
.
Printf
(
"%d samples
\n
"
+
"avg %.
2f ms 2sigma %.2
f "
+
"median %.
2
fms
\n
"
+
"10%%tile %.
2fms, 90%%tile %.2
fms
\n
"
,
"avg %.
3f ms 2sigma %.3
f "
+
"median %.
3
fms
\n
"
+
"10%%tile %.
3fms, 90%%tile %.3
fms
\n
"
,
len
(
times
),
avg
,
2
*
stddev
,
median
,
perc10
,
perc90
)
}
...
...
benchmark/stat_test.go
View file @
ea239fe1
...
...
@@ -2,13 +2,15 @@ package fuse
import
(
"bufio"
"exec"
"fmt"
"github.com/hanwen/go-fuse/fuse"
"io/ioutil"
"log"
"os"
"github.com/hanwen/go-fuse/fuse"
"path/filepath"
"runtime"
"sort"
"strings"
"testing"
"time"
...
...
@@ -49,7 +51,6 @@ func (me *StatFs) GetAttr(name string, context *fuse.Context) (*os.FileInfo, fus
}
func
(
me
*
StatFs
)
OpenDir
(
name
string
,
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
status
fuse
.
Status
)
{
log
.
Printf
(
"OPENDIR '%v', %v %v"
,
name
,
me
.
entries
,
me
.
dirs
)
entries
:=
me
.
dirs
[
name
]
if
entries
==
nil
{
return
nil
,
fuse
.
ENOENT
...
...
@@ -128,18 +129,18 @@ func TestNewStatFs(t *testing.T) {
}
}
func
BenchmarkThreadedStat
(
b
*
testing
.
B
)
{
b
.
StopTimer
()
fs
:=
NewStatFs
()
func
GetTestLines
()
[]
string
{
wd
,
_
:=
os
.
Getwd
()
// Names from OpenJDK 1.6
f
,
err
:=
os
.
Open
(
wd
+
"/testpaths.txt"
)
fn
:=
wd
+
"/testpaths.txt"
f
,
err
:=
os
.
Open
(
fn
)
CheckSuccess
(
err
)
defer
f
.
Close
()
r
:=
bufio
.
NewReader
(
f
)
files
:=
[]
string
{}
l
:=
[]
string
{}
for
{
line
,
_
,
err
:=
r
.
ReadLine
()
if
line
==
nil
||
err
!=
nil
{
...
...
@@ -147,16 +148,24 @@ func BenchmarkThreadedStat(b *testing.B) {
}
fn
:=
string
(
line
)
files
=
append
(
files
,
fn
)
l
=
append
(
l
,
fn
)
}
return
l
}
func
BenchmarkThreadedStat
(
b
*
testing
.
B
)
{
b
.
StopTimer
()
fs
:=
NewStatFs
()
files
:=
GetTestLines
()
for
_
,
fn
:=
range
files
{
fs
.
add
(
fn
,
os
.
FileInfo
{
Mode
:
fuse
.
S_IFREG
|
0644
})
}
log
.
Printf
(
"Read %d file names"
,
len
(
files
))
if
len
(
files
)
==
0
{
log
.
Fatal
(
"no files added"
)
}
log
.
Printf
(
"Read %d file names"
,
len
(
files
))
ttl
:=
0.1
opts
:=
fuse
.
FileSystemOptions
{
EntryTimeout
:
ttl
,
...
...
@@ -197,3 +206,58 @@ func TestingBOnePass(b *testing.B, threads int, sleepTime float64, files []strin
}
return
results
}
func
BenchmarkCFuseThreadedStat
(
b
*
testing
.
B
)
{
log
.
Println
(
"benchmarking CFuse"
)
lines
:=
GetTestLines
()
unique
:=
map
[
string
]
int
{}
for
_
,
l
:=
range
lines
{
unique
[
l
]
=
1
dir
,
_
:=
filepath
.
Split
(
l
)
for
dir
!=
"/"
&&
dir
!=
""
{
unique
[
dir
]
=
1
dir
=
filepath
.
Clean
(
dir
)
dir
,
_
=
filepath
.
Split
(
dir
)
}
}
out
:=
[]
string
{}
for
k
,
_
:=
range
unique
{
out
=
append
(
out
,
k
)
}
f
,
err
:=
ioutil
.
TempFile
(
""
,
""
)
CheckSuccess
(
err
)
sort
.
Strings
(
out
)
for
_
,
k
:=
range
out
{
f
.
Write
([]
byte
(
fmt
.
Sprintf
(
"/%s
\n
"
,
k
)))
}
f
.
Close
()
log
.
Println
(
"Written:"
,
f
.
Name
())
mountPoint
:=
fuse
.
MakeTempDir
()
wd
,
_
:=
os
.
Getwd
()
cmd
:=
exec
.
Command
(
wd
+
"/cstatfs"
,
mountPoint
)
cmd
.
Env
=
append
(
os
.
Environ
(),
fmt
.
Sprintf
(
"STATFS_INPUT=%s"
,
f
.
Name
()))
cmd
.
Start
()
bin
,
err
:=
exec
.
LookPath
(
"fusermount"
)
CheckSuccess
(
err
)
stop
:=
exec
.
Command
(
bin
,
"-u"
,
mountPoint
)
CheckSuccess
(
err
)
defer
stop
.
Run
()
for
i
,
l
:=
range
lines
{
lines
[
i
]
=
filepath
.
Join
(
mountPoint
,
l
)
}
// Wait for the daemon to mount.
time
.
Sleep
(
0.2e9
)
ttl
:=
1.0
log
.
Println
(
"N = "
,
b
.
N
)
threads
:=
runtime
.
GOMAXPROCS
(
0
)
results
:=
TestingBOnePass
(
b
,
threads
,
ttl
*
1.2
,
lines
)
AnalyzeBenchmarkRuns
(
results
)
}
benchmark/statfs.cc
0 → 100644
View file @
ea239fe1
//
// g++ -Wall `pkg-config fuse --cflags --libs` statfs.cc -o statfs
#include <unordered_map>
#include <string>
using
std
::
string
;
using
std
::
unordered_map
;
#define FUSE_USE_VERSION 26
extern
"C"
{
#include <fuse.h>
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
class
StatFs
{
public:
void
readFrom
(
const
string
&
fn
);
unordered_map
<
string
,
bool
>
is_dir_
;
int
GetAttr
(
const
char
*
name
,
struct
stat
*
statbuf
)
{
if
(
strcmp
(
name
,
"/"
)
==
0
)
{
statbuf
->
st_mode
=
S_IFDIR
|
0777
;
return
0
;
}
unordered_map
<
string
,
bool
>::
const_iterator
it
(
is_dir_
.
find
(
name
));
if
(
it
==
is_dir_
.
end
())
{
return
-
ENOENT
;
}
if
(
it
->
second
)
{
statbuf
->
st_mode
=
S_IFDIR
|
0777
;
}
else
{
statbuf
->
st_nlink
=
1
;
statbuf
->
st_mode
=
S_IFREG
|
0666
;
}
return
0
;
}
};
StatFs
*
global
;
int
global_getattr
(
const
char
*
name
,
struct
stat
*
statbuf
)
{
return
global
->
GetAttr
(
name
,
statbuf
);
}
void
StatFs
::
readFrom
(
const
string
&
fn
)
{
FILE
*
f
=
fopen
(
fn
.
c_str
(),
"r"
);
char
line
[
1024
];
while
(
char
*
s
=
fgets
(
line
,
sizeof
(
line
),
f
))
{
int
l
=
strlen
(
s
);
if
(
line
[
l
-
1
]
==
'\n'
)
{
line
[
l
-
1
]
=
'\0'
;
l
--
;
}
bool
is_dir
=
line
[
l
-
1
]
==
'/'
;
if
(
is_dir
)
{
line
[
l
-
1
]
=
'\0'
;
}
is_dir_
[
line
]
=
is_dir
;
}
fclose
(
f
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
global
=
new
StatFs
;
// don't want to know about fuselib's option handling
char
*
in
=
getenv
(
"STATFS_INPUT"
);
if
(
!
in
||
!*
in
)
{
fprintf
(
stderr
,
"pass file in $STATFS_INPUT
\n
"
);
exit
(
2
);
}
global
->
readFrom
(
in
);
struct
fuse_operations
statfs_oper
=
{
0
};
statfs_oper
.
getattr
=
&
global_getattr
;
return
fuse_main
(
argc
,
argv
,
&
statfs_oper
,
NULL
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment