// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package nfsfs import ( "fmt" "os" "path/filepath" "testing" ) const benchChunk = 64 << 10 // benchRoot builds a backend over a fresh directory with one file of the // given size, filled with a repeating pattern, and returns the backend // and the file handle. Setup runs once, outside the measured region. func benchRoot(b *testing.B, size int) (*Local, Handle) { b.Helper() root := b.TempDir() l, err := NewLocal(root) if err != nil { b.Fatalf("NewLocal: %v", err) } p := filepath.Join(root, "file") buf := make([]byte, 1<<20) for i := range buf { buf[i] = byte(i) } f, err := os.Create(p) if err != nil { b.Fatalf("Create: %v", err) } for written := 0; written < size; written += len(buf) { if _, err := f.Write(buf); err != nil { b.Fatalf("Write: %v", err) } } if err := f.Close(); err != nil { b.Fatalf("Close: %v", err) } rh, err := l.Root() if err != nil { b.Fatalf("Root: %v", err) } h, _, err := l.Lookup(rh, "file") if err != nil { b.Fatalf("Lookup: %v", err) } return l, h } // BenchmarkRead64K reads 64 KiB at a time from a 64 MiB file, cycling // through the offsets so every read touches pages the previous read left. func BenchmarkRead64K(b *testing.B) { l, h := benchRoot(b, 64<<20) off := int64(0) b.SetBytes(benchChunk) b.ResetTimer() for b.Loop() { if _, err := l.Read(h, off, benchChunk); err != nil { b.Fatalf("Read: %v", err) } off += benchChunk if off > 64<<20-benchChunk { off = 0 } } } // BenchmarkWrite64K writes 64 KiB at a time over a preallocated 64 MiB // file, cycling through the offsets, so no read has to grow the file. func BenchmarkWrite64K(b *testing.B) { l, h := benchRoot(b, 64<<20) buf := make([]byte, benchChunk) off := int64(0) b.SetBytes(benchChunk) b.ResetTimer() for b.Loop() { if _, err := l.Write(h, off, buf); err != nil { b.Fatalf("Write: %v", err) } off += benchChunk if off > 64<<20-benchChunk { off = 0 } } } // BenchmarkGetattr reports the attributes of one file. func BenchmarkGetattr(b *testing.B) { l, h := benchRoot(b, 1<<20) b.ResetTimer() for b.Loop() { if _, err := l.Getattr(h); err != nil { b.Fatalf("Getattr: %v", err) } } } // BenchmarkLookup resolves one name under the export root of a directory // holding a hundred files. func BenchmarkLookup(b *testing.B) { root := b.TempDir() l, err := NewLocal(root) if err != nil { b.Fatalf("NewLocal: %v", err) } rh, err := l.Root() if err != nil { b.Fatalf("Root: %v", err) } for i := range 100 { name := fmt.Sprintf("f%d", i) if err := os.WriteFile(filepath.Join(root, name), []byte("x"), 0o644); err != nil { b.Fatalf("WriteFile: %v", err) } } b.ResetTimer() i := 0 for b.Loop() { if _, _, err := l.Lookup(rh, fmt.Sprintf("f%d", i%100)); err != nil { b.Fatalf("Lookup: %v", err) } i++ } } // BenchmarkReadDirPage64 pages a 10 000 entry directory 64 entries at a // time after the first page: with the listing cache the cost of a page // is the page, and the benchmark holds that to the measurement. func BenchmarkReadDirPage64(b *testing.B) { root := b.TempDir() l, err := NewLocal(root) if err != nil { b.Fatalf("NewLocal: %v", err) } dir := filepath.Join(root, "big") if err := os.Mkdir(dir, 0o755); err != nil { b.Fatalf("Mkdir: %v", err) } for i := range 10000 { if err := os.WriteFile(filepath.Join(dir, fmt.Sprintf("f%04d", i)), []byte("x"), 0o644); err != nil { b.Fatalf("WriteFile: %v", err) } } rh, err := l.Root() if err != nil { b.Fatalf("Root: %v", err) } h, _, err := l.Lookup(rh, "big") if err != nil { b.Fatalf("Lookup: %v", err) } if _, err := l.ReadDir(h, 0, 64); err != nil { b.Fatalf("first page: %v", err) } b.ResetTimer() for b.Loop() { page, err := l.ReadDir(h, 0, 64) if err != nil { b.Fatalf("ReadDir: %v", err) } if len(page.Entries) != 64 || page.EOF { b.Fatalf("page: %d entries, eof %v", len(page.Entries), page.EOF) } } }