From fb3fb16debb32f9e6b6997c1a8e29b214135c736 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 6 Oct 2026 13:23:08 +0200 Subject: [PATCH] Answer stability round 3: the allocation case of a read two levels under a pick holds at its baseline with no margin, as the performance gate decision now says --- docs/decisions.md | 4 ++++ perf_test.go | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/decisions.md b/docs/decisions.md index 6dc7fc4..8b35d25 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -398,6 +398,10 @@ CI load, while time varies with the machine and its neighbours. A rendering slow almost always costs an allocation too (a lost pre-size, a per-item map, an extra copy). The benchmark suite (the README's Development) reports time for a human, not as a pass/fail gate. +A case guarding against one allocation per render, such as a render's scope reaching the +heap through `pickKey.under`, holds at its baseline with no margin, since 10% of its +count is less than one allocation. Lilleman auf Larv decided it on 2026-10-06. + ## Rows live in a TSV, the shape in JSON 2026-09-17, Lilleman auf Larv. Goals 8 and 13. diff --git a/perf_test.go b/perf_test.go index 0e5a412..8944922 100644 --- a/perf_test.go +++ b/perf_test.go @@ -59,12 +59,12 @@ func TestNoRenderAllocRegression(t *testing.T) { func TestNoReferenceAllocRegression(t *testing.T) { word := `{"format":"{w}","w":["alpha","beta","gamma","delta"]}` for _, s := range []struct { - name, json string - base float64 + name, json string + base, slack float64 }{ - {"a repeat of a reference path", `{"format":"{r}","r":{"format":"{/word.w}","repeat":20,"separator":", "}}`, 25}, - {"a repeat of a name", `{"format":"{r}","r":{"format":"{/word as n}{n.w}{n.w}","repeat":20,"separator":", "}}`, 162}, - {"a read two levels under a pick", `{"format":"{place.geo as g}{g} {g.town.zip}","place":{"format":"{geo}","geo":{"format":"{town.zip}","town":{"format":"{zip}","zip":"1"}}}}`, 12}, + {"a repeat of a reference path", `{"format":"{r}","r":{"format":"{/word.w}","repeat":20,"separator":", "}}`, 25, 1.10}, + {"a repeat of a name", `{"format":"{r}","r":{"format":"{/word as n}{n.w}{n.w}","repeat":20,"separator":", "}}`, 162, 1.10}, + {"a read two levels under a pick", `{"format":"{place.geo as g}{g} {g.town.zip}","place":{"format":"{geo}","geo":{"format":"{town.zip}","town":{"format":"{zip}","zip":"1"}}}}`, 12, 1}, } { f, err := New(WithoutShippedData(), WithDataFS(fstest.MapFS{ "word.json": {Data: []byte(word)}, @@ -73,8 +73,8 @@ func TestNoReferenceAllocRegression(t *testing.T) { 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 render's scope reaching the heap is the usual cause", s.name, allocs, s.base*1.10, s.base) + if allocs := testing.AllocsPerRun(10000, func() { f.Fake("x") }); allocs > s.base*s.slack { + t.Errorf("%s: %.1f allocs/op regressed past %.1f (baseline %.1f × %.2f); a render's scope reaching the heap is the usual cause", s.name, allocs, s.base*s.slack, s.base, s.slack) } } }