os: reduce allocations in Readdir on unix

Include syscall.Stat_t on unix to the
unexported fileStat structure rather than
accessing it though an interface.

Additionally add a benchmark for Readdir
(and Readdirnames).

Tested on linux, freebsd, netbsd, openbsd
darwin, solaris, does not touch windows
stuff. Does not change the API, as
discussed on golang-dev.

E.g. on linux/amd64 with a directory of 65 files:

benchmark              old ns/op     new ns/op     delta
BenchmarkReaddir-4     67774         66225         -2.29%

benchmark              old allocs     new allocs     delta
BenchmarkReaddir-4     334            269            -19.46%

benchmark              old bytes     new bytes     delta
BenchmarkReaddir-4     25208         24168         -4.13%

Change-Id: I44ef72a04ad7055523a980f29aa11122040ae8fe
Reviewed-on: https://go-review.googlesource.com/16423
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Taru Karttunen 2015-10-28 12:58:58 +02:00 committed by Brad Fitzpatrick
parent a21b4bca0c
commit f5f480e1df
12 changed files with 158 additions and 166 deletions

View file

@ -12,6 +12,10 @@ import (
"syscall"
)
func sameFile(fs1, fs2 *fileStat) bool {
return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
}
func rename(oldname, newname string) error {
e := syscall.Rename(oldname, newname)
if e != nil {
@ -152,23 +156,25 @@ func (f *File) Stat() (FileInfo, error) {
if f == nil {
return nil, ErrInvalid
}
var stat syscall.Stat_t
err := syscall.Fstat(f.fd, &stat)
var fs fileStat
err := syscall.Fstat(f.fd, &fs.sys)
if err != nil {
return nil, &PathError{"stat", f.name, err}
}
return fileInfoFromStat(&stat, f.name), nil
fillFileStatFromSys(&fs, f.name)
return &fs, nil
}
// Stat returns a FileInfo describing the named file.
// If there is an error, it will be of type *PathError.
func Stat(name string) (FileInfo, error) {
var stat syscall.Stat_t
err := syscall.Stat(name, &stat)
var fs fileStat
err := syscall.Stat(name, &fs.sys)
if err != nil {
return nil, &PathError{"stat", name, err}
}
return fileInfoFromStat(&stat, name), nil
fillFileStatFromSys(&fs, name)
return &fs, nil
}
// Lstat returns a FileInfo describing the named file.
@ -176,12 +182,13 @@ func Stat(name string) (FileInfo, error) {
// describes the symbolic link. Lstat makes no attempt to follow the link.
// If there is an error, it will be of type *PathError.
func Lstat(name string) (FileInfo, error) {
var stat syscall.Stat_t
err := syscall.Lstat(name, &stat)
var fs fileStat
err := syscall.Lstat(name, &fs.sys)
if err != nil {
return nil, &PathError{"lstat", name, err}
}
return fileInfoFromStat(&stat, name), nil
fillFileStatFromSys(&fs, name)
return &fs, nil
}
func (f *File) readdir(n int) (fi []FileInfo, err error) {