Skip to content

perf: optimize enforcement hot paths - #422

Open
H-Chris233 wants to merge 2 commits into
apache:masterfrom
H-Chris233:master
Open

perf: optimize enforcement hot paths#422
H-Chris233 wants to merge 2 commits into
apache:masterfrom
H-Chris233:master

Conversation

@H-Chris233

Copy link
Copy Markdown
Contributor

Changes

This PR includes two performance optimizations for the enforcement hot path:

  • Cache the p_eft token index to avoid repeated lookups for each policy.
  • Reuse precompiled regexes in key matching helpers.
  • Return early on CachedEnforcer cache hits to skip redundant argument conversion.
  • Add cached basic and ABAC benchmarks.

Performance

Improves cached enforcement by approximately 36%–45% on cache hits.

Verification

Tests, Clippy checks, and runtime combinations pass with both default and cached configurations.

Compute p_eft index once in src/enforcer.rs and reuse it instead of calling .position repeatedly, reducing repeated iteration. In src/model/function_map.rs add static compiled regexes (MAT_COLON, MAT_BRACE) and replace on-the-fly Regex::new calls with these statics, adjust replacements/escaping accordingly. Small performance-focused refactor with no behavior changes.
Add no-op benchmark functions gated by #[cfg(not(feature = "cached"))] so Criterion groups compile when the "cached" feature is disabled. Simplify event handler insertion by using or_default(), remove unnecessary references when calling private_enforce/private_enforce_with_context, and add early-return cache checks in enforce/enforce_with_context behind #[cfg(not(feature = "logging"))] to avoid work when a cached result exists. These changes clean up code, fix feature-flagged build issues, and optimize the cache fast path.
@github-actions

Copy link
Copy Markdown

Benchmark Results

group                                 changes                                master
-----                                 -------                                ------
b_benchmark_rbac_model_large          1.00      7.4±0.01ms        ? ?/sec    1.01      7.5±0.02ms        ? ?/sec
benchmark priority model              1.00   1059.5±5.10ns        ? ?/sec    1.01   1069.5±6.03ns        ? ?/sec
benchmark_abac_model                  1.01    831.6±4.20ns        ? ?/sec    1.00    827.1±3.97ns        ? ?/sec
benchmark_basic_model                 1.00    874.1±3.84ns        ? ?/sec    1.00    876.4±4.69ns        ? ?/sec
benchmark_key_match                   1.00      3.1±0.02µs        ? ?/sec    1.05      3.2±0.04µs        ? ?/sec
benchmark_raw                         1.00      0.0±0.00ns        ? ?/sec    1.00      0.0±0.00ns        ? ?/sec
benchmark_rbac_model                  1.00      2.3±0.02µs        ? ?/sec    1.02      2.3±0.01µs        ? ?/sec
benchmark_rbac_model_medium           1.00    608.2±2.63µs        ? ?/sec    1.04    631.8±6.84µs        ? ?/sec
benchmark_rbac_model_with_domains     1.00   1506.2±9.40ns        ? ?/sec    1.01   1522.3±5.72ns        ? ?/sec
benchmark_rbac_with_deny              1.00      3.9±0.03µs        ? ?/sec    1.06      4.1±0.04µs        ? ?/sec
benchmark_rbac_with_resource_roles    1.00   1074.3±5.49ns        ? ?/sec    1.00   1072.0±4.57ns        ? ?/sec
benchmark_role_manager_large          1.01      3.3±0.02ms        ? ?/sec    1.00      3.3±0.01ms        ? ?/sec
benchmark_role_manager_medium         1.01    220.3±2.01µs        ? ?/sec    1.00    217.9±1.04µs        ? ?/sec
benchmark_role_manager_small          1.00     23.1±0.61µs        ? ?/sec    1.08     24.9±0.23µs        ? ?/sec

@H-Chris233

Copy link
Copy Markdown
Contributor Author

Local benchmark verification

Environment: local Windows machine (noisy, ±20–30% run-to-run), 3 alternating
rounds per scenario with --measurement-time 10.

Optimization Scenario base 5b382a7 PR 86e8ccc Change
③ static regex key_get2 micro-bench (100× samples) 95.1 µs 39.7 µs −58%
③ static regex key_match4 micro-bench 89.3 µs 50.9 µs −43%
② p_eft index deny-effect model, 10k policies, full scan 7.62 ms 7.12 ms −6.5%
① early return cached basic/abac cache-hit (--features cached) 453 / 506 ns 455 / 497 ns no significant change (within noise)

Findings:

  • Regex static-fication (③) is real and reproducible: −43% to −58% on
    key_get2 / key_match4. Note it only affects key_get2 / key_get3 /
    key_match4 / key_match5keyMatch2 / keyMatch3 already used the
    pre-existing static MAT_B / MAT_P, so usual RBAC benchmarks don't
    exercise this change (consistent with CI showing no change there).
  • p_eft index (②) gives a small consistent gain (−6.5%) in a full-scan
    deny model with a large policy set; models that break early (the common
    some(where (p.eft == allow)) case) only call position 1–3 times, so the
    gain is negligible there.
  • The claimed 36–45% on cached cache-hits (①) did not reproduce locally:
    the early return removes try_into_vec + a duplicate cache.get, worth
    ~5–15% of the ~450 ns hit path, which is below measurement noise on this
    machine. A quieter environment or a dedicated micro-benchmark would be
    needed to confirm it.

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