Files
regorus/benches/evaluation/compiled_policy_evaluation_benchmark.md
Anand Krishnamoorthi 2a0b4ae6b5 feat! Mimalloc as the default allocator (#434)
This change integrates mimalloc as the default memory allocator for Regorus,
delivering significant performance improvements across all evaluation modes
and language bindings.

Technical Implementation:
- Build mimalloc in vendored mode from C sources (following QSharp approach)
- Implement GlobalAlloc trait for seamless Rust integration
- Add optional 'mimalloc' feature flag for conditional compilation
- Add comprehensive ACI benchmarks to measure evaluation performance

Performance Impact:

Rust Engine Evaluation:
- Single-threaded: ~29% improvement (423 vs 328 Kelem/s)
- Multi-threaded: Better scaling with reduced thread contention
- Fresh engines: ~24% improvement (56 vs 45 Kelem/s)

Rust Compiled Policy Evaluation:
- Single-threaded: ~41% improvement (426 vs 303 Kelem/s)
- Multi-threaded: Improved allocation efficiency under contention
- Fresh compilation: ~26% improvement (53 vs 42 Kelem/s)

C# FFI Bindings:
- Engine evaluation: ~27% improvement (279 vs 219 Kelem/s)
- Compiled policies: ~29% improvement (273 vs 211 Kelem/s)
- Better threading characteristics through improved underlying allocation

Key Benefits:
- Reduced allocation-related contention in multi-threaded scenarios
- More consistent performance across different thread counts
- Improved memory allocation efficiency for both native Rust and FFI workloads
- Better scaling characteristics for production deployments

The mimalloc integration provides substantial performance gains while
maintaining full compatibility with existing code through feature flags.

Reference: QSharp allocator implementation
(https://github.com/microsoft/qsharp/tree/main/source/allocator)

Fixes #297

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
2025-08-25 15:01:38 -05:00

9.9 KiB

Compiled Policy Evaluation Benchmark Results

Test Environment

  • Platform: Apple Silicon (M-Series)
  • CPU: 16 cores
  • Architecture: ARM64 (aarch64-apple-darwin)
  • Rust Version: 1.82.0
  • Allocator: mimalloc (default allocator)
  • Benchmark Framework: Criterion.rs
  • Test Data: 20,000 inputs per evaluation (1000 per thread)
  • Policy: Complex authorization policy with nested rules

Benchmark Overview

The compiled policy evaluation benchmark tests Regorus compiled policy performance across multiple thread configurations (1-32 threads). It measures throughput (thousands of evaluations per second) for different combinations of compiled policy and input data reuse strategies.

Configuration Combinations

  1. Compiled Shared Policies, Cloned Inputs: Each thread uses shared compiled policies and clones of parsed input data - optimal for performance
  2. Compiled Shared Policies, Fresh Inputs: Each thread uses shared compiled policies but parses new inputs each time
  3. Compiled Per Iteration, Cloned Inputs: Each thread compiles the policy each iteration but reuses input data
  4. Compiled Per Iteration, Fresh Inputs: Each thread compiles new policies and parses new inputs for each iteration

Performance Results

Compiled Shared Policies, Cloned Inputs (Best Performance)

Threads Total Evaluation Time (ms) Throughput (Kelem/s)
1 2.35 426
2 5.36 373
4 11.70 342
6 20.33 295
8 43.26 185
10 61.93 162
12 79.30 151
14 94.45 148
16 113.39 141
18 154.41 117
20 184.37 108
22 204.00 108
24 220.45 109
26 237.07 110
28 252.58 111
30 273.57 110
32 292.69 109

Compiled Shared Policies, Fresh Inputs

Threads Total Evaluation Time (ms) Throughput (Kelem/s)
1 3.34 299
2 7.29 274
4 15.19 263
6 24.90 241
8 49.22 163
10 68.45 146
12 86.55 139
14 104.77 134
16 136.07 118
18 169.05 106
20 198.25 101
22 217.05 101
24 234.75 102
26 254.53 102
28 276.06 101
30 296.12 101
32 318.81 100

Compiled Per Iteration, Cloned Inputs

Threads Total Evaluation Time (ms) Throughput (Kelem/s)
1 18.11 55
2 36.89 54
4 75.46 53
6 114.66 52
8 152.80 52
10 192.17 52
12 232.32 52
14 301.47 46
16 380.36 42
18 424.64 42
20 484.76 41
22 531.62 41
24 582.88 41
26 631.39 41
28 671.99 42
30 717.65 42
32 766.05 42

Compiled Per Iteration, Fresh Inputs

Threads Total Evaluation Time (ms) Throughput (Kelem/s)
1 19.07 52
2 38.89 51
4 79.52 50
6 120.89 50
8 161.08 50
10 202.37 49
12 244.04 49
14 316.66 44
16 398.02 40
18 449.54 40
20 500.57 40
22 557.97 39
24 605.71 40
26 656.88 40
28 710.03 39
30 741.09 40
32 801.26 40

Analysis

The compiled policy benchmark demonstrates the following performance characteristics with mimalloc as the default allocator:

  1. Best Performance: Compiled shared policies with cloned inputs provide the highest throughput
  2. Compilation Impact:
    • Pre-compiled policies: Significantly faster than per-iteration compilation
    • Per-iteration compilation: Major overhead (~7-8x slower than pre-compiled)
  3. Scaling Patterns with mimalloc:
    • Best throughput achieved at 1 thread for shared policy configurations
    • mimalloc provides better thread scaling characteristics compared to the default allocator
    • Higher thread counts show performance degradation due to contention, but less severe with mimalloc
    • Per-iteration compilation shows poor scaling across all thread counts
  4. Input Processing: Fresh inputs add ~30% overhead across all configurations
  5. Thread Performance with mimalloc:
    • Peak performance at 1 thread for most configurations
    • Reasonable performance maintained up to 12-16 threads for shared policies
    • Compiled policies show better thread scaling than per-iteration compilation
    • mimalloc helps reduce allocation-related contention in multi-threaded scenarios

Comparison with Engine Evaluation

Multi-Thread Performance Comparison

Configuration 1 Thread (Kelem/s) 4 Threads (Kelem/s) 8 Threads (Kelem/s)
CP / EE CP / EE CP / EE
Shared/Cloned 426 / 423 342 / 406 185 / 341
Shared/Fresh 299 / 309 263 / 297 163 / 266
Per-iteration/Cloned 55 / 56 53 / 54 52 / 53
Per-iteration/Fresh 52 / 53 50 / 51 50 / 51

Threading Efficiency Analysis

Configuration Low Contention (1-4t) Medium Contention (6-12t) High Contention (16+t)
Avg CP / EE Avg CP / EE Avg CP / EE
Shared/Cloned 384 / 414 203 / 329 123 / 250
Shared/Fresh 284 / 302 176 / 235 108 / 201
Per-iteration/Cloned 54 / 55 50 / 52 42 / 42
Per-iteration/Fresh 51 / 52 47 / 50 40 / 40

The compiled policy evaluation shows performance characteristics that are generally comparable to engine evaluation, though with some notable differences. While single-threaded performance is very close between the systems, there are observable impacts from the compilation approach that become more apparent under different threading scenarios.

Key Observations:

  • Single-threaded performance: Very close parity between systems, though results may vary between runs
  • Threading behavior: Engine evaluation demonstrates better scaling characteristics under higher thread contention (4+ threads)
  • Multi-threaded impact: Compiled policies show more pronounced performance degradation under thread contention in shared policy configurations
  • Contention resistance: Per-iteration compilation shows more consistent (though lower absolute) performance across thread counts
  • Optimal usage: Both systems achieve best results with minimal threading (1-4 threads), though engine evaluation maintains better performance at higher thread counts for shared configurations