tpl: Add a partial lookup cache

````
                 │ stash.bench  │          perf-v146.bench           │
                 │    sec/op    │   sec/op     vs base               │
LookupPartial-10   248.00n ± 0%   14.75n ± 2%  -94.05% (p=0.002 n=6)

                 │ stash.bench │          perf-v146.bench          │
                 │    B/op     │   B/op     vs base                │
LookupPartial-10    48.00 ± 0%   0.00 ± 0%  -100.00% (p=0.002 n=6)

                 │ stash.bench │          perf-v146.bench           │
                 │  allocs/op  │ allocs/op   vs base                │
LookupPartial-10    3.000 ± 0%   0.000 ± 0%  -100.00% (p=0.002 n=6)
```

THe speedup above assumes reuse of the same partials over and over again, which I think is not uncommon.

This commits also adds some more lookup benchmarks. The current output of these on my MacBook looks decent:

```
BenchmarkLookupPagesLayout/Single_root-10                3031562               395.5 ns/op             0 B/op          0 allocs/op
BenchmarkLookupPagesLayout/Single_sub_folder-10          2515915               480.9 ns/op             0 B/op          0 allocs/op
BenchmarkLookupPartial-10                               84808112                14.13 ns/op            0 B/op          0 allocs/op
BenchmarkLookupShortcode/toplevelpage-10                 8111779               148.2 ns/op             0 B/op          0 allocs/op
BenchmarkLookupShortcode/nestedpage-10                   8088183               148.6 ns/op             0 B/op          0 allocs/op
```

Note that in the above the partial lookups are cahced, the others not (they are harder to cache because of the page path).

Closes #13571
This commit is contained in:
Bjørn Erik Pedersen 2025-04-10 09:22:29 +02:00
parent 18d2d2f985
commit 208a0de6c3
11 changed files with 158 additions and 73 deletions

View file

@ -8,6 +8,7 @@ import (
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/hugolib"
"github.com/gohugoio/hugo/resources/kinds"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/tpl/tplimpl"
)
@ -849,7 +850,7 @@ func BenchmarkExecuteWithContext(b *testing.B) {
disableKinds = ["taxonomy", "term", "home"]
-- layouts/all.html --
{{ .Title }}|
{{ partial "p1.html" . }}
{{ partial "p1.html" . }}
-- layouts/_partials/p1.html --
p1.
{{ partial "p2.html" . }}
@ -878,6 +879,82 @@ p3
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := store.ExecuteWithContext(context.Background(), ti, io.Discard, p)
bb.Assert(err, qt.IsNil)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkLookupPartial(b *testing.B) {
files := `
-- hugo.toml --
disableKinds = ["taxonomy", "term", "home"]
-- layouts/all.html --
{{ .Title }}|
-- layouts/_partials/p1.html --
-- layouts/_partials/p2.html --
-- layouts/_partials/p2.json --
-- layouts/_partials/p3.html --
`
bb := hugolib.Test(b, files)
store := bb.H.TemplateStore
for i := 0; i < b.N; i++ {
fi := store.LookupPartial("p3.html")
if fi == nil {
b.Fatal("not found")
}
}
}
// Implemented by pageOutput.
type getDescriptorProvider interface {
GetInternalTemplateBasePathAndDescriptor() (string, tplimpl.TemplateDescriptor)
}
func BenchmarkLookupShortcode(b *testing.B) {
files := `
-- hugo.toml --
disableKinds = ["taxonomy", "term", "home"]
-- content/toplevelpage.md --
-- content/a/b/c/nested.md --
-- layouts/all.html --
{{ .Title }}|
-- layouts/_shortcodes/s.html --
s1.
-- layouts/_shortcodes/a/b/s.html --
s2.
`
bb := hugolib.Test(b, files)
store := bb.H.TemplateStore
runOne := func(p page.Page) {
pth, desc := p.(getDescriptorProvider).GetInternalTemplateBasePathAndDescriptor()
q := tplimpl.TemplateQuery{
Path: pth,
Name: "s",
Category: tplimpl.CategoryShortcode,
Desc: desc,
}
v := store.LookupShortcode(q)
if v == nil {
b.Fatal("not found")
}
}
b.Run("toplevelpage", func(b *testing.B) {
toplevelpage, _ := bb.H.Sites[0].GetPage("/toplevelpage")
for i := 0; i < b.N; i++ {
runOne(toplevelpage)
}
})
b.Run("nestedpage", func(b *testing.B) {
toplevelpage, _ := bb.H.Sites[0].GetPage("/a/b/c/nested")
for i := 0; i < b.N; i++ {
runOne(toplevelpage)
}
})
}