From 13964ed69ba3c225a5bef756695f705b036f3e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Tue, 23 Apr 2019 12:33:51 +0200 Subject: [PATCH] hugolib: Avoid recloning of shortcode templates ```bash benchmark old ns/op new ns/op delta BenchmarkSiteNew/Bundle_with_image-4 14572242 14382188 -1.30% BenchmarkSiteNew/Bundle_with_JSON_file-4 13683922 13738196 +0.40% BenchmarkSiteNew/Multiple_languages-4 41912231 25192494 -39.89% benchmark old allocs new allocs delta BenchmarkSiteNew/Bundle_with_image-4 57496 57493 -0.01% BenchmarkSiteNew/Bundle_with_JSON_file-4 57492 57501 +0.02% BenchmarkSiteNew/Multiple_languages-4 242422 118809 -50.99% benchmark old bytes new bytes delta BenchmarkSiteNew/Bundle_with_image-4 3845077 3844065 -0.03% BenchmarkSiteNew/Bundle_with_JSON_file-4 3627442 3627798 +0.01% BenchmarkSiteNew/Multiple_languages-4 13963502 7543885 -45.97% ``` Fixes #5890 --- hugolib/site_benchmark_new_test.go | 106 +++++++++++++++++++++++++++++ hugolib/testhelpers_test.go | 20 +++++- tpl/tplimpl/template.go | 8 +-- 3 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 hugolib/site_benchmark_new_test.go diff --git a/hugolib/site_benchmark_new_test.go b/hugolib/site_benchmark_new_test.go new file mode 100644 index 00000000000..c816dc9c3e8 --- /dev/null +++ b/hugolib/site_benchmark_new_test.go @@ -0,0 +1,106 @@ +// Copyright 2019 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" +) + +// TODO(bep) eventually remove the old (too complicated setup). +func BenchmarkSiteNew(b *testing.B) { + // TODO(bep) create some common and stable data set + + const pageContent = `--- +title: "My Page" +--- + +My page content. + +` + + config := ` +baseURL = "https://example.com" + +` + + benchmarks := []struct { + name string + create func(i int) *sitesBuilder + check func(s *sitesBuilder) + }{ + {"Bundle with image", func(i int) *sitesBuilder { + sb := newTestSitesBuilder(b).WithConfigFile("toml", config) + sb.WithContent("content/blog/mybundle/index.md", pageContent) + sb.WithSunset("content/blog/mybundle/sunset1.jpg") + + return sb + }, + func(s *sitesBuilder) { + s.AssertFileContent("public/blog/mybundle/index.html", "/blog/mybundle/sunset1.jpg") + s.CheckExists("public/blog/mybundle/sunset1.jpg") + + }, + }, + {"Bundle with JSON file", func(i int) *sitesBuilder { + sb := newTestSitesBuilder(b).WithConfigFile("toml", config) + sb.WithContent("content/blog/mybundle/index.md", pageContent) + sb.WithContent("content/blog/mybundle/mydata.json", `{ "hello": "world" }`) + + return sb + }, + func(s *sitesBuilder) { + s.AssertFileContent("public/blog/mybundle/index.html", "Resources: application/json: /blog/mybundle/mydata.json") + s.CheckExists("public/blog/mybundle/mydata.json") + + }, + }, + {"Multiple languages", func(i int) *sitesBuilder { + sb := newTestSitesBuilder(b).WithConfigFile("toml", ` +baseURL = "https://example.com" + +[languages] +[languages.en] +weight=1 +[languages.fr] +weight=2 + +`) + + return sb + }, + func(s *sitesBuilder) { + + }, + }, + } + + for _, bm := range benchmarks { + b.Run(bm.name, func(b *testing.B) { + sites := make([]*sitesBuilder, b.N) + for i := 0; i < b.N; i++ { + sites[i] = bm.create(i) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + s := sites[i] + err := s.BuildE(BuildCfg{}) + if err != nil { + b.Fatal(err) + } + bm.check(s) + } + }) + } +} diff --git a/hugolib/testhelpers_test.go b/hugolib/testhelpers_test.go index d7c97244323..fe0f824f2c9 100644 --- a/hugolib/testhelpers_test.go +++ b/hugolib/testhelpers_test.go @@ -1,6 +1,7 @@ package hugolib import ( + "io" "io/ioutil" "path/filepath" "runtime" @@ -42,6 +43,8 @@ type sitesBuilder struct { Fs *hugofs.Fs T testing.TB + *require.Assertions + logger *loggers.Logger dumper litter.Options @@ -88,7 +91,7 @@ func newTestSitesBuilder(t testing.TB) *sitesBuilder { Separator: " ", } - return &sitesBuilder{T: t, Fs: fs, configFormat: "toml", dumper: litterOptions} + return &sitesBuilder{T: t, Assertions: require.New(t), Fs: fs, configFormat: "toml", dumper: litterOptions} } func createTempDir(prefix string) (string, func(), error) { @@ -260,6 +263,21 @@ lag = "lag" } +func (s *sitesBuilder) WithSunset(in string) { + // Write a real image into one of the bundle above. + src, err := os.Open(filepath.FromSlash("testdata/sunset.jpg")) + s.NoError(err) + + out, err := s.Fs.Source.Create(filepath.FromSlash(in)) + s.NoError(err) + + _, err = io.Copy(out, src) + s.NoError(err) + + out.Close() + src.Close() +} + func (s *sitesBuilder) WithContent(filenameContent ...string) *sitesBuilder { s.contentFilePairs = append(s.contentFilePairs, filenameContent...) return s diff --git a/tpl/tplimpl/template.go b/tpl/tplimpl/template.go index c1fad30687c..f0d3066e2ec 100644 --- a/tpl/tplimpl/template.go +++ b/tpl/tplimpl/template.go @@ -252,12 +252,12 @@ func (t *htmlTemplates) LookupVariant(name string, variants tpl.TemplateVariants return t.handler.LookupVariant(name, variants) } -func (t *templateHandler) cloneTemplate(in interface{}) tpl.Template { +func (t *templateHandler) lookupTemplate(in interface{}) tpl.Template { switch templ := in.(type) { case *texttemplate.Template: - return texttemplate.Must(templ.Clone()) + return t.text.lookup(templ.Name()) case *template.Template: - return template.Must(templ.Clone()) + return t.html.lookup(templ.Name()) } panic(fmt.Sprintf("%T is not a template", in)) @@ -294,7 +294,7 @@ func (t *templateHandler) clone(d *deps.Deps) *templateHandler { variantsc[i] = shortcodeVariant{ info: variant.info, variants: variant.variants, - templ: t.cloneTemplate(variant.templ), + templ: c.lookupTemplate(variant.templ), } } other.variants = variantsc