Skip to content

Optimize JNI performance and fix Decimal validation#349

Merged
muditchaudhary merged 6 commits intocedar-policy:mainfrom
geekphilosophy:main
Apr 21, 2026
Merged

Optimize JNI performance and fix Decimal validation#349
muditchaudhary merged 6 commits intocedar-policy:mainfrom
geekphilosophy:main

Conversation

@geekphilosophy
Copy link
Copy Markdown
Contributor

Improve JNI call performance ~3x with reduced overhead. Add JMH benchmark suite for tracking JNI performance. Fix Decimal validator to accept leading zeros in corpus integration tests.

Issue #, if available:

Description of changes:
Cedar-Java JMH Benchmark Results — After Performance Fixes

Date: 2026-04-15
Base: 1d141bc (main)
JDK: 21.0.10 (Corretto)
JMH: 1.37
OS: macOS (Darwin 25.3.0, aarch64)
Config: @WarmUp(iterations=3, time=1) @measurement(iterations=5, time=1) @fork(1)

Changes applied:

  1. Remove thread::spawn per JNI call, use std::panic::catch_unwind instead (interface.rs)
  2. Remove redundant j_input_str.push(' ') (interface.rs)
  3. Eliminate double JSON deserialization (readTree+readValue → single readValue) (BasicAuthorizationEngine.java)
  4. Cache JNI version check in static initializer instead of per-call (BasicAuthorizationEngine.java)
  5. Single-pass escape detection in ValueDeserializer using node.size() + node.has() (ValueDeserializer.java)

Results (thorough run: 2 forks, 5 warmup, 20 measurement iterations):
Benchmark Mode Cnt Score Error Units
AuthorizationBenchmark.isAuthorized_medium avgt 40 122.606 ± 2.303 us/op
AuthorizationBenchmark.isAuthorized_small avgt 40 25.416 ± 0.837 us/op
AuthorizationBenchmark.validate_small avgt 40 159.865 ± 29.990 us/op

Comparison to baseline (1d141bc):
Baseline After Improvement
isAuthorized_small 85.4 ± 3.4 25.4 ± 0.8 ~3.4x faster
isAuthorized_medium 329.1 ± 258.4 122.6 ± 2.3 ~2.7x faster
validate_small 353.3 ± 146.0 159.9 ± 30.0 ~2.2x faster

Chris Simmons added 3 commits April 17, 2026 08:44
Improve JNI call performance ~3x with reduced overhead. Add JMH
benchmark suite for tracking JNI performance. Fix Decimal validator
to accept leading zeros in corpus integration tests.

Signed-off-by: Chris Simmons <simmonsc@amazon.com>
Rename snake_case methods to camelCase to comply with the MethodName
checkstyle rule ('^[a-z][a-zA-Z0-9]*$').

Signed-off-by: Chris Simmons <simmonsc@amazon.com>
JMH generates padding fields and dead stores intentionally for
cache-line isolation, which triggers false positives in SpotBugs.

Signed-off-by: Chris Simmons <simmonsc@amazon.com>
smallEntities.add(new Entity(resource, new HashMap<>(), new HashSet<>()));
}

private void setUpMediumScenario() throws Exception {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: I think if we anticipate adding more scenarios, we might want to rename this (perhaps basicPhotoFlashScenario), but I think this is good as is

if (node.size() == 1) {
if (node.has(ENTITY_ESCAPE_SEQ)) {
JsonNode val = node.get(ENTITY_ESCAPE_SEQ);
if (val.isObject() && val.has("id") && val.has("type") && val.size() == 2) {
Copy link
Copy Markdown
Contributor

@mark-creamer-amazon mark-creamer-amazon Apr 17, 2026

Choose a reason for hiding this comment

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

Nit: Looks like we can also shed the val.isObject() && because val.has(...) checks this already

Method that allows checking whether this node is JSON Object node and contains value for specified property.

Copy link
Copy Markdown
Contributor

@muditchaudhary muditchaudhary left a comment

Choose a reason for hiding this comment

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

Mostly nits except for decimal validation.

Comment thread CedarJava/src/main/java/com/cedarpolicy/serializer/ValueDeserializer.java Outdated
JsonNode val = node.get(ENTITY_ESCAPE_SEQ);
if (val.isObject() && val.has("id") && val.has("type") && val.size() == 2) {
EntityIdentifier id = new EntityIdentifier(val.get("id").textValue());
Optional<EntityTypeName> type = EntityTypeName.parse(val.get("type").textValue());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not required for this PR, but something I remembered while reviewing it: we can further optimize the deserializer by caching results from pure functions that cross the FFI boundary like EntityTypeName.parse(_) to avoid redundant and expensive FFI roundtrip costs for the same inputs. Can probably extend this idea beyond deserializers.

Comment thread CedarJava/src/main/java/com/cedarpolicy/value/Decimal.java
mediumRequest = new AuthorizationRequest(principal, action, resource, new HashMap<>());

Set<Policy> policies = new HashSet<>();
policies.add(new Policy(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: We can put the policies in a file and use PolicySet.parsePolicies() Example

Same for Entities using Entities.parse Example

let handle = thread::spawn(move || call_cedar_in_thread(j_call_str, j_input_str));

let result = match handle.join() {
let result = match panic::catch_unwind(|| call_cedar(&j_call_str, &j_input_str)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is nice.

Nit: call_cedar_in_thread is probably dead code now.

Chris Simmons added 2 commits April 18, 2026 15:52
- Fix Decimal validation to correctly handle leading zeros and enforce
  range bounds [-922337203685477.5808, 922337203685477.5807] instead of
  the previous format-only regex check
- Add DecimalTests covering boundary values, leading zeros, and
  out-of-range rejection
- Remove unused EscapeType enum from ValueDeserializer
- Remove redundant val.isObject() check in entity deserialization
- Move benchmark policies and entities to resource files, use
  PolicySet.parsePolicies() and Entities.parse() instead of inline
  construction

Signed-off-by: Chris Simmons <simmonsc@amazon.com>
Add --locked flag to cargo install for cargo-zigbuild to prevent
dependency resolution from pulling cargo-platform 0.3.3 which
requires rustc 1.91. Also fix trailing whitespace flagged by
checkstyle.

Signed-off-by: Chris Simmons <simmonsc@amazon.com>
@muditchaudhary muditchaudhary self-requested a review April 19, 2026 19:38
Comment thread CedarJava/src/test/java/com/cedarpolicy/DecimalTests.java
Comment thread CedarJava/src/main/java/com/cedarpolicy/value/Decimal.java Outdated
Comment thread CedarJava/src/main/java/com/cedarpolicy/value/Decimal.java Outdated
Tighten Decimal regex to require digits before and after the dot,
rejecting invalid forms like .1, 1., and -.0. Simplify range
validation using BigDecimal. Remove trim() to reject whitespace
inputs. Add edge case tests. Fix JMH resource path so benchmarks
run.

Signed-off-by: Chris Simmons <simmonsc@amazon.com>
@muditchaudhary muditchaudhary merged commit edffaac into cedar-policy:main Apr 21, 2026
4 checks passed
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.

3 participants