Summary
os.ReadDir returns fs.DirEntry values that already carry IsDir() (and on most filesystems, the type is reported by getdents64/readdir without an extra stat). find-replace ignores this and immediately calls os.Stat on every entry via File.Info():
func (fr *findReplace) HandleFile(f *File) {
if f.Info().IsDir() { ... } // <- os.Stat
...
}
For a tree with N entries this doubles the syscall count. On a tree the size of the OpenStack nova repo (the README's benchmark target, ~6k files), that's ~6k extra syscalls per run.
Impact (Performance: Medium)
Suggested Fix
- Pass the
fs.DirEntry from ReadDir directly into HandleFile, and use entry.Type() / entry.IsDir() / entry.Info() only when needed (and Info() on a DirEntry is itself often free on Unix).
- Remove the lazy
os.Stat in File.Info() for the dispatch decision.
Files
find_replace.go:54-73, 79-94
file_handling.go:34-43
Summary
os.ReadDirreturnsfs.DirEntryvalues that already carryIsDir()(and on most filesystems, the type is reported bygetdents64/readdirwithout an extra stat).find-replaceignores this and immediately callsos.Staton every entry viaFile.Info():For a tree with N entries this doubles the syscall count. On a tree the size of the OpenStack
novarepo (the README's benchmark target, ~6k files), that's ~6k extra syscalls per run.Impact (Performance: Medium)
statis a roundtrip.Suggested Fix
fs.DirEntryfromReadDirdirectly intoHandleFile, and useentry.Type()/entry.IsDir()/entry.Info()only when needed (andInfo()on aDirEntryis itself often free on Unix).os.StatinFile.Info()for the dispatch decision.Files
find_replace.go:54-73, 79-94file_handling.go:34-43