From 0443ecdf1322616e56e565334cb2f9a7dd707785 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Wed, 16 Sep 2026 10:29:00 +0200 Subject: [PATCH] Tests: gate the allocations a reference path costs across a repeat and in a named draw group --- perf_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/perf_test.go b/perf_test.go index ab92408..4ff2bbf 100644 --- a/perf_test.go +++ b/perf_test.go @@ -52,6 +52,32 @@ func TestNoRenderAllocRegression(t *testing.T) { } // A record's fences read the compiled tree, so they belong to New, not to a draw. +// A reference path read across a repeat, and one read in a named draw group. The repeat +// prices both measures that keep a render's draw set off the heap — inlining expandAnew +// into render's loop, or keying a draw group's map with the scope's own string, costs an +// allocation an iteration — while the draw group holds the group path's own count. +func TestNoReferenceAllocRegression(t *testing.T) { + word := `{"format":"{w}","w":["alpha","beta","gamma","delta"]}` + for _, s := range []struct { + name, json string + base float64 + }{ + {"a repeat of a reference path", `{"format":"{r}","r":{"format":"{/word.w}","repeat":20,"separator":", "}}`, 66}, + {"a named draw group", `{"format":"{a}","a":{"format":"{/word.w}","drawGroup":"g"}}`, 11}, + } { + f, err := New(WithoutShippedData(), WithDataFS(fstest.MapFS{ + "word.json": {Data: []byte(word)}, + "x.json": {Data: []byte(s.json)}, + })) + if err != nil { + t.Fatalf("New(%s): %v", s.name, err) + } + if allocs := testing.AllocsPerRun(10000, func() { f.Fake("x") }); allocs > s.base*1.10 { + t.Errorf("%s: %.1f allocs/op regressed past %.1f (baseline %.1f + 10%%); a draw set reaching the heap is the usual cause", s.name, allocs, s.base*1.10, s.base) + } + } +} + func TestNoRecordAllocRegression(t *testing.T) { for _, s := range []struct{ name, json string }{ {"record 3 columns", `{"format":"","a":"x","b":"y","c":"z"}`},