diff --git a/common/hreflect/helpers_test.go b/common/hreflect/helpers_test.go index bd578650d..fb5a06d27 100644 --- a/common/hreflect/helpers_test.go +++ b/common/hreflect/helpers_test.go @@ -152,17 +152,18 @@ func TestIndirectInterface(t *testing.T) { } func BenchmarkIsContextType(b *testing.B) { + const size = 1000 type k string b.Run("value", func(b *testing.B) { ctx := context.Background() - ctxs := make([]reflect.Type, b.N) - for i := 0; b.Loop(); i++ { + ctxs := make([]reflect.Type, size) + for i := range size { ctxs[i] = reflect.TypeOf(context.WithValue(ctx, k("key"), i)) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - if !IsContextType(ctxs[i]) { + for i := 0; b.Loop(); i++ { + idx := i % size + if !IsContextType(ctxs[idx]) { b.Fatal("not context") } } diff --git a/common/hstrings/strings_test.go b/common/hstrings/strings_test.go index 9eb3b04cb..3150ada07 100644 --- a/common/hstrings/strings_test.go +++ b/common/hstrings/strings_test.go @@ -71,6 +71,7 @@ func TestUniqueStringsSorted(t *testing.T) { c.Assert(UniqueStringsSorted(nil), qt.IsNil) } +// Note that these cannot use b.Loop() because of golang/go#27217. func BenchmarkUniqueStrings(b *testing.B) { input := []string{"a", "b", "d", "e", "d", "h", "a", "i"} @@ -84,15 +85,14 @@ func BenchmarkUniqueStrings(b *testing.B) { }) b.Run("Reuse slice", func(b *testing.B) { - b.StopTimer() inputs := make([][]string, b.N) - for i := 0; b.Loop(); i++ { + for i := 0; i < b.N; i++ { inputc := make([]string, len(input)) copy(inputc, input) inputs[i] = inputc } - b.StartTimer() - for i := 0; b.Loop(); i++ { + b.ResetTimer() + for i := 0; i < b.N; i++ { inputc := inputs[i] result := UniqueStringsReuse(inputc) @@ -103,14 +103,13 @@ func BenchmarkUniqueStrings(b *testing.B) { }) b.Run("Reuse slice sorted", func(b *testing.B) { - b.StopTimer() inputs := make([][]string, b.N) for i := 0; i < b.N; i++ { inputc := make([]string, len(input)) copy(inputc, input) inputs[i] = inputc } - b.StartTimer() + b.ResetTimer() for i := 0; i < b.N; i++ { inputc := inputs[i] diff --git a/compare/compare_strings_test.go b/compare/compare_strings_test.go index 1a5bb0b1a..0ccfab243 100644 --- a/compare/compare_strings_test.go +++ b/compare/compare_strings_test.go @@ -63,6 +63,7 @@ func TestLexicographicSort(t *testing.T) { c.Assert(s, qt.DeepEquals, []string{"A", "b", "Ba", "ba", "ba", "Bz"}) } +// // Note that this cannot use b.Loop() because of golang/go#27217. func BenchmarkStringSort(b *testing.B) { prototype := []string{"b", "Bz", "zz", "ba", "αβδ αβδ αβδ", "A", "Ba", "ba", "nnnnasdfnnn", "AAgæåz", "αβδC"} b.Run("LessStrings", func(b *testing.B) { diff --git a/hugolib/cascade_test.go b/hugolib/cascade_test.go index b592ee0f8..01db67c3b 100644 --- a/hugolib/cascade_test.go +++ b/hugolib/cascade_test.go @@ -34,15 +34,11 @@ func BenchmarkCascade(b *testing.B) { langs := allLangs[0:i] b.Run(fmt.Sprintf("langs-%d", len(langs)), func(b *testing.B) { c := qt.New(b) - b.StopTimer() - builders := make([]*sitesBuilder, b.N) - for i := 0; b.Loop(); i++ { - builders[i] = newCascadeTestBuilder(b, langs) - } - b.StartTimer() - for i := 0; b.Loop(); i++ { - builder := builders[i] + for b.Loop() { + b.StopTimer() + builder := newCascadeTestBuilder(b, langs) + b.StartTimer() err := builder.BuildE(BuildCfg{}) c.Assert(err, qt.IsNil) first := builder.H.Sites[0] @@ -75,16 +71,13 @@ kind = '{section,term}' T: b, TxtarString: files, } - builders := make([]*IntegrationTestBuilder, b.N) - - for i := range builders { - builders[i] = NewIntegrationTestBuilder(cfg) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - builders[i].Build() + for b.Loop() { + b.StopTimer() + builder := NewIntegrationTestBuilder(cfg) + b.StartTimer() + builder.Build() } }) } diff --git a/hugolib/hugo_smoke_test.go b/hugolib/hugo_smoke_test.go index f7c0562ed..a32d01d44 100644 --- a/hugolib/hugo_smoke_test.go +++ b/hugolib/hugo_smoke_test.go @@ -743,14 +743,12 @@ func BenchmarkBaseline(b *testing.B) { T: b, TxtarString: benchmarkBaselineFiles(false), } - builders := make([]*IntegrationTestBuilder, b.N) - for i := range builders { - builders[i] = NewIntegrationTestBuilder(cfg) - } - - for i := 0; i < b.N; i++ { - builders[i].Build() + for b.Loop() { + b.StopTimer() + builder := NewIntegrationTestBuilder(cfg) + b.StartTimer() + builder.Build() } } diff --git a/hugolib/page_permalink_test.go b/hugolib/page_permalink_test.go index 03fe62cec..52d1c9931 100644 --- a/hugolib/page_permalink_test.go +++ b/hugolib/page_permalink_test.go @@ -64,7 +64,6 @@ func TestPermalink(t *testing.T) { } for i, test := range tests { - test := test t.Run(fmt.Sprintf("%s-%d", test.file, i), func(t *testing.T) { t.Parallel() c := qt.New(t) diff --git a/hugolib/pagecollections_test.go b/hugolib/pagecollections_test.go index 94ae175b5..74e5a7194 100644 --- a/hugolib/pagecollections_test.go +++ b/hugolib/pagecollections_test.go @@ -37,17 +37,16 @@ categories: ` func BenchmarkGetPage(b *testing.B) { - var ( - cfg, fs = newTestCfg() - r = rand.New(rand.NewSource(time.Now().UnixNano())) - ) + cfg, fs := newTestCfg() configs, err := loadTestConfigFromProvider(cfg) if err != nil { b.Fatal(err) } - for i := range 10 { + const size = 10 + + for i := range size { for j := range 100 { writeSource(b, fs, filepath.Join("content", fmt.Sprintf("sect%d", i), fmt.Sprintf("page%d.md", j)), "CONTENT") } @@ -55,19 +54,18 @@ func BenchmarkGetPage(b *testing.B) { s := buildSingleSite(b, deps.DepsCfg{Fs: fs, Configs: configs}, BuildCfg{SkipRender: true}) - pagePaths := make([]string, b.N) - - for i := 0; b.Loop(); i++ { - pagePaths[i] = fmt.Sprintf("sect%d", r.Intn(10)) + pagePaths := make([]string, size) + for i := range size { + pagePaths[i] = fmt.Sprintf("sect%d", i) } - for i := 0; i < b.N; i++ { + for i := 0; b.Loop(); i++ { home, _ := s.getPage(nil, "/") if home == nil { b.Fatal("Home is nil") } - p, _ := s.getPage(nil, pagePaths[i]) + p, _ := s.getPage(nil, pagePaths[i%size]) if p == nil { b.Fatal("Section is nil") } @@ -113,20 +111,21 @@ func TestBenchmarkGetPageRegular(t *testing.T) { func BenchmarkGetPageRegular(b *testing.B) { r := rand.New(rand.NewSource(time.Now().UnixNano())) + const size = 100 b.Run("From root", func(b *testing.B) { s := createGetPageRegularBenchmarkSite(b) c := qt.New(b) - pagePaths := make([]string, b.N) + pagePaths := make([]string, size) - for i := 0; i < b.N; i++ { - pagePaths[i] = path.Join(fmt.Sprintf("/sect%d", r.Intn(10)), fmt.Sprintf("page%d.md", r.Intn(100))) + for i := range size { + pagePaths[i] = path.Join(fmt.Sprintf("/sect%d", r.Intn(10)), fmt.Sprintf("page%d.md", i)) } b.ResetTimer() - for i := 0; i < b.N; i++ { - page, _ := s.getPage(nil, pagePaths[i]) + for i := 0; b.Loop(); i++ { + page, _ := s.getPage(nil, pagePaths[i%size]) c.Assert(page, qt.Not(qt.IsNil)) } }) @@ -136,17 +135,15 @@ func BenchmarkGetPageRegular(b *testing.B) { c := qt.New(b) allPages := s.RegularPages() - pagePaths := make([]string, b.N) - pages := make([]page.Page, b.N) + pagePaths := make([]string, size) + pages := allPages[:size] - for i := 0; i < b.N; i++ { - pagePaths[i] = fmt.Sprintf("page%d.md", r.Intn(100)) - pages[i] = allPages[r.Intn(len(allPages)/3)] + for i := range size { + pagePaths[i] = fmt.Sprintf("page%d.md", i) } - b.ResetTimer() - for i := 0; i < b.N; i++ { - page, _ := s.getPage(pages[i], pagePaths[i]) + for i := 0; b.Loop(); i++ { + page, _ := s.getPage(pages[i%size], pagePaths[i%size]) c.Assert(page, qt.Not(qt.IsNil)) } }) diff --git a/hugolib/rebuild_test.go b/hugolib/rebuild_test.go index 07317ae1c..afb2d7909 100644 --- a/hugolib/rebuild_test.go +++ b/hugolib/rebuild_test.go @@ -1787,22 +1787,15 @@ func BenchmarkRebuildContentFileChange(b *testing.B) { T: b, TxtarString: files, Running: true, - // Verbose: true, - // LogLevel: logg.LevelInfo, - } - builders := make([]*IntegrationTestBuilder, b.N) - - for i := range builders { - builders[i] = NewIntegrationTestBuilder(cfg) - builders[i].Build() } - for i := 0; i < b.N; i++ { - bb := builders[i] + for b.Loop() { + b.StopTimer() + bb := NewIntegrationTestBuilder(cfg).Build() + b.StartTimer() bb.EditFileReplaceFunc("content/mysect/p123/index.md", func(s string) string { return s + "... Edited" }).Build() - // fmt.Println(bb.LogString()) } } diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go index 560e0b4c0..0d6e72c10 100644 --- a/hugolib/shortcode_test.go +++ b/hugolib/shortcode_test.go @@ -242,6 +242,7 @@ CSV: {{< myShort >}} ) } +// Note that this cannot use b.Loop() because of golang/go#27217. func BenchmarkReplaceShortcodeTokens(b *testing.B) { type input struct { in []byte @@ -263,7 +264,7 @@ func BenchmarkReplaceShortcodeTokens(b *testing.B) { cnt := 0 in := make([]input, b.N*len(data)) - for b.Loop() { + for i := 0; i < b.N; i++ { for _, this := range data { replacements := make(map[string]shortcodeRenderer) for k, v := range this.replacements { @@ -279,7 +280,8 @@ func BenchmarkReplaceShortcodeTokens(b *testing.B) { cnt = 0 ctx := context.Background() - for i := 0; b.Loop(); i++ { + b.ResetTimer() + for i := 0; i < b.N; i++ { for j := range data { currIn := in[cnt] cnt++ @@ -335,14 +337,12 @@ title: "Markdown Shortcode" T: b, TxtarString: files, } - builders := make([]*IntegrationTestBuilder, b.N) - for i := range builders { - builders[i] = NewIntegrationTestBuilder(cfg) - } - - for i := 0; i < b.N; i++ { - builders[i].Build() + for b.Loop() { + b.StopTimer() + builder := NewIntegrationTestBuilder(cfg) + b.StartTimer() + builder.Build() } } diff --git a/hugolib/site_benchmark_new_test.go b/hugolib/site_benchmark_new_test.go deleted file mode 100644 index 85fff472f..000000000 --- a/hugolib/site_benchmark_new_test.go +++ /dev/null @@ -1,560 +0,0 @@ -// 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 ( - "fmt" - "math/rand" - "path" - "path/filepath" - "strconv" - "strings" - "testing" - - "github.com/gohugoio/hugo/resources/page" - - qt "github.com/frankban/quicktest" -) - -type siteBenchmarkTestcase struct { - name string - create func(t testing.TB) *sitesBuilder - check func(s *sitesBuilder) -} - -func getBenchmarkSiteDeepContent(b testing.TB) *sitesBuilder { - pageContent := func(size int) string { - return getBenchmarkTestDataPageContentForMarkdown(size, false, "", benchmarkMarkdownSnippets) - } - - sb := newTestSitesBuilder(b).WithConfigFile("toml", ` -baseURL = "https://example.com" - -[languages] -[languages.en] -weight=1 -contentDir="content/en" -[languages.fr] -weight=2 -contentDir="content/fr" -[languages.no] -weight=3 -contentDir="content/no" -[languages.sv] -weight=4 -contentDir="content/sv" - -`) - - createContent := func(dir, name string) { - sb.WithContent(filepath.Join("content", dir, name), pageContent(1)) - } - - createBundledFiles := func(dir string) { - sb.WithContent(filepath.Join("content", dir, "data.json"), `{ "hello": "world" }`) - for i := 1; i <= 3; i++ { - sb.WithContent(filepath.Join("content", dir, fmt.Sprintf("page%d.md", i)), pageContent(1)) - } - } - - for _, lang := range []string{"en", "fr", "no", "sv"} { - for level := 1; level <= 5; level++ { - sectionDir := path.Join(lang, strings.Repeat("section/", level)) - createContent(sectionDir, "_index.md") - createBundledFiles(sectionDir) - for i := 1; i <= 3; i++ { - leafBundleDir := path.Join(sectionDir, fmt.Sprintf("bundle%d", i)) - createContent(leafBundleDir, "index.md") - createBundledFiles(path.Join(leafBundleDir, "assets1")) - createBundledFiles(path.Join(leafBundleDir, "assets1", "assets2")) - } - } - } - - return sb -} - -func getBenchmarkTestDataPageContentForMarkdown(size int, toml bool, category, markdown string) string { - base := `--- -title: "My Page" -%s ---- - -My page content. -` - if toml { - base = `+++ -title="My Page" -%s -+++ - -My page content. -` - } - - var categoryKey string - if category != "" { - categoryKey = fmt.Sprintf("categories: [%s]", category) - if toml { - categoryKey = fmt.Sprintf("categories=[%s]", category) - } - } - base = fmt.Sprintf(base, categoryKey) - - return base + strings.Repeat(markdown, size) -} - -const benchmarkMarkdownSnippets = ` - -## Links - - -This is [an example](http://example.com/ "Title") inline link. - -[This link](http://example.net/) has no title attribute. - -This is [Relative](/all-is-relative). - -See my [About](/about/) page for details. -` - -func getBenchmarkSiteTestCases() []siteBenchmarkTestcase { - pageContentWithCategory := func(size int, category string) string { - return getBenchmarkTestDataPageContentForMarkdown(size, false, category, benchmarkMarkdownSnippets) - } - - pageContent := func(size int) string { - return getBenchmarkTestDataPageContentForMarkdown(size, false, "", benchmarkMarkdownSnippets) - } - - config := ` -baseURL = "https://example.com" -` - - benchmarks := []siteBenchmarkTestcase{ - { - "Bundle with image", func(b testing.TB) *sitesBuilder { - sb := newTestSitesBuilder(b).WithConfigFile("toml", config) - sb.WithContent("content/blog/mybundle/index.md", pageContent(1)) - 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(b testing.TB) *sitesBuilder { - sb := newTestSitesBuilder(b).WithConfigFile("toml", config) - sb.WithContent("content/blog/mybundle/index.md", pageContent(1)) - 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") - }, - }, - { - "Tags and categories", func(b testing.TB) *sitesBuilder { - sb := newTestSitesBuilder(b).WithConfigFile("toml", ` -title = "Tags and Cats" -baseURL = "https://example.com" - -`) - - const pageTemplate = ` ---- -title: "Some tags and cats" -categories: ["caGR", "cbGR"] -tags: ["taGR", "tbGR"] ---- - -Some content. - -` - for i := 1; i <= 100; i++ { - content := strings.Replace(pageTemplate, "GR", strconv.Itoa(i/3), -1) - sb.WithContent(fmt.Sprintf("content/page%d.md", i), content) - } - - return sb - }, - func(s *sitesBuilder) { - s.AssertFileContent("public/page3/index.html", "/page3/|Permalink: https://example.com/page3/") - s.AssertFileContent("public/tags/ta3/index.html", "a3") - }, - }, - { - "Canonify URLs", func(b testing.TB) *sitesBuilder { - sb := newTestSitesBuilder(b).WithConfigFile("toml", ` -title = "Canon" -baseURL = "https://example.com" -canonifyURLs = true - -`) - for i := 1; i <= 100; i++ { - sb.WithContent(fmt.Sprintf("content/page%d.md", i), pageContent(i)) - } - - return sb - }, - func(s *sitesBuilder) { - s.AssertFileContent("public/page8/index.html", "https://example.com/about/") - }, - }, - - { - "Deep content tree", func(b testing.TB) *sitesBuilder { - return getBenchmarkSiteDeepContent(b) - }, - func(s *sitesBuilder) { - s.CheckExists("public/blog/mybundle/index.html") - s.Assert(len(s.H.Sites), qt.Equals, 4) - s.Assert(len(s.H.Sites[0].RegularPages()), qt.Equals, len(s.H.Sites[1].RegularPages())) - s.Assert(len(s.H.Sites[0].RegularPages()), qt.Equals, 30) - }, - }, - { - "TOML front matter", func(b testing.TB) *sitesBuilder { - sb := newTestSitesBuilder(b).WithConfigFile("toml", config) - for i := 1; i <= 200; i++ { - content := getBenchmarkTestDataPageContentForMarkdown(1, true, "\"a\", \"b\", \"c\"", benchmarkMarkdownSnippets) - sb.WithContent(fmt.Sprintf("content/p%d.md", i), content) - } - - return sb - }, - func(s *sitesBuilder) { - }, - }, - { - "Many HTML templates", func(b testing.TB) *sitesBuilder { - pageTemplateTemplate := ` - - -
- -