From: Bjørn Erik Pedersen Date: Tue, 18 Nov 2025 12:58:19 +0000 (+0100) Subject: performance: Misc allocation improvements X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=f33c1a3fdb6ac019e97f8bcbd044c6aab0a88c68;p=brevno-suite%2Fhugo performance: Misc allocation improvements ``` │ stash.bench │ perf-allloc20251118.bench │ │ sec/op │ sec/op vs base │ CreateShortcodePlaceholders-10 54.16n ± ∞ ¹ 39.06n ± ∞ ¹ -27.87% (p=0.029 n=4) ¹ need >= 6 samples for confidence interval at level 0.95 │ stash.bench │ perf-allloc20251118.bench │ │ B/op │ B/op vs base │ CreateShortcodePlaceholders-10 52.00 ± ∞ ¹ 48.00 ± ∞ ¹ -7.69% (p=0.029 n=4) ¹ need >= 6 samples for confidence interval at level 0.95 │ stash.bench │ perf-allloc20251118.bench │ │ allocs/op │ allocs/op vs base │ CreateShortcodePlaceholders-10 2.000 ± ∞ ¹ 1.000 ± ∞ ¹ -50.00% (p=0.029 n=4) ¹ need >= 6 samples for confidence interval at level 0.95 ```` --- diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index a01f93b75..e89ad222a 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -86,7 +86,7 @@ type HugoSites struct { // Cache for page listings. cachePages *dynacache.Partition[string, page.Pages] // Cache for content sources. - cacheContentSource *dynacache.Partition[string, *resources.StaleValue[[]byte]] + cacheContentSource *dynacache.Partition[uint64, *resources.StaleValue[[]byte]] // Before Hugo 0.122.0 we managed all translations in a map using a translationKey // that could be overridden in front matter. diff --git a/hugolib/page__content.go b/hugolib/page__content.go index ba164e549..f1ed435e9 100644 --- a/hugolib/page__content.go +++ b/hugolib/page__content.go @@ -19,7 +19,6 @@ import ( "fmt" "html/template" "io" - "strconv" "strings" "sync/atomic" "unicode/utf8" @@ -69,12 +68,6 @@ func (m *pageMetaSource) parseFrontMatter( h *HugoSites, sid uint64, ) error { - var sourceKey string - - if sourceKey == "" { - sourceKey = strconv.FormatUint(sid, 10) - } - var filename string if m.f != nil { filename = m.f.Filename() @@ -83,7 +76,6 @@ func (m *pageMetaSource) parseFrontMatter( m.pi = &contentParseInfo{ h: h, sid: sid, - sourceKey: sourceKey, openSource: m.openSource, shortcodeParseInfo: newShortcodeHandler(filename, h.Deps), } @@ -163,8 +155,7 @@ func (c *cachedContent) getOrCreateScope(scope string, pco *pageContentOutput) * type contentParseInfo struct { h *HugoSites - sid uint64 - sourceKey string + sid uint64 // The source bytes. openSource hugio.OpenReadSeekCloser @@ -323,7 +314,7 @@ Loop: currShortcode.pos = it.Pos() currShortcode.length = iter.Current().Pos() - it.Pos() if currShortcode.placeholder == "" { - currShortcode.placeholder = createShortcodePlaceholder("s", pi.sid, currShortcode.ordinal) + currShortcode.placeholder = createShortcodePlaceholder("s", pi.sid, uint64(currShortcode.ordinal)) } if currShortcode.name != "" { @@ -335,7 +326,7 @@ Loop: currShortcode.params = s } - currShortcode.placeholder = createShortcodePlaceholder("s", pi.sid, ordinal) + currShortcode.placeholder = createShortcodePlaceholder("s", pi.sid, uint64(ordinal)) ordinal++ s.shortcodes = append(s.shortcodes, currShortcode) @@ -390,10 +381,10 @@ func (c *cachedContent) mustSource() []byte { } func (pi *contentParseInfo) contentSource(s resource.StaleInfo) ([]byte, error) { - key := pi.sourceKey + key := pi.sid versionv := s.StaleVersion() - v, err := pi.h.cacheContentSource.GetOrCreate(key, func(string) (*resources.StaleValue[[]byte], error) { + v, err := pi.h.cacheContentSource.GetOrCreate(key, func(uint64) (*resources.StaleValue[[]byte], error) { b, err := pi.readSourceAll() if err != nil { return nil, err @@ -457,13 +448,13 @@ type contentPlainPlainWords struct { } func (c *cachedContentScope) keyScope(ctx context.Context) string { - return hugo.GetMarkupScope(ctx) + c.pco.po.f.Name + return hugo.GetMarkupScope(ctx) + c.pco.po.f.Name + fmt.Sprintf("_%d", c.pi.sid) } func (c *cachedContentScope) contentRendered(ctx context.Context) (contentSummary, error) { cp := c.pco ctx = tpl.Context.DependencyScope.Set(ctx, pageDependencyScopeGlobal) - key := c.pi.sourceKey + "/" + c.keyScope(ctx) + key := c.keyScope(ctx) versionv := c.version(cp) @@ -616,7 +607,7 @@ var setGetContentCallbackInContext = contexthelpers.NewContextDispatcher[func(*p func (c *cachedContentScope) contentToC(ctx context.Context) (contentTableOfContents, error) { cp := c.pco - key := c.pi.sourceKey + "/" + c.keyScope(ctx) + key := c.keyScope(ctx) versionv := c.version(cp) v, err := c.pm.contentTableOfContents.GetOrCreate(key, func(string) (*resources.StaleValue[contentTableOfContents], error) { @@ -737,7 +728,7 @@ func (c *cachedContent) version(cp *pageContentOutput) uint32 { func (c *cachedContentScope) contentPlain(ctx context.Context) (contentPlainPlainWords, error) { cp := c.pco - key := c.pi.sourceKey + "/" + c.keyScope(ctx) + key := c.keyScope(ctx) versionv := c.version(cp) diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go index ec6e25cd6..78edd8135 100644 --- a/hugolib/shortcode.go +++ b/hugolib/shortcode.go @@ -192,8 +192,8 @@ func (scp *ShortcodeWithPage) Unwrapv() any { // Note - this value must not contain any markup syntax const shortcodePlaceholderPrefix = "HAHAHUGOSHORTCODE" -func createShortcodePlaceholder(sid string, id uint64, ordinal int) string { - return shortcodePlaceholderPrefix + strconv.FormatUint(id, 10) + sid + strconv.Itoa(ordinal) + "HBHB" +func createShortcodePlaceholder(sid string, id, ordinal uint64) string { + return shortcodePlaceholderPrefix + strconv.FormatUint(id, 10) + sid + strconv.FormatUint(ordinal, 10) + "HBHB" } type shortcode struct { diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go new file mode 100644 index 000000000..dceb93be4 --- /dev/null +++ b/hugolib/shortcode_test.go @@ -0,0 +1,23 @@ +// Copyright 2025 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package hugolib + +import "testing" + +func BenchmarkCreateShortcodePlaceholders(b *testing.B) { + var ordinal int = 42 + for b.Loop() { + createShortcodePlaceholder("shortcodeName", 32, uint64(ordinal)) + } +} diff --git a/hugolib/site.go b/hugolib/site.go index ce0331200..edcf2548a 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -451,7 +451,7 @@ func newHugoSites( page.Pages](d.MemCache, "/pags/all", dynacache.OptionsPartition{Weight: 10, ClearWhen: dynacache.ClearOnRebuild}, ), - cacheContentSource: dynacache.GetOrCreatePartition[string, *resources.StaleValue[[]byte]](d.MemCache, "/cont/src", dynacache.OptionsPartition{Weight: 70, ClearWhen: dynacache.ClearOnChange}), + cacheContentSource: dynacache.GetOrCreatePartition[uint64, *resources.StaleValue[[]byte]](d.MemCache, "/cont/src", dynacache.OptionsPartition{Weight: 70, ClearWhen: dynacache.ClearOnChange}), translationKeyPages: maps.NewSliceCache[page.Page](), currentSite: first[0], skipRebuildForFilenames: make(map[string]bool), diff --git a/hugolib/sitesmatrix/vectorstores_test.go b/hugolib/sitesmatrix/vectorstores_test.go index 45015afdd..3f5bd5905 100644 --- a/hugolib/sitesmatrix/vectorstores_test.go +++ b/hugolib/sitesmatrix/vectorstores_test.go @@ -398,11 +398,22 @@ func BenchmarkSets(b *testing.B) { } }) - b.Run("HasAnyVector", func(b *testing.B) { + b.Run("HasAnyVector(Sets)", func(b *testing.B) { for b.Loop() { _ = sets1.HasAnyVector(sets2) } }) + b.Run("HasAnyVector(Vector)", func(b *testing.B) { + for b.Loop() { + _ = sets1.HasAnyVector(v1) + } + }) + + b.Run("HasAnyVector(&Vector)", func(b *testing.B) { + for b.Loop() { + _ = sets1.HasAnyVector(&v1) + } + }) b.Run("FirstVector", func(b *testing.B) { for b.Loop() {