This is an automated email from the ASF dual-hosted git repository. amashenkov pushed a commit to branch ignite-13618 in repository https://gitbox.apache.org/repos/asf/ignite.git
commit 23b1ceb54e414bc0f7067c20d44e0f1de1bb4f47 Author: Andrew Mashenkov <andrey.mashen...@gmail.com> AuthorDate: Fri Nov 20 22:49:24 2020 +0300 Fix styles. Add benchmarks. --- modules/commons/pom.xml | 16 ++ .../generator/JaninoSerializerGenerator.java | 2 +- .../schema/marshaller/reflection/Marshaller.java | 1 + .../reflection => util}/ObjectFactory.java | 9 +- .../benchmarks/SerializerBenchmarkTest.java | 186 +++++++++++++++++++++ .../schema/marshaller/JavaSerializerTest.java | 4 +- 6 files changed, 210 insertions(+), 8 deletions(-) diff --git a/modules/commons/pom.xml b/modules/commons/pom.xml index 472e960..2f0e372 100644 --- a/modules/commons/pom.xml +++ b/modules/commons/pom.xml @@ -39,6 +39,7 @@ <junit.jupiter.version>5.7.0</junit.jupiter.version> <junit.platform.version>1.7.0</junit.platform.version> <mockito.version>1.10.19</mockito.version> + <jmh.verion>1.9.3</jmh.verion> <!-- Maven plugins versions. --> <apache.rat.plugin.version>0.13</apache.rat.plugin.version> @@ -181,6 +182,21 @@ <version>${mockito.version}</version> <scope>test</scope> </dependency> + + <!-- Benchmarks dependencies --> + <!-- TODO: Move the dependencies along with benchmarks code to separate module or profile. --> + <dependency> + <groupId>org.openjdk.jmh</groupId> + <artifactId>jmh-core</artifactId> + <version>${jmh.verion}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.openjdk.jmh</groupId> + <artifactId>jmh-generator-annprocess</artifactId> + <version>${jmh.verion}</version> + <scope>test</scope> + </dependency> </dependencies> <build> <!-- TODO: Move section to some parent module. --> diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java index cd2f89b..def510a 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java @@ -64,7 +64,7 @@ public class JaninoSerializerGenerator implements SerializerFactory { ce.setDebuggingInformation(true, true, true); //TODO: dump code to log. - System.out.println(code); +// System.out.println(code); } try { // Compile and load class. diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java index e5f7145..506c3a3 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java @@ -26,6 +26,7 @@ import org.apache.ignite.internal.schema.marshaller.BinaryMode; import org.apache.ignite.internal.schema.marshaller.MarshallerUtil; import org.apache.ignite.internal.schema.marshaller.SerializationException; import org.apache.ignite.internal.util.Factory; +import org.apache.ignite.internal.util.ObjectFactory; import org.jetbrains.annotations.Nullable; /** diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/ObjectFactory.java b/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java similarity index 83% rename from modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/ObjectFactory.java rename to modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java index 0e622a9..1b0fb4f 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/ObjectFactory.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java @@ -15,15 +15,12 @@ * limitations under the License. */ -package org.apache.ignite.internal.schema.marshaller.reflection; - -import org.apache.ignite.internal.util.Factory; -import org.apache.ignite.internal.util.IgniteUnsafeUtils; +package org.apache.ignite.internal.util; /** * Object factory. */ -class ObjectFactory<T> implements Factory<T> { +public class ObjectFactory<T> implements Factory<T> { /** Class. */ private final Class<T> tClass; @@ -32,7 +29,7 @@ class ObjectFactory<T> implements Factory<T> { * * @param tClass Class. */ - ObjectFactory(Class<T> tClass) { + public ObjectFactory(Class<T> tClass) { this.tClass = tClass; } diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java new file mode 100644 index 0000000..2abe9d4 --- /dev/null +++ b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.ignite.internal.benchmarks; + +import java.lang.reflect.Field; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.internal.schema.Column; +import org.apache.ignite.internal.schema.Columns; +import org.apache.ignite.internal.schema.SchemaDescriptor; +import org.apache.ignite.internal.schema.marshaller.Serializer; +import org.apache.ignite.internal.schema.marshaller.SerializerFactory; +import org.apache.ignite.internal.util.Factory; +import org.apache.ignite.internal.util.ObjectFactory; +import org.codehaus.commons.compiler.CompilerFactoryFactory; +import org.codehaus.commons.compiler.IClassBodyEvaluator; +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.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import static org.apache.ignite.internal.schema.NativeType.LONG; + +/** + * Serializer benchmark. + */ +@State(Scope.Benchmark) +@Warmup(time = 10, iterations = 3, timeUnit = TimeUnit.SECONDS) +@Measurement(time = 10, iterations = 5, timeUnit = TimeUnit.SECONDS) +@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SingleShotTime}) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Fork(1) +public class SerializerBenchmarkTest { + /** Random. */ + private Random rnd = new Random(); + + /** Reflection-based Serializer. */ + private Serializer serializer; + + /** Test object factory. */ + private Factory<?> objectFactory; + + /** Object fields count. */ + @Param({ "10", "100"}) + public int fieldsCount; + + /** Serializer. */ + @Param({"Janino","Java"}) + public String serializerName; + + /** + * Runner. + */ + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(SerializerBenchmarkTest.class.getSimpleName()) + .build(); + + new Runner(opt).run(); + } + + /** + * @throws Exception If failed. + */ + @Setup + public void init() throws Exception { + long seed = System.currentTimeMillis(); + + rnd = new Random(seed); + + final Class<?> valClass = createGeneratedObjectClass(fieldsCount, Long.TYPE); + objectFactory = new ObjectFactory<>(valClass); + + Columns keyCols = new Columns(new Column("key", LONG, true)); + Columns valCols = mapFieldsToColumns(valClass); + final SchemaDescriptor schema = new SchemaDescriptor(1, keyCols, valCols); + + if ("Java".equals(serializerName)) + serializer = SerializerFactory.createJavaSerializerFactory().create(schema, Long.class, valClass); + else + serializer = SerializerFactory.createJaninoSerializerFactory().create(schema, Long.class, valClass); + } + + /** + * Measure serialization-deserialization operation cost. + * + * @param bh Black hole. + * @throws Exception If failed. + */ + @Benchmark + public void measureSerializeDeserializeCost(Blackhole bh) throws Exception { + Long key = rnd.nextLong(); + + Object val = objectFactory.create(); + byte[] bytes = serializer.serialize(key, val); + + // Try different order. + Object restoredVal = serializer.deserializeValue(bytes); + Object restoredKey = serializer.deserializeKey(bytes); + + bh.consume(restoredVal); + bh.consume(restoredKey); + } + + /** + * Map fields to columns. + * + * @param aClass Object class. + * @return Columns for schema + */ + private Columns mapFieldsToColumns(Class<?> aClass) { + final Field[] fields = aClass.getDeclaredFields(); + final Column[] cols = new Column[fields.length]; + + for (int i = 0; i < fields.length; i++) { + assert fields[i].getType() == Long.TYPE : "Only 'long' field type is supported."; + + cols[i] = new Column("col" + i, LONG, false); + } + + return new Columns(cols); + } + + /** + * Generate class for test objects. + * + * @param maxFields Max class member fields. + * @param fieldType Field type. + * @return Generated test object class. + * @throws Exception If failed. + */ + private Class<?> createGeneratedObjectClass(int maxFields, Class<?> fieldType) throws Exception { + final IClassBodyEvaluator ce = CompilerFactoryFactory.getDefaultCompilerFactory().newClassBodyEvaluator(); + + ce.setClassName("TestObject"); + ce.setDefaultImports("java.util.Random"); + + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < maxFields; i++) + sb.append(fieldType.getName()).append(" col").append(i).append(";\n"); + + // Constructor. + sb.append("public TestObject() {\n"); + sb.append(" Random rnd = new Random();\n"); + for (int i = 0; i < maxFields; i++) + sb.append(" col").append(i).append(" = rnd.nextLong();\n"); + sb.append("}\n"); + + try { + ce.setParentClassLoader(getClass().getClassLoader()); + ce.cook(sb.toString()); + + return ce.getClazz(); + } + catch (Exception ex) { + throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex); + } + } +} diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java index babc7cb..27a156d 100644 --- a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java +++ b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java @@ -59,7 +59,9 @@ import static org.junit.jupiter.api.DynamicTest.dynamicTest; * Serializer test. */ public class JavaSerializerTest { - + /** + * @return List of serializers for test. + */ private static List<SerializerFactory> serializerFactoryProvider() { return Arrays.asList( new JaninoSerializerGenerator(),