cmd/guru: re-use buffer for reading files
I felt guilty about leaving 2% on the table in CL 108878, so I thought I'd get it a different way. Teach readFile to accept a re-usable bytes.Buffer to read into, to reduce the amount of garbage created. To limit the possible memory impact of giant files, only re-use the buffer for the duration of a single package. Even that is enough to help. name old time/op new time/op delta Referrers 4.67s ± 3% 4.58s ± 2% -1.96% (p=0.029 n=10+10) name old user-time/op new user-time/op delta Referrers 16.5s ± 3% 15.8s ± 1% -4.39% (p=0.000 n=10+8) name old sys-time/op new sys-time/op delta Referrers 16.1s ± 3% 15.9s ± 3% ~ (p=0.218 n=10+10) This work supported by Sourcegraph. Change-Id: I594ef25c0fd5ccb766ff5b98dbbd1a75a7a4f957 Reviewed-on: https://go-review.googlesource.com/108935 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
c1f4e2c6dc
commit
5c8013c561
|
@ -436,12 +436,15 @@ func globalReferrersPkgLevel(q *Query, obj types.Object, fset *token.FileSet) er
|
|||
deffiles = make(map[string]*ast.File)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer) // reusable buffer for reading files
|
||||
|
||||
for _, file := range files {
|
||||
if !buildutil.IsAbsPath(q.Build, file) {
|
||||
file = buildutil.JoinPath(q.Build, pkg.Dir, file)
|
||||
}
|
||||
buf.Reset()
|
||||
sema <- struct{}{} // acquire token
|
||||
src, err := readFile(q.Build, file)
|
||||
src, err := readFile(q.Build, file, buf)
|
||||
<-sema // release token
|
||||
if err != nil {
|
||||
continue
|
||||
|
@ -731,7 +734,7 @@ func (r *referrersPackageResult) foreachRef(f func(id *ast.Ident, text string))
|
|||
// start asynchronous read.
|
||||
go func() {
|
||||
sema <- struct{}{} // acquire token
|
||||
content, err := readFile(r.build, posn.Filename)
|
||||
content, err := readFile(r.build, posn.Filename, nil)
|
||||
<-sema // release token
|
||||
if err != nil {
|
||||
fi.data <- err
|
||||
|
@ -769,14 +772,17 @@ func (r *referrersPackageResult) foreachRef(f func(id *ast.Ident, text string))
|
|||
|
||||
// readFile is like ioutil.ReadFile, but
|
||||
// it goes through the virtualized build.Context.
|
||||
func readFile(ctxt *build.Context, filename string) ([]byte, error) {
|
||||
// If non-nil, buf must have been reset.
|
||||
func readFile(ctxt *build.Context, filename string, buf *bytes.Buffer) ([]byte, error) {
|
||||
rc, err := buildutil.OpenFile(ctxt, filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
var buf bytes.Buffer
|
||||
if _, err := io.Copy(&buf, rc); err != nil {
|
||||
if buf == nil {
|
||||
buf = new(bytes.Buffer)
|
||||
}
|
||||
if _, err := io.Copy(buf, rc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
|
|
Loading…
Reference in New Issue