Skip to content

Conversation

@renuka-fernando
Copy link
Contributor

@renuka-fernando renuka-fernando commented Jan 27, 2026

Purpose

Related Issue: #825

Summary by CodeRabbit

  • Documentation

    • Added benchmarking guide with instructions for running performance tests.
  • Tests

    • Added comprehensive performance benchmarks for policy chain execution, external processor handling, and CEL expression evaluation components.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

Walkthrough

This pull request adds comprehensive benchmarking infrastructure to the gateway policy-engine, including three new benchmark test files measuring the chain executor, ext_proc kernel, and CEL evaluator components, along with updated README documentation describing how to run these benchmarks.

Changes

Cohort / File(s) Summary
Documentation
gateway/policy-engine/README.md
Replaced License section with new "Running Benchmarks" guide, detailing how to execute package-wide benchmarks, specific BenchmarkProcess scenarios, and CPU/memory profiling commands.
Chain Executor Benchmarks
gateway/policy-engine/internal/executor/chain_bench_test.go
Added comprehensive benchmark suite with mock CEL evaluators and policy implementations (passthrough, header-modify, short-circuit), helper constructors for policy specs and contexts, and benchmarks covering request/response policy execution, modifications, short-circuiting, disabled policies, CEL skipping, and parallel execution scenarios.
Ext_proc Kernel Benchmarks
gateway/policy-engine/internal/kernel/extproc_bench_test.go
Added extensive benchmark suite for Envoy ext_proc kernel path with mock gRPC streaming, three mock policy implementations, helper constructors for server/chain/spec building, and benchmarks testing full Process lifecycle, parallel processing, short-circuit behavior, header modification overhead, metadata extraction, request/response context building, and throughput targeting.
CEL Evaluator Benchmarks
gateway/policy-engine/internal/pkg/cel/evaluator_bench_test.go
Added comprehensive benchmark test file with request/response context builders and Benchmark functions covering evaluator creation overhead, request/response condition evaluation, cache hit/miss scenarios, parallel evaluation, expression complexity analysis, and real-world production-like scenarios.

Poem

A rabbit hops through benchmarks new,
Three shiny suites put code to the test—
Chain, kernel, CEL all measure true,
Performance metrics put to the vest! 🐰⚡

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is largely incomplete, missing most required sections from the template including Goals, Approach, User stories, Documentation, Automation tests, Security checks, Samples, Related PRs, and Test environment. Complete the description by filling in all required template sections, particularly Goals, Approach, Documentation, Automation tests coverage details, Security checks confirmation, and Test environment specifications.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: adding benchmark tests to the policy engine.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@gateway/policy-engine/internal/kernel/extproc_bench_test.go`:
- Around line 604-620: The benchmark has a data race on writeCounter in the
"ParallelWithWrites" subtest; make writeCounter an int64 and use atomic
operations from sync/atomic to increment and read it safely (e.g., call
atomic.AddInt64(&writeCounter, 1) inside the RunParallel loop and use the
returned value to decide when to call kernel.RegisterRoute), and add the
sync/atomic import. Reference symbols: writeCounter,
b.Run("ParallelWithWrites"), kernel.RegisterRoute, kernel.GetPolicyChainForKey.
🧹 Nitpick comments (3)
gateway/policy-engine/internal/executor/chain_bench_test.go (1)

60-74: Mock evaluator has non-thread-safe counter - acceptable for current usage.

The sometimesFalseCELEvaluator uses a non-atomic counter which would cause data races in parallel execution. This is fine since it's only used in BenchmarkExecuteRequestPolicies_CELSkipping which is serial, but add a comment to prevent future misuse.

📝 Add thread-safety note
 // sometimesFalseCELEvaluator skips policies based on index for realistic testing.
+// Note: Not thread-safe. Only use in serial benchmarks.
 type sometimesFalseCELEvaluator struct {
 	counter int
 }
gateway/policy-engine/internal/kernel/extproc_bench_test.go (1)

107-173: Mock policies duplicate those in chain_bench_test.go.

Consider extracting shared mock policies to a common test helper package (e.g., internal/testutil/) to reduce duplication. This is optional since test code duplication is less critical than production code.

gateway/policy-engine/internal/pkg/cel/evaluator_bench_test.go (1)

19-25: Consider adding TestMain for consistent benchmark isolation.

The other benchmark files disable metrics via TestMain for clean measurements. For consistency, consider adding similar setup here if the CEL evaluator triggers any metrics.

📝 Add TestMain for consistency
 import (
+	"os"
 	"testing"
 
 	policy "github.com/wso2/api-platform/sdk/gateway/policy/v1alpha"
+	"github.com/wso2/api-platform/gateway/policy-engine/internal/metrics"
 )
+
+func TestMain(m *testing.M) {
+	metrics.SetEnabled(false)
+	metrics.Init()
+	os.Exit(m.Run())
+}

Comment on lines +604 to +620
b.Run("ParallelWithWrites", func(b *testing.B) {
// Simulates scenario with occasional route updates
var writeCounter int64
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// Every 1000th operation is a write
if writeCounter%1000 == 0 {
kernel.RegisterRoute("dynamic-route", chain)
}
_ = kernel.GetPolicyChainForKey("route-50")
writeCounter++
}
})
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Data race on writeCounter in parallel benchmark.

writeCounter++ is not atomic and will race across goroutines in b.RunParallel. While the benchmark intent is to occasionally trigger writes, the race detector will flag this.

🔧 Use atomic counter
+import "sync/atomic"
+
 b.Run("ParallelWithWrites", func(b *testing.B) {
 	// Simulates scenario with occasional route updates
-	var writeCounter int64
+	var writeCounter atomic.Int64
 	b.ReportAllocs()
 	b.ResetTimer()
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
 			// Every 1000th operation is a write
-			if writeCounter%1000 == 0 {
+			if writeCounter.Add(1)%1000 == 0 {
 				kernel.RegisterRoute("dynamic-route", chain)
 			}
 			_ = kernel.GetPolicyChainForKey("route-50")
-			writeCounter++
 		}
 	})
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
b.Run("ParallelWithWrites", func(b *testing.B) {
// Simulates scenario with occasional route updates
var writeCounter int64
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// Every 1000th operation is a write
if writeCounter%1000 == 0 {
kernel.RegisterRoute("dynamic-route", chain)
}
_ = kernel.GetPolicyChainForKey("route-50")
writeCounter++
}
})
})
}
b.Run("ParallelWithWrites", func(b *testing.B) {
// Simulates scenario with occasional route updates
var writeCounter atomic.Int64
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// Every 1000th operation is a write
if writeCounter.Add(1)%1000 == 0 {
kernel.RegisterRoute("dynamic-route", chain)
}
_ = kernel.GetPolicyChainForKey("route-50")
}
})
})
🤖 Prompt for AI Agents
In `@gateway/policy-engine/internal/kernel/extproc_bench_test.go` around lines 604
- 620, The benchmark has a data race on writeCounter in the "ParallelWithWrites"
subtest; make writeCounter an int64 and use atomic operations from sync/atomic
to increment and read it safely (e.g., call atomic.AddInt64(&writeCounter, 1)
inside the RunParallel loop and use the returned value to decide when to call
kernel.RegisterRoute), and add the sync/atomic import. Reference symbols:
writeCounter, b.Run("ParallelWithWrites"), kernel.RegisterRoute,
kernel.GetPolicyChainForKey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant