From b993d83500a0b97538e1e5cb7c6a84e0cfef674b Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Thu, 16 Jul 2026 14:51:33 +0200 Subject: [PATCH 1/2] Add performance-focused JMH benchmark --- .../projectnessie/cel/CompileBuildBench.java | 102 ++++++++++++++ .../InterpreterAllocationBench.java | 26 +++- .../cel/interpreter/MacroRuntimeBench.java | 119 ++++++++++++++++ jackson/build.gradle.kts | 10 ++ .../types/jackson/JacksonRegistryBench.java | 128 ++++++++++++++++++ jackson3/build.gradle.kts | 10 ++ .../types/jackson3/Jackson3RegistryBench.java | 128 ++++++++++++++++++ 7 files changed, 522 insertions(+), 1 deletion(-) create mode 100644 core/src/jmh/java/org/projectnessie/cel/CompileBuildBench.java create mode 100644 core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java create mode 100644 jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java create mode 100644 jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java diff --git a/core/src/jmh/java/org/projectnessie/cel/CompileBuildBench.java b/core/src/jmh/java/org/projectnessie/cel/CompileBuildBench.java new file mode 100644 index 00000000..76bb13ab --- /dev/null +++ b/core/src/jmh/java/org/projectnessie/cel/CompileBuildBench.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 The Authors of CEL-Java + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.projectnessie.cel; + +import static org.projectnessie.cel.Env.newEnv; +import static org.projectnessie.cel.EnvOption.declarations; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.projectnessie.cel.Env.AstIssuesTuple; +import org.projectnessie.cel.checker.Decls; +import org.projectnessie.cel.common.types.pb.ProtoTypeRegistry; +import org.projectnessie.cel.tools.Script; +import org.projectnessie.cel.tools.ScriptHost; + +@Warmup(iterations = 1, time = 1500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) +@Fork(1) +@Threads(2) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +public class CompileBuildBench { + + @State(Scope.Thread) + public static class CompileState { + @Param({"simplePredicate", "deepSelectors", "macroPipeline"}) + public String expression; + + String source() { + switch (expression) { + case "simplePredicate": + return "resource == 'projects/p1' && user == 'alice'"; + case "deepSelectors": + return "request.auth.claims.email.endsWith('@example.com')" + + " && request.resource.labels['env'] == 'prod'"; + case "macroPipeline": + return "items.filter(i, i.score > 10).map(i, i.name).exists(n, n.startsWith('a'))"; + default: + throw new IllegalArgumentException("Unknown compile benchmark expression: " + expression); + } + } + } + + @Benchmark + public void envCompileAndProgram(CompileState state, Blackhole blackhole) { + Env env = + newEnv( + declarations( + Decls.newVar("resource", Decls.String), + Decls.newVar("user", Decls.String), + Decls.newVar("request", Decls.Dyn), + Decls.newVar("items", Decls.newListType(Decls.Dyn)))); + AstIssuesTuple ast = env.compile(state.source()); + if (ast.hasIssues()) { + throw ast.getIssues().err(); + } + blackhole.consume(env.program(ast.getAst())); + } + + @Benchmark + public void scriptHostBuild(CompileState state, Blackhole blackhole) throws Exception { + ScriptHost host = ScriptHost.newBuilder().build(); + Script script = + host.buildScript(state.source()) + .withDeclarations( + Decls.newVar("resource", Decls.String), + Decls.newVar("user", Decls.String), + Decls.newVar("request", Decls.Dyn), + Decls.newVar("items", Decls.newListType(Decls.Dyn))) + .build(); + blackhole.consume(script); + } + + @Benchmark + public void protoRegistryCreation(Blackhole blackhole) { + blackhole.consume(ProtoTypeRegistry.newRegistry()); + } +} diff --git a/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java b/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java index b71d4e04..4b209aee 100644 --- a/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java +++ b/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java @@ -142,7 +142,13 @@ public void dynamicMapLiteral(DynamicMapLiteralState state, Blackhole blackhole) @State(Scope.Benchmark) public static class ProtoInputState { - @Param({"mapLookup", "repeatedUintExistsEarly", "repeatedUintExistsLate"}) + @Param({ + "mapLookup", + "mapLookupMiss", + "mapLookupRepeated", + "repeatedUintExistsEarly", + "repeatedUintExistsLate" + }) public String kind; @Param({"10", "1000"}) @@ -164,6 +170,24 @@ public void init() { mapOf( "msg", protoMessage(size), "key", "key-" + (size - 1), "target", (long) size - 1); return; + case "mapLookupMiss": + program = + protoProgram( + "msg.map_string_uint64[key] == target", + Decls.newVar("key", Decls.String), + Decls.newVar("target", Decls.Uint)); + vars = mapOf("msg", protoMessage(size), "key", "missing", "target", 0L); + return; + case "mapLookupRepeated": + program = + protoProgram( + "msg.map_string_uint64[key] == target && msg.map_string_uint64[key] == target", + Decls.newVar("key", Decls.String), + Decls.newVar("target", Decls.Uint)); + vars = + mapOf( + "msg", protoMessage(size), "key", "key-" + (size - 1), "target", (long) size - 1); + return; case "repeatedUintExistsEarly": program = protoProgram( diff --git a/core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java b/core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java new file mode 100644 index 00000000..fde49352 --- /dev/null +++ b/core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 The Authors of CEL-Java + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.projectnessie.cel.interpreter; + +import static org.projectnessie.cel.Env.newEnv; +import static org.projectnessie.cel.EnvOption.declarations; +import static org.projectnessie.cel.ProgramOption.evalOptions; +import static org.projectnessie.cel.Util.mapOf; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.projectnessie.cel.Env; +import org.projectnessie.cel.Env.AstIssuesTuple; +import org.projectnessie.cel.EvalOption; +import org.projectnessie.cel.Program; +import org.projectnessie.cel.checker.Decls; + +@Warmup(iterations = 1, time = 1500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) +@Fork(1) +@Threads(2) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +public class MacroRuntimeBench { + + @State(Scope.Benchmark) + public static class MacroState { + @Param({"existsEarly", "existsLate", "all", "filter", "map"}) + public String expression; + + @Param({"10", "1000"}) + public int size; + + Program program; + Map vars; + + @Setup + public void init() { + switch (expression) { + case "existsEarly": + program = program("items.exists(i, i == target)"); + vars = mapOf("items", list(size), "target", 0L); + return; + case "existsLate": + program = program("items.exists(i, i == target)"); + vars = mapOf("items", list(size), "target", (long) size - 1); + return; + case "all": + program = program("items.all(i, i >= 0)"); + vars = mapOf("items", list(size), "target", (long) size - 1); + return; + case "filter": + program = program("items.filter(i, i > target)"); + vars = mapOf("items", list(size), "target", (long) size / 2); + return; + case "map": + program = program("items.map(i, i + 1)"); + vars = mapOf("items", list(size), "target", (long) size - 1); + return; + default: + throw new IllegalArgumentException("Unknown macro benchmark expression: " + expression); + } + } + } + + @Benchmark + public void macroRuntime(MacroState state, Blackhole blackhole) { + blackhole.consume(state.program.eval(state.vars)); + } + + private static Program program(String expression) { + Env env = + newEnv( + declarations( + Decls.newVar("items", Decls.newListType(Decls.Int)), + Decls.newVar("target", Decls.Int))); + AstIssuesTuple ast = env.compile(expression); + if (ast.hasIssues()) { + throw ast.getIssues().err(); + } + return env.program(ast.getAst(), evalOptions(EvalOption.OptOptimize)); + } + + private static List list(int size) { + List values = new ArrayList<>(size); + for (long i = 0; i < size; i++) { + values.add(i); + } + return values; + } +} diff --git a/jackson/build.gradle.kts b/jackson/build.gradle.kts index 480bd0ce..20112b20 100644 --- a/jackson/build.gradle.kts +++ b/jackson/build.gradle.kts @@ -18,6 +18,7 @@ plugins { `java-library` `maven-publish` signing + alias(libs.plugins.jmh) id("cel-conventions") } @@ -43,4 +44,13 @@ dependencies { testImplementation(libs.bundles.junit.testing) testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + jmhImplementation(libs.jmh.core) + jmhAnnotationProcessor(libs.jmh.generator.annprocess) } + +jmh { jmhVersion.set(libs.versions.jmh.get()) } + +tasks.named("check") { dependsOn(tasks.named("jmh")) } + +tasks.named("assemble") { dependsOn(tasks.named("jmhJar")) } diff --git a/jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java b/jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java new file mode 100644 index 00000000..ec74c9e7 --- /dev/null +++ b/jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2021 The Authors of CEL-Java + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.projectnessie.cel.types.jackson; + +import static org.projectnessie.cel.common.types.StringT.stringOf; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Warmup(iterations = 1, time = 1500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) +@Fork(1) +@Threads(2) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +public class JacksonRegistryBench { + + @State(Scope.Benchmark) + public static class ReadState { + JacksonObjectT value; + + @Setup + public void init() { + JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); + registry.typeDescription(Policy.class); + value = + JacksonObjectT.newObject( + registry, + new Policy("policy-1", 7, new Principal("alice@example.com"), Status.ACTIVE), + registry.typeDescription(Policy.class)); + } + } + + @Benchmark + public void registerType(Blackhole blackhole) { + JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); + blackhole.consume(registry.typeDescription(Policy.class)); + } + + @Benchmark + public void registerEnum(Blackhole blackhole) { + JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); + blackhole.consume(registry.enumDescription(Status.class)); + } + + @Benchmark + public void propertyRead(ReadState state, Blackhole blackhole) { + blackhole.consume(state.value.get(stringOf("owner"))); + } + + @Benchmark + public void enumConversion(Blackhole blackhole) { + JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); + registry.enumDescription(Status.class); + blackhole.consume(registry.nativeToValue(Status.ACTIVE)); + } + + public enum Status { + ACTIVE, + DISABLED + } + + public static final class Principal { + private final String email; + + Principal(String email) { + this.email = email; + } + + public String getEmail() { + return email; + } + } + + public static final class Policy { + private final String name; + private final int priority; + private final Principal owner; + private final Status status; + + Policy(String name, int priority, Principal owner, Status status) { + this.name = name; + this.priority = priority; + this.owner = owner; + this.status = status; + } + + public String getName() { + return name; + } + + public int getPriority() { + return priority; + } + + public Principal getOwner() { + return owner; + } + + public Status getStatus() { + return status; + } + } +} diff --git a/jackson3/build.gradle.kts b/jackson3/build.gradle.kts index 6d1b5d73..3dc4bb58 100644 --- a/jackson3/build.gradle.kts +++ b/jackson3/build.gradle.kts @@ -18,6 +18,7 @@ plugins { `java-library` `maven-publish` signing + alias(libs.plugins.jmh) id("cel-conventions") } @@ -43,4 +44,13 @@ dependencies { testImplementation(libs.bundles.junit.testing) testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + jmhImplementation(libs.jmh.core) + jmhAnnotationProcessor(libs.jmh.generator.annprocess) } + +jmh { jmhVersion.set(libs.versions.jmh.get()) } + +tasks.named("check") { dependsOn(tasks.named("jmh")) } + +tasks.named("assemble") { dependsOn(tasks.named("jmhJar")) } diff --git a/jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java b/jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java new file mode 100644 index 00000000..5e36e692 --- /dev/null +++ b/jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2021 The Authors of CEL-Java + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.projectnessie.cel.types.jackson3; + +import static org.projectnessie.cel.common.types.StringT.stringOf; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@Warmup(iterations = 1, time = 1500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 300, timeUnit = TimeUnit.MILLISECONDS) +@Fork(1) +@Threads(2) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +public class Jackson3RegistryBench { + + @State(Scope.Benchmark) + public static class ReadState { + JacksonObjectT value; + + @Setup + public void init() { + Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); + registry.typeDescription(Policy.class); + value = + JacksonObjectT.newObject( + registry, + new Policy("policy-1", 7, new Principal("alice@example.com"), Status.ACTIVE), + registry.typeDescription(Policy.class)); + } + } + + @Benchmark + public void registerType(Blackhole blackhole) { + Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); + blackhole.consume(registry.typeDescription(Policy.class)); + } + + @Benchmark + public void registerEnum(Blackhole blackhole) { + Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); + blackhole.consume(registry.enumDescription(Status.class)); + } + + @Benchmark + public void propertyRead(ReadState state, Blackhole blackhole) { + blackhole.consume(state.value.get(stringOf("owner"))); + } + + @Benchmark + public void enumConversion(Blackhole blackhole) { + Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); + registry.enumDescription(Status.class); + blackhole.consume(registry.nativeToValue(Status.ACTIVE)); + } + + public enum Status { + ACTIVE, + DISABLED + } + + public static final class Principal { + private final String email; + + Principal(String email) { + this.email = email; + } + + public String getEmail() { + return email; + } + } + + public static final class Policy { + private final String name; + private final int priority; + private final Principal owner; + private final Status status; + + Policy(String name, int priority, Principal owner, Status status) { + this.name = name; + this.priority = priority; + this.owner = owner; + this.status = status; + } + + public String getName() { + return name; + } + + public int getPriority() { + return priority; + } + + public Principal getOwner() { + return owner; + } + + public Status getStatus() { + return status; + } + } +} From 444907776eff1f27e4cd77b7d83af6443c2c36da Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Tue, 21 Jul 2026 09:50:46 +0200 Subject: [PATCH 2/2] review --- .../InterpreterAllocationBench.java | 4 +- .../cel/interpreter/MacroRuntimeBench.java | 4 +- .../types/jackson/JacksonRegistryBench.java | 39 +++++++++++++------ .../types/jackson3/Jackson3RegistryBench.java | 39 +++++++++++++------ 4 files changed, 60 insertions(+), 26 deletions(-) diff --git a/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java b/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java index 4b209aee..781f863a 100644 --- a/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java +++ b/core/src/jmh/java/org/projectnessie/cel/interpreter/InterpreterAllocationBench.java @@ -144,7 +144,7 @@ public void dynamicMapLiteral(DynamicMapLiteralState state, Blackhole blackhole) public static class ProtoInputState { @Param({ "mapLookup", - "mapLookupMiss", + "mapLookupMissingKeyError", "mapLookupRepeated", "repeatedUintExistsEarly", "repeatedUintExistsLate" @@ -170,7 +170,7 @@ public void init() { mapOf( "msg", protoMessage(size), "key", "key-" + (size - 1), "target", (long) size - 1); return; - case "mapLookupMiss": + case "mapLookupMissingKeyError": program = protoProgram( "msg.map_string_uint64[key] == target", diff --git a/core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java b/core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java index fde49352..eb20b652 100644 --- a/core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java +++ b/core/src/jmh/java/org/projectnessie/cel/interpreter/MacroRuntimeBench.java @@ -75,7 +75,7 @@ public void init() { return; case "all": program = program("items.all(i, i >= 0)"); - vars = mapOf("items", list(size), "target", (long) size - 1); + vars = mapOf("items", list(size)); return; case "filter": program = program("items.filter(i, i > target)"); @@ -83,7 +83,7 @@ public void init() { return; case "map": program = program("items.map(i, i + 1)"); - vars = mapOf("items", list(size), "target", (long) size - 1); + vars = mapOf("items", list(size)); return; default: throw new IllegalArgumentException("Unknown macro benchmark expression: " + expression); diff --git a/jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java b/jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java index ec74c9e7..ae88be30 100644 --- a/jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java +++ b/jackson/src/jmh/java/org/projectnessie/cel/types/jackson/JacksonRegistryBench.java @@ -21,6 +21,7 @@ import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; @@ -41,12 +42,14 @@ public class JacksonRegistryBench { @State(Scope.Benchmark) public static class ReadState { + JacksonRegistry registry; JacksonObjectT value; @Setup public void init() { - JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); + registry = (JacksonRegistry) JacksonRegistry.newRegistry(); registry.typeDescription(Policy.class); + registry.enumDescription(Status.class); value = JacksonObjectT.newObject( registry, @@ -55,16 +58,32 @@ public void init() { } } + /** Supplies a fresh registry to each single-shot cold-registration benchmark iteration. */ + @State(Scope.Thread) + public static class RegistrationState { + JacksonRegistry registry; + + @Setup(Level.Iteration) + public void init() { + registry = (JacksonRegistry) JacksonRegistry.newRegistry(); + } + } + + @Benchmark + public void registryCreation(Blackhole blackhole) { + blackhole.consume(JacksonRegistry.newRegistry()); + } + @Benchmark - public void registerType(Blackhole blackhole) { - JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); - blackhole.consume(registry.typeDescription(Policy.class)); + @BenchmarkMode(Mode.SingleShotTime) + public void registerType(RegistrationState state, Blackhole blackhole) { + blackhole.consume(state.registry.typeDescription(Policy.class)); } @Benchmark - public void registerEnum(Blackhole blackhole) { - JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); - blackhole.consume(registry.enumDescription(Status.class)); + @BenchmarkMode(Mode.SingleShotTime) + public void registerEnum(RegistrationState state, Blackhole blackhole) { + blackhole.consume(state.registry.enumDescription(Status.class)); } @Benchmark @@ -73,10 +92,8 @@ public void propertyRead(ReadState state, Blackhole blackhole) { } @Benchmark - public void enumConversion(Blackhole blackhole) { - JacksonRegistry registry = (JacksonRegistry) JacksonRegistry.newRegistry(); - registry.enumDescription(Status.class); - blackhole.consume(registry.nativeToValue(Status.ACTIVE)); + public void enumConversion(ReadState state, Blackhole blackhole) { + blackhole.consume(state.registry.nativeToValue(Status.ACTIVE)); } public enum Status { diff --git a/jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java b/jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java index 5e36e692..9e739a79 100644 --- a/jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java +++ b/jackson3/src/jmh/java/org/projectnessie/cel/types/jackson3/Jackson3RegistryBench.java @@ -21,6 +21,7 @@ import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; @@ -41,12 +42,14 @@ public class Jackson3RegistryBench { @State(Scope.Benchmark) public static class ReadState { + Jackson3Registry registry; JacksonObjectT value; @Setup public void init() { - Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); + registry = (Jackson3Registry) Jackson3Registry.newRegistry(); registry.typeDescription(Policy.class); + registry.enumDescription(Status.class); value = JacksonObjectT.newObject( registry, @@ -55,16 +58,32 @@ public void init() { } } + /** Supplies a fresh registry to each single-shot cold-registration benchmark iteration. */ + @State(Scope.Thread) + public static class RegistrationState { + Jackson3Registry registry; + + @Setup(Level.Iteration) + public void init() { + registry = (Jackson3Registry) Jackson3Registry.newRegistry(); + } + } + + @Benchmark + public void registryCreation(Blackhole blackhole) { + blackhole.consume(Jackson3Registry.newRegistry()); + } + @Benchmark - public void registerType(Blackhole blackhole) { - Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); - blackhole.consume(registry.typeDescription(Policy.class)); + @BenchmarkMode(Mode.SingleShotTime) + public void registerType(RegistrationState state, Blackhole blackhole) { + blackhole.consume(state.registry.typeDescription(Policy.class)); } @Benchmark - public void registerEnum(Blackhole blackhole) { - Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); - blackhole.consume(registry.enumDescription(Status.class)); + @BenchmarkMode(Mode.SingleShotTime) + public void registerEnum(RegistrationState state, Blackhole blackhole) { + blackhole.consume(state.registry.enumDescription(Status.class)); } @Benchmark @@ -73,10 +92,8 @@ public void propertyRead(ReadState state, Blackhole blackhole) { } @Benchmark - public void enumConversion(Blackhole blackhole) { - Jackson3Registry registry = (Jackson3Registry) Jackson3Registry.newRegistry(); - registry.enumDescription(Status.class); - blackhole.consume(registry.nativeToValue(Status.ACTIVE)); + public void enumConversion(ReadState state, Blackhole blackhole) { + blackhole.consume(state.registry.nativeToValue(Status.ACTIVE)); } public enum Status {