diff options
author | Sergey Shanshin <sergey.shanshin@jetbrains.com> | 2022-09-07 20:52:08 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-07 20:52:08 +0300 |
commit | daa95c79ffadc0eedbbb4a481a00556b78212e43 (patch) | |
tree | 3b5a0f7ea2ffbed9d0f65fc1fd6b8e6f1893a5a4 | |
parent | 24ac6b81ff418c701047086b5f30a41c5140a0b3 (diff) | |
download | kotlinx.serialization-daa95c79ffadc0eedbbb4a481a00556b78212e43.tar.gz |
Added benchmarks on cacheable child serializers
Relates #1918
3 files changed, 211 insertions, 0 deletions
diff --git a/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/ContextualOverheadBenchmark.kt b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/ContextualOverheadBenchmark.kt new file mode 100644 index 00000000..2773cfc2 --- /dev/null +++ b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/ContextualOverheadBenchmark.kt @@ -0,0 +1,72 @@ +package kotlinx.benchmarks.json + +import kotlinx.serialization.* +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.descriptors.element +import kotlinx.serialization.encoding.* +import kotlinx.serialization.json.* +import kotlinx.serialization.modules.* +import org.openjdk.jmh.annotations.* +import java.util.concurrent.* + +@Warmup(iterations = 7, time = 1) +@Measurement(iterations = 5, time = 1) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Fork(1) +open class ContextualOverheadBenchmark { + @Serializable + data class Holder(val data: @Contextual Data) + + class Data(val a: Int, val b: String) + + object DataSerializer: KSerializer<Data> { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Serializer") { + element<Int>("a") + element<String>("b") + } + + override fun deserialize(decoder: Decoder): Data { + return decoder.decodeStructure(descriptor) { + var a = 0 + var b = "" + while (true) { + when (val index = decodeElementIndex(descriptor)) { + 0 -> a = decodeIntElement(descriptor, 0) + 1 -> b = decodeStringElement(descriptor, 1) + CompositeDecoder.DECODE_DONE -> break + else -> error("Unexpected index: $index") + } + } + Data(a, b) + } + } + + override fun serialize(encoder: Encoder, value: Data) { + encoder.encodeStructure(descriptor) { + encodeIntElement(descriptor, 0, value.a) + encodeStringElement(descriptor, 1, value.b) + } + } + + } + + private val module = SerializersModule { + contextual(DataSerializer) + } + + private val json = Json { serializersModule = module } + + private val holder = Holder(Data(1, "abc")) + private val holderString = json.encodeToString(holder) + private val holderSerializer = serializer<Holder>() + + @Benchmark + fun decode() = json.decodeFromString(holderSerializer, holderString) + + @Benchmark + fun encode() = json.encodeToString(holderSerializer, holder) + +} diff --git a/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/PolymorphismOverheadBenchmark.kt b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/PolymorphismOverheadBenchmark.kt index b272bae6..9af856d3 100644 --- a/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/PolymorphismOverheadBenchmark.kt +++ b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/PolymorphismOverheadBenchmark.kt @@ -19,6 +19,9 @@ open class PolymorphismOverheadBenchmark { data class PolymorphicWrapper(val i: @Polymorphic Poly, val i2: Impl) // amortize the cost a bit @Serializable + data class SimpleWrapper(val poly: @Polymorphic Poly) + + @Serializable data class BaseWrapper(val i: Impl, val i2: Impl) @JsonClassDiscriminator("poly") @@ -40,6 +43,11 @@ open class PolymorphismOverheadBenchmark { private val polyString = json.encodeToString<Poly>(impl) private val serializer = serializer<Poly>() + private val wrapper = SimpleWrapper(Impl(1, "abc")) + private val wrapperString = json.encodeToString(wrapper) + private val wrapperSerializer = serializer<SimpleWrapper>() + + // 5000 @Benchmark fun base() = json.decodeFromString(Impl.serializer(), implString) @@ -51,4 +59,12 @@ open class PolymorphismOverheadBenchmark { @Benchmark fun poly() = json.decodeFromString(serializer, polyString) + // test for child polymorphic serializer in decoding + @Benchmark + fun polyChildDecode() = json.decodeFromString(wrapperSerializer, wrapperString) + + // test for child polymorphic serializer in encoding + @Benchmark + fun polyChildEncode() = json.encodeToString(wrapperSerializer, wrapper) + } diff --git a/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/UseSerializerOverheadBenchmark.kt b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/UseSerializerOverheadBenchmark.kt new file mode 100644 index 00000000..bc3c89d7 --- /dev/null +++ b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/UseSerializerOverheadBenchmark.kt @@ -0,0 +1,123 @@ +@file:UseSerializers(UseSerializerOverheadBenchmark.DataClassSerializer::class, UseSerializerOverheadBenchmark.DataObjectSerializer::class) +package kotlinx.benchmarks.json + + +import kotlinx.serialization.* +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.descriptors.element +import kotlinx.serialization.encoding.* +import kotlinx.serialization.json.* +import kotlinx.serialization.modules.* +import org.openjdk.jmh.annotations.* +import java.util.concurrent.* + +@Warmup(iterations = 7, time = 1) +@Measurement(iterations = 5, time = 1) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Fork(1) +open class UseSerializerOverheadBenchmark { + @Serializable + data class HolderForClass(val data: DataForClass) + + @Serializable + data class HolderForObject(val data: DataForObject) + + class DataForClass(val a: Int, val b: String) + + class DataForObject(val a: Int, val b: String) + + object DataClassSerializer: KSerializer<DataForClass> { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("ClassSerializer") { + element<Int>("a") + element<String>("b") + } + + override fun deserialize(decoder: Decoder): DataForClass { + return decoder.decodeStructure(descriptor) { + var a = 0 + var b = "" + while (true) { + when (val index = decodeElementIndex(ContextualOverheadBenchmark.DataSerializer.descriptor)) { + 0 -> a = decodeIntElement(ContextualOverheadBenchmark.DataSerializer.descriptor, 0) + 1 -> b = decodeStringElement(ContextualOverheadBenchmark.DataSerializer.descriptor, 1) + CompositeDecoder.DECODE_DONE -> break + else -> error("Unexpected index: $index") + } + } + DataForClass(a, b) + } + } + + override fun serialize(encoder: Encoder, value: DataForClass) { + encoder.encodeStructure(descriptor) { + encodeIntElement(descriptor, 0, value.a) + encodeStringElement(descriptor, 1, value.b) + } + } + } + + object DataObjectSerializer: KSerializer<DataForObject> { + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("ObjectSerializer") { + element<Int>("a") + element<String>("b") + } + + override fun deserialize(decoder: Decoder): DataForObject { + return decoder.decodeStructure(descriptor) { + var a = 0 + var b = "" + while (true) { + when (val index = decodeElementIndex(ContextualOverheadBenchmark.DataSerializer.descriptor)) { + 0 -> a = decodeIntElement(ContextualOverheadBenchmark.DataSerializer.descriptor, 0) + 1 -> b = decodeStringElement(ContextualOverheadBenchmark.DataSerializer.descriptor, 1) + CompositeDecoder.DECODE_DONE -> break + else -> error("Unexpected index: $index") + } + } + DataForObject(a, b) + } + } + + override fun serialize(encoder: Encoder, value: DataForObject) { + encoder.encodeStructure(descriptor) { + encodeIntElement(descriptor, 0, value.a) + encodeStringElement(descriptor, 1, value.b) + } + } + } + + private val module = SerializersModule { + contextual(DataClassSerializer) + } + + private val json = Json { serializersModule = module } + + private val classHolder = HolderForClass(DataForClass(1, "abc")) + private val classHolderString = json.encodeToString(classHolder) + private val classHolderSerializer = serializer<HolderForClass>() + + private val objectHolder = HolderForObject(DataForObject(1, "abc")) + private val objectHolderString = json.encodeToString(objectHolder) + private val objectHolderSerializer = serializer<HolderForObject>() + + @Benchmark + fun decodeForClass() = json.decodeFromString(classHolderSerializer, classHolderString) + + @Benchmark + fun encodeForClass() = json.encodeToString(classHolderSerializer, classHolder) + + /* + Any optimizations should not affect the speed of these tests. + It doesn't make sense to cache singleton (`object`) serializer, because the object is accessed instantly + */ + + @Benchmark + fun decodeForObject() = json.decodeFromString(objectHolderSerializer, objectHolderString) + + @Benchmark + fun encodeForObject() = json.encodeToString(objectHolderSerializer, objectHolder) + +} |