Skip to content

Commit 6a53c89

Browse files
committed
Benchmark fixes
A number of benchmarks did not have a `for range b.N` (or equivalent) loop in them, leading to nothing being measured. This PR fixes that, along with some cleanups in benchmarks found along the way. Also remove `b.StopTimer` where not absolutely necessary, as that is [notoriously buggy](golang/go#27217), and had some benchmarks hang for a very long time. Signed-off-by: Anders Eknert <anders@styra.com>
1 parent 6aa579d commit 6a53c89

21 files changed

Lines changed: 165 additions & 320 deletions

v1/ast/strings_bench_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import "testing"
55
// BenchmarkTypeName-10 32207775 38.93 ns/op 8 B/op 1 allocs/op
66
func BenchmarkTypeName(b *testing.B) {
77
term := StringTerm("foo")
8-
b.ResetTimer()
98

109
for range b.N {
1110
name := TypeName(term.Value)
@@ -18,7 +17,6 @@ func BenchmarkTypeName(b *testing.B) {
1817
// BenchmarkValueName-10 508312227 2.374 ns/op 0 B/op 0 allocs/op
1918
func BenchmarkValueName(b *testing.B) {
2019
term := StringTerm("foo")
21-
b.ResetTimer()
2220

2321
for range b.N {
2422
name := ValueName(term.Value)

v1/bundle/file_bench_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,31 +52,31 @@ func BenchmarkTarballLoader(b *testing.B) {
5252
defer f.Close()
5353

5454
b.Run(strconv.Itoa(n), func(b *testing.B) {
55-
// Reset the file reader.
56-
if _, err := f.Seek(0, 0); err != nil {
57-
b.Fatalf("Unexpected error: %s", err)
55+
for range b.N {
56+
// Reset the file reader.
57+
if _, err := f.Seek(0, 0); err != nil {
58+
b.Fatalf("Unexpected error: %s", err)
59+
}
60+
loader := NewTarballLoaderWithBaseURL(f, tarballFile)
61+
benchTestLoader(b, loader)
5862
}
59-
loader := NewTarballLoaderWithBaseURL(f, tarballFile)
60-
benchTestLoader(b, loader)
6163
})
6264
})
6365
}
6466
}
6567

6668
func BenchmarkDirectoryLoader(b *testing.B) {
67-
sizes := []int{10000, 100000, 250000, 500000}
68-
69-
for _, n := range sizes {
69+
for _, n := range []int{10000, 100000, 250000, 500000} {
7070
expectedFiles := make(map[string]string, len(benchTestArchiveFiles)+1)
7171
maps.Copy(expectedFiles, benchTestArchiveFiles)
7272
expectedFiles["/x/data.json"] = benchTestGetFlatDataJSON(n)
7373

7474
test.WithTempFS(expectedFiles, func(rootDir string) {
7575
b.ResetTimer()
76-
7776
b.Run(strconv.Itoa(n), func(b *testing.B) {
78-
loader := NewDirectoryLoader(rootDir)
79-
benchTestLoader(b, loader)
77+
for range b.N {
78+
benchTestLoader(b, NewDirectoryLoader(rootDir))
79+
}
8080
})
8181
})
8282
}

v1/compile/compile_bench_test.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,19 @@ import (
1919
func BenchmarkCompileDynamicPolicy(b *testing.B) {
2020
// This benchmarks the compiler against increasingly large numbers of dynamically-selected policies.
2121
// See: https://github.com/open-policy-agent/opa/issues/5216
22-
2322
numPolicies := []int{1000, 2500, 5000, 7500, 10000}
2423

2524
for _, n := range numPolicies {
2625
testcase := generateDynamicPolicyBenchmarkData(n)
2726
test.WithTestFS(testcase, true, func(root string, fileSys fs.FS) {
2827
b.ResetTimer()
2928
b.Run(strconv.Itoa(n), func(b *testing.B) {
30-
compiler := New().
31-
WithFS(fileSys).
32-
WithPaths(root)
29+
for range b.N {
30+
compiler := New().WithFS(fileSys).WithPaths(root)
3331

34-
err := compiler.Build(context.Background())
35-
if err != nil {
36-
b.Fatal("unexpected error", err)
32+
if err := compiler.Build(context.Background()); err != nil {
33+
b.Fatal("unexpected error", err)
34+
}
3735
}
3836
})
3937
})
@@ -83,12 +81,12 @@ func BenchmarkLargePartialRulePolicy(b *testing.B) {
8381
test.WithTempFS(testcase, func(root string) {
8482
b.ResetTimer()
8583

86-
compiler := New().
87-
WithPaths(root)
84+
for range b.N {
85+
compiler := New().WithPaths(root)
8886

89-
err := compiler.Build(context.Background())
90-
if err != nil {
91-
b.Fatal("unexpected error", err)
87+
if err := compiler.Build(context.Background()); err != nil {
88+
b.Fatal("unexpected error", err)
89+
}
9290
}
9391
})
9492
})

v1/cover/cover_bench_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ func BenchmarkCoverBigLocalVar(b *testing.B) {
2222
for _, varCount := range vars {
2323
name := fmt.Sprintf("%dVars%dIterations", varCount, iterationCount)
2424
b.Run(name, func(b *testing.B) {
25-
cover := New()
2625
module := generateModule(varCount, iterationCount)
2726

28-
_, err := ast.ParseModule("test.rego", module)
29-
if err != nil {
27+
if _, err := ast.ParseModule("test.rego", module); err != nil {
3028
b.Fatal(err)
3129
}
3230

@@ -41,14 +39,12 @@ func BenchmarkCoverBigLocalVar(b *testing.B) {
4139
b.Fatal(err)
4240
}
4341

42+
cover := New()
43+
4444
b.ResetTimer()
4545

4646
for range b.N {
47-
b.StartTimer()
48-
_, err = pq.Eval(ctx, rego.EvalQueryTracer(cover))
49-
b.StopTimer()
50-
51-
if err != nil {
47+
if _, err = pq.Eval(ctx, rego.EvalQueryTracer(cover)); err != nil {
5248
b.Fatal(err)
5349
}
5450
}

v1/dependencies/deps_bench_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ func BenchmarkBase(b *testing.B) {
2424

2525
b.ResetTimer()
2626

27-
_, err := Base(compiler, ref)
28-
if err != nil {
29-
b.Fatalf("Failed to compute base doc deps: %v", err)
27+
for range b.N {
28+
if _, err := Base(compiler, ref); err != nil {
29+
b.Fatalf("Failed to compute base doc deps: %v", err)
30+
}
3031
}
3132
})
3233
}
@@ -36,8 +37,7 @@ func BenchmarkVirtual(b *testing.B) {
3637
ruleCounts := []int{10, 20, 50}
3738
for _, ruleCount := range ruleCounts {
3839
b.Run(strconv.Itoa(ruleCount), func(b *testing.B) {
39-
policy := makePolicy(ruleCount)
40-
module := ast.MustParseModule(policy)
40+
module := ast.MustParseModule(makePolicy(ruleCount))
4141
compiler := ast.NewCompiler()
4242
if compiler.Compile(map[string]*ast.Module{"test": module}); compiler.Failed() {
4343
b.Fatalf("Failed to compile policy: %v", compiler.Errors)
@@ -47,9 +47,10 @@ func BenchmarkVirtual(b *testing.B) {
4747

4848
b.ResetTimer()
4949

50-
_, err := Virtual(compiler, ref)
51-
if err != nil {
52-
b.Fatalf("Failed to compute virtual doc deps: %v", err)
50+
for range b.N {
51+
if _, err := Virtual(compiler, ref); err != nil {
52+
b.Fatalf("Failed to compute virtual doc deps: %v", err)
53+
}
5354
}
5455
})
5556
}

v1/metrics/metrics_bench_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,16 @@ func BenchmarkMetricsMarshaling(b *testing.B) {
4646
b.Fatalf("No output")
4747
}
4848
}
49-
50-
b.StopTimer()
5149
}
5250

5351
func BenchmarkMetricsTimerStartStopRestart(b *testing.B) {
5452
m := metrics.New()
5553

56-
b.ResetTimer()
57-
5854
for range b.N {
5955
m.Timer("foo").Start()
6056
_ = m.Timer("foo").Stop()
6157
_ = m.Timer("foo").Stop() // Second stop to exercise the sync guard.
6258
m.Timer("foo").Start()
6359
_ = m.Timer("foo").Stop()
6460
}
65-
66-
b.StopTimer()
6761
}

v1/profiler/profiler_bench_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ func BenchmarkProfilerBigLocalVar(b *testing.B) {
2525
profiler := New()
2626
module := generateModule(varCount, iterationCount)
2727

28-
_, err := ast.ParseModule("test.rego", module)
29-
if err != nil {
28+
if _, err := ast.ParseModule("test.rego", module); err != nil {
3029
b.Fatal(err)
3130
}
3231

@@ -44,11 +43,7 @@ func BenchmarkProfilerBigLocalVar(b *testing.B) {
4443
b.ResetTimer()
4544

4645
for range b.N {
47-
b.StartTimer()
48-
_, err = pq.Eval(ctx, rego.EvalQueryTracer(profiler))
49-
b.StopTimer()
50-
51-
if err != nil {
46+
if _, err = pq.Eval(ctx, rego.EvalQueryTracer(profiler)); err != nil {
5247
b.Fatal(err)
5348
}
5449
}

v1/rego/rego_bench_test.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,6 @@ r contains true if {
344344
}
345345

346346
b.ResetTimer()
347-
b.ReportAllocs()
348347

349348
for range b.N {
350349
res, err := pq.Eval(ctx)
@@ -416,8 +415,7 @@ func BenchmarkTrivialPolicy(b *testing.B) {
416415
}
417416

418417
for range b.N {
419-
_, err := pq.Eval(ctx)
420-
if err != nil {
418+
if _, err := pq.Eval(ctx); err != nil {
421419
b.Fatal(err)
422420
}
423421
}
@@ -439,8 +437,7 @@ func BenchmarkTrivialQuery(b *testing.B) {
439437
}
440438

441439
for range b.N {
442-
_, err := pq.Eval(ctx, EvalMetrics(m))
443-
if err != nil {
440+
if _, err := pq.Eval(ctx, EvalMetrics(m)); err != nil {
444441
b.Fatal(err)
445442
}
446443
}
@@ -502,8 +499,7 @@ local_var if {
502499
for i, pq := range []PreparedEvalQuery{pq1, pq2} {
503500
b.Run(names[i], func(b *testing.B) {
504501
for range b.N {
505-
_, err := pq.Eval(ctx)
506-
if err != nil {
502+
if _, err := pq.Eval(ctx); err != nil {
507503
b.Fatal(err)
508504
}
509505
}

v1/test/authz/authz_bench_test.go

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -46,76 +46,60 @@ func BenchmarkAuthzAllow1000Paths(b *testing.B) {
4646
}
4747

4848
func runAuthzBenchmark(b *testing.B, mode InputMode, numPaths int, extras ...bool) {
49-
5049
profile := DataSetProfile{
5150
NumTokens: 1000,
5251
NumPaths: numPaths,
5352
}
5453

5554
ctx := context.Background()
5655
data := GenerateDataset(profile)
57-
58-
useDisk := false
59-
if len(extras) > 0 {
60-
useDisk = extras[0]
61-
}
56+
useDisk := len(extras) > 0 && extras[0]
6257

6358
var store storage.Store
64-
var err error
6559
if useDisk {
66-
rootDir := b.TempDir()
67-
store, err = disk.New(ctx, logging.NewNoOpLogger(), nil, disk.Options{
68-
Dir: rootDir,
69-
Partitions: nil,
70-
})
71-
if err != nil {
60+
var err error
61+
if store, err = disk.New(ctx, logging.NewNoOpLogger(), nil, disk.Options{Dir: b.TempDir()}); err != nil {
7262
b.Fatal(err)
7363
}
7464

75-
err = storage.WriteOne(ctx, store, storage.AddOp, storage.Path{}, data)
76-
if err != nil {
65+
if err = storage.WriteOne(ctx, store, storage.AddOp, storage.Path{}, data); err != nil {
7766
b.Fatal(err)
7867
}
7968
} else {
80-
store = inmem.NewFromObject(data)
69+
store = inmem.NewFromObjectWithOpts(data)
8170
}
8271

83-
txn := storage.NewTransactionOrDie(ctx, store)
8472
compiler := ast.NewCompiler()
85-
module := ast.MustParseModule(Policy)
86-
87-
compiler.Compile(map[string]*ast.Module{"": module})
88-
if compiler.Failed() {
73+
if compiler.Compile(map[string]*ast.Module{"": ast.MustParseModule(Policy)}); compiler.Failed() {
8974
b.Fatalf("Unexpected error(s): %v", compiler.Errors)
9075
}
9176

9277
r := rego.New(
9378
rego.Compiler(compiler),
9479
rego.Store(store),
95-
rego.Transaction(txn),
80+
rego.Transaction(storage.NewTransactionOrDie(ctx, store)),
9681
rego.Query(AllowQuery),
9782
)
9883

99-
// Pre-process as much as we can
10084
pq, err := r.PrepareForEval(ctx)
10185
if err != nil {
10286
b.Fatalf("Unexpected error(s): %v", err)
10387
}
10488

10589
input, expected := GenerateInput(profile, mode)
10690

91+
inputAST, err := ast.InterfaceToValue(input)
92+
if err != nil {
93+
b.Fatal(err)
94+
}
95+
10796
b.ResetTimer()
10897

10998
for range b.N {
110-
b.StartTimer()
111-
rs, err := pq.Eval(
112-
ctx,
113-
rego.EvalInput(input),
114-
)
99+
rs, err := pq.Eval(ctx, rego.EvalParsedInput(inputAST))
115100
if err != nil {
116101
b.Fatalf("Unexpected error(s): %v", err)
117102
}
118-
b.StopTimer()
119103

120104
if rs.Allowed() != expected {
121105
b.Fatalf("Unexpected result: %v", rs)

v1/test/authz/testing.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ import (
1717
// Policy is a test rego policy for a token based authz system
1818
const Policy = `package policy.restauthz
1919
20-
import rego.v1
2120
import data.restauthz.tokens
2221
23-
default allow = false
22+
default allow := false
2423
2524
allow if {
26-
tokens[input.token_id] = token
27-
token.authz_profiles[_] = authz
25+
token := tokens[input.token_id]
26+
some authz in token.authz_profiles
2827
regex.match(authz.path, input.path)
29-
authz.methods[_] = input.method
28+
input.method in authz.methods
3029
}`
3130

3231
// AllowQuery is the test query that goes with the Policy
@@ -52,7 +51,6 @@ const (
5251

5352
// GenerateInput will use a dataset profile and desired InputMode to generate inputs for testing
5453
func GenerateInput(profile DataSetProfile, mode InputMode) (any, any) {
55-
5654
var input string
5755
var allow bool
5856

@@ -132,11 +130,10 @@ func generateTokens(profile DataSetProfile) map[string]token {
132130
}
133131

134132
func generateToken(profile DataSetProfile, i int) token {
135-
token := token{
133+
return token{
136134
ID: generateTokenID(i),
137135
AuthzProfiles: generateAuthzProfiles(profile),
138136
}
139-
return token
140137
}
141138

142139
func generateAuthzProfiles(profile DataSetProfile) []authzProfile {

0 commit comments

Comments
 (0)