From 7855b47f07aed926a7992bf1ad03a8740f747457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Thu, 24 Nov 2022 12:13:19 +0100 Subject: [PATCH] Add a cache for lexers.Get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` name old time/op new time/op delta Codeblocks/Default-10 152ms ±11% 12ms ± 1% -92.44% (p=0.029 n=4+4) Codeblocks/Hook_no_higlight-10 142ms ± 0% 7ms ± 0% -95.36% (p=0.029 n=4+4) name old alloc/op new alloc/op delta Codeblocks/Default-10 11.9MB ± 0% 11.7MB ± 0% -1.59% (p=0.029 n=4+4) Codeblocks/Hook_no_higlight-10 4.62MB ± 1% 4.43MB ± 0% -4.08% (p=0.029 n=4+4) name old allocs/op new allocs/op delta Codeblocks/Default-10 209k ± 0% 209k ± 0% -0.03% (p=0.029 n=4+4) Codeblocks/Hook_no_higlight-10 68.4k ± 0% 68.3k ± 0% -0.06% (p=0.029 n=4+4) ``` --- hugolib/page__per_output.go | 4 +- markup/goldmark/codeblocks/render.go | 4 +- markup/highlight/chromalexers/chromalexers.go | 50 +++++++++++++++++++ markup/highlight/highlight.go | 3 +- tpl/transform/transform.go | 4 +- 5 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 markup/highlight/chromalexers/chromalexers.go diff --git a/hugolib/page__per_output.go b/hugolib/page__per_output.go index e8dc69507..60e3a7f59 100644 --- a/hugolib/page__per_output.go +++ b/hugolib/page__per_output.go @@ -33,10 +33,10 @@ import ( "github.com/spf13/cast" "github.com/gohugoio/hugo/markup/converter/hooks" + "github.com/gohugoio/hugo/markup/highlight/chromalexers" "github.com/gohugoio/hugo/markup/converter" - "github.com/alecthomas/chroma/v2/lexers" "github.com/gohugoio/hugo/lazy" bp "github.com/gohugoio/hugo/bufferpool" @@ -545,7 +545,7 @@ func (p *pageContentOutput) initRenderHooks() error { layoutDescriptor.Kind = "render-codeblock" if id != nil { lang := id.(string) - lexer := lexers.Get(lang) + lexer := chromalexers.Get(lang) if lexer != nil { layoutDescriptor.KindVariants = strings.Join(lexer.Config().Aliases, ",") } else { diff --git a/markup/goldmark/codeblocks/render.go b/markup/goldmark/codeblocks/render.go index 3daad0af6..739781de1 100644 --- a/markup/goldmark/codeblocks/render.go +++ b/markup/goldmark/codeblocks/render.go @@ -19,11 +19,11 @@ import ( "strings" "sync" - "github.com/alecthomas/chroma/v2/lexers" "github.com/gohugoio/hugo/common/herrors" htext "github.com/gohugoio/hugo/common/text" "github.com/gohugoio/hugo/markup/converter/hooks" "github.com/gohugoio/hugo/markup/goldmark/internal/render" + "github.com/gohugoio/hugo/markup/highlight/chromalexers" "github.com/gohugoio/hugo/markup/internal/attributes" "github.com/yuin/goldmark" "github.com/yuin/goldmark/ast" @@ -94,7 +94,7 @@ func (r *htmlRenderer) renderCodeBlock(w util.BufWriter, src []byte, node ast.No } attrtp := attributes.AttributesOwnerCodeBlockCustom - if isd, ok := renderer.(hooks.IsDefaultCodeBlockRendererProvider); (ok && isd.IsDefaultCodeBlockRenderer()) || lexers.Get(lang) != nil { + if isd, ok := renderer.(hooks.IsDefaultCodeBlockRendererProvider); (ok && isd.IsDefaultCodeBlockRenderer()) || chromalexers.Get(lang) != nil { // We say that this is a Chroma code block if it's the default code block renderer // or if the language is supported by Chroma. attrtp = attributes.AttributesOwnerCodeBlockChroma diff --git a/markup/highlight/chromalexers/chromalexers.go b/markup/highlight/chromalexers/chromalexers.go new file mode 100644 index 000000000..41fd76261 --- /dev/null +++ b/markup/highlight/chromalexers/chromalexers.go @@ -0,0 +1,50 @@ +// Copyright 2022 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 chromalexers + +import ( + "sync" + + "github.com/alecthomas/chroma/v2" + "github.com/alecthomas/chroma/v2/lexers" +) + +type lexersMap struct { + lexers map[string]chroma.Lexer + mu sync.RWMutex +} + +var lexerCache = &lexersMap{lexers: make(map[string]chroma.Lexer)} + +// Get returns a lexer for the given language name, nil if not found. +// This is just a wrapper around chromalexers.Get that caches the result. +// Reasoning for this is that chromalexers.Get is slow in the case where the lexer is not found, +// which is a common case in Hugo. +func Get(name string) chroma.Lexer { + lexerCache.mu.RLock() + lexer, found := lexerCache.lexers[name] + lexerCache.mu.RUnlock() + + if found { + return lexer + } + + lexer = lexers.Get(name) + + lexerCache.mu.Lock() + lexerCache.lexers[name] = lexer + lexerCache.mu.Unlock() + + return lexer +} diff --git a/markup/highlight/highlight.go b/markup/highlight/highlight.go index 5b19d6e8e..010c941f7 100644 --- a/markup/highlight/highlight.go +++ b/markup/highlight/highlight.go @@ -28,6 +28,7 @@ import ( "github.com/gohugoio/hugo/common/text" "github.com/gohugoio/hugo/identity" "github.com/gohugoio/hugo/markup/converter/hooks" + "github.com/gohugoio/hugo/markup/highlight/chromalexers" "github.com/gohugoio/hugo/markup/internal/attributes" ) @@ -167,7 +168,7 @@ func (h HightlightResult) Inner() template.HTML { func highlight(fw hugio.FlexiWriter, code, lang string, attributes []attributes.Attribute, cfg Config) (int, int, error) { var lexer chroma.Lexer if lang != "" { - lexer = lexers.Get(lang) + lexer = chromalexers.Get(lang) } if lexer == nil && (cfg.GuessSyntax && !cfg.NoHl) { diff --git a/tpl/transform/transform.go b/tpl/transform/transform.go index 36508c428..039d674c4 100644 --- a/tpl/transform/transform.go +++ b/tpl/transform/transform.go @@ -18,10 +18,10 @@ import ( "html" "html/template" - "github.com/alecthomas/chroma/v2/lexers" "github.com/gohugoio/hugo/cache/namedmemcache" "github.com/gohugoio/hugo/markup/converter/hooks" "github.com/gohugoio/hugo/markup/highlight" + "github.com/gohugoio/hugo/markup/highlight/chromalexers" "github.com/gohugoio/hugo/tpl" "github.com/gohugoio/hugo/deps" @@ -93,7 +93,7 @@ func (ns *Namespace) HighlightCodeBlock(ctx hooks.CodeblockContext, opts ...any) // CanHighlight returns whether the given code language is supported by the Chroma highlighter. func (ns *Namespace) CanHighlight(language string) bool { - return lexers.Get(language) != nil + return chromalexers.Get(language) != nil } // HTMLEscape returns a copy of s with reserved HTML characters escaped.