mirror of
https://github.com/anchore/syft.git
synced 2026-10-11 21:57:22 +02:00
Stop reading the mount table for every single-file source (#5257)
Signed-off-by: Darragh McGurk <120114728+dmcg310@users.noreply.github.com>
This commit is contained in:
@@ -29,11 +29,15 @@ func newFileIndexer(path, base string, visitors ...PathIndexVisitor) *fileIndexe
|
|||||||
base: base,
|
base: base,
|
||||||
tree: filetree.New(),
|
tree: filetree.New(),
|
||||||
index: filetree.NewIndex(),
|
index: filetree.NewIndex(),
|
||||||
|
// Unlike the directory indexer there is no skipPathsByMountTypeAndName here: it exists
|
||||||
|
// to keep a directory walk out of /proc, /sys and similar, and to do so it reads the
|
||||||
|
// whole mount table on construction. A file source indexes exactly one file and its
|
||||||
|
// parent, so there is nothing to walk into, and the mount table read is paid for
|
||||||
|
// every file source with nothing in return.
|
||||||
pathIndexVisitors: append(
|
pathIndexVisitors: append(
|
||||||
[]PathIndexVisitor{
|
[]PathIndexVisitor{
|
||||||
requireFileInfo,
|
requireFileInfo,
|
||||||
disallowByFileType,
|
disallowByFileType,
|
||||||
skipPathsByMountTypeAndName(path),
|
|
||||||
},
|
},
|
||||||
visitors...,
|
visitors...,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package fileresolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/moby/sys/mountinfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BenchmarkNewFromFile is the cost of building a resolver for a single-file source, which is
|
||||||
|
// paid once per file by callers that catalog files individually. The default case is
|
||||||
|
// NewFromFile as shipped. The with-mount-skipper case attaches skipPathsByMountTypeAndName
|
||||||
|
// the way the file indexer used to, so the difference is what reading the mount table for
|
||||||
|
// every file source cost. That cost scales with the mount table, so its size is reported as
|
||||||
|
// the mounts metric: expect a bigger gap on a container host than on a laptop.
|
||||||
|
//
|
||||||
|
// go test ./syft/internal/fileresolver/ -run '^$' -bench NewFromFile -benchmem -count 6 | tee bench.txt
|
||||||
|
// benchstat -col /variant bench.txt
|
||||||
|
func BenchmarkNewFromFile(b *testing.B) {
|
||||||
|
path := filepath.Join(b.TempDir(), "file.txt")
|
||||||
|
if err := os.WriteFile(path, []byte("hello\n"), 0o644); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
mounts, err := mountinfo.GetMounts(nil)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("variant=default", func(b *testing.B) {
|
||||||
|
for b.Loop() {
|
||||||
|
if _, err := NewFromFile(path); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.ReportMetric(float64(len(mounts)), "mounts")
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("variant=with-mount-skipper", func(b *testing.B) {
|
||||||
|
for b.Loop() {
|
||||||
|
r, err := newFromFileWithoutIndex(path, skipPathsByMountTypeAndName(path))
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := r.buildIndex(); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.ReportMetric(float64(len(mounts)), "mounts")
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user