-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalloc_gate_test.go
More file actions
131 lines (114 loc) · 5.06 KB
/
Copy pathalloc_gate_test.go
File metadata and controls
131 lines (114 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-License-Identifier: EUPL-1.2
// Allocation regression gates. Unlike a Benchmark (which only prints a
// number nobody compares), each case here asserts a hard ceiling on
// allocations-per-call via testing.AllocsPerRun — so the suite FAILS if a
// hot primitive starts allocating where it didn't before. ns/op is
// deliberately not gated (machine-dependent); allocs are stable.
//
// Ceilings are the measured floor as of this commit:
// 0 — pure / zero-copy primitive (no heap touch)
// 1 — one unavoidable alloc: Result{Value:<non-pointer>} boxes the value
// into `any` (string/int → 1 alloc; pointer values box for free)
//
// Tightening a ceiling that's been beaten is welcome; raising one is a
// regression that needs justifying in review.
//
// Run: go test -run 'TestAllocs_' .
package core_test
import (
"testing"
. "dappco.re/go"
)
// gate sinks — keep the measured call from being elided as dead code.
var (
gateInt int
gateBool bool
gateStr string
gateBytes []byte
gateResult Result
gateAny any
gateDiags []LSPDiagnostic
)
func TestAllocs_HotPrimitives(t *T) {
ptr := &struct{ n int }{}
bs := []byte("homelab")
var ai32 AtomicInt32
var ab AtomicBool
var au64 AtomicUint64
cases := []struct {
name string
ceiling int
fn func()
}{
// math / ordering — pure, must stay 0
{"Compare", 0, func() { gateInt = Compare(3, 7) }},
{"Min", 0, func() { gateInt = Min(3, 7) }},
{"Max", 0, func() { gateInt = Max(3, 7) }},
{"Abs", 0, func() { gateInt = Abs(-42) }},
{"Clamp", 0, func() { gateInt = Clamp(15, 0, 10) }},
{"Sign", 0, func() { gateInt = Sign(-3) }},
// string predicates / index — pure, must stay 0
{"Contains", 0, func() { gateBool = Contains("agent ready", "ready") }},
{"HasPrefix", 0, func() { gateBool = HasPrefix("agent.go", "agent") }},
{"HasSuffix", 0, func() { gateBool = HasSuffix("agent.go", ".go") }},
{"EqualFold", 0, func() { gateBool = EqualFold("Bearer", "bearer") }},
{"Index", 0, func() { gateInt = Index("agent", "e") }},
{"Count", 0, func() { gateInt = Count("banana", "a") }},
{"Trim", 0, func() { gateStr = Trim(" x ") }},
// slice search — pure, must stay 0
{"SliceContains", 0, func() { gateBool = SliceContains([]int{1, 2, 3}, 2) }},
{"SliceIndex", 0, func() { gateInt = SliceIndex([]int{1, 2, 3}, 2) }},
// unsafe zero-copy conversions — must stay 0
{"AsBytes", 0, func() { gateBytes = AsBytes("homelab") }},
{"AsString", 0, func() { gateStr = AsString(bs) }},
// Result constructors — pointer value boxes for free (0); a
// non-pointer value pays the one inherent Result-boxing alloc.
{"Ok_Pointer", 0, func() { gateResult = Ok(ptr) }},
{"Fail", 0, func() { gateResult = Fail(AnError) }},
{"Ok_String", 1, func() { gateResult = Ok("ready") }},
{"ResultOf_String", 1, func() { gateResult = ResultOf("ready", nil) }},
// Result accessors — pure reads, must stay 0
{"Result_Or", 0, func() { gateAny = (Result{OK: false}).Or("fallback") }},
// atomics — lock-free, must stay 0
{"AtomicInt32_Load", 0, func() { gateInt = int(ai32.Load()) }},
{"AtomicInt32_Store", 0, func() { ai32.Store(7) }},
{"AtomicInt32_Add", 0, func() { gateInt = int(ai32.Add(1)) }},
{"AtomicBool_Load", 0, func() { gateBool = ab.Load() }},
{"AtomicBool_Store", 0, func() { ab.Store(true) }},
{"AtomicUint64_Add", 0, func() { gateInt = int(au64.Add(1)) }},
// more math — pure, must stay 0
{"Pow", 0, func() { gateInt = int(Pow(2, 8)) }},
{"Floor", 0, func() { gateInt = int(Floor(3.7)) }},
{"Ceil", 0, func() { gateInt = int(Ceil(3.1)) }},
{"Round", 0, func() { gateInt = int(Round(3.5)) }},
// slice — Clone copies (1 alloc for the backing array); Reverse is in-place (0)
{"SliceClone", 1, func() { gateBytes = SliceClone(bs) }},
}
for _, c := range cases {
avg := int(testing.AllocsPerRun(1000, c.fn))
AssertLessOrEqual(t, avg, c.ceiling, c.name)
}
}
// TestAllocs_LSPComputeDiagnostics locks the regex-hoist win (c1cf230):
// with per-call regexp.Compile it allocated ~186/call; compiling the
// naming-diagnostic patterns once dropped it to ~47. A regression to
// per-call compilation jumps back over 100, so the ceiling catches it.
func TestAllocs_LSPComputeDiagnostics(t *T) {
uri := "file:///agent/worker.go"
content := []byte("package worker\n\nfunc process(in string) (string, error) {\n\treturn in, nil\n}\n")
LSPComputeDiagnostics(uri, content) // warm the per-dir cache → measure steady state
avg := int(testing.AllocsPerRun(200, func() {
gateDiags = LSPComputeDiagnostics(uri, content)
}))
AssertLessOrEqual(t, avg, 70, "LSPComputeDiagnostics")
}
var gateStrSlice []string
// TestAllocs_FilterArgs locks the pre-size win (1f59e31): was an unpresized
// 'var clean []string' + append (geometric regrow), now the single presized
// result allocation. (Typed sink — assigning to `any` would box and add a
// spurious alloc.)
func TestAllocs_FilterArgs(t *T) {
args := []string{"deploy", "--target", "homelab", "-v"}
fa := int(testing.AllocsPerRun(1000, func() { gateStrSlice = FilterArgs(args) }))
AssertLessOrEqual(t, fa, 1, "FilterArgs")
}