summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Shanshin <sergey.shanshin@jetbrains.com>2022-09-07 20:52:08 +0300
committerGitHub <noreply@github.com>2022-09-07 20:52:08 +0300
commitdaa95c79ffadc0eedbbb4a481a00556b78212e43 (patch)
tree3b5a0f7ea2ffbed9d0f65fc1fd6b8e6f1893a5a4
parent24ac6b81ff418c701047086b5f30a41c5140a0b3 (diff)
downloadkotlinx.serialization-daa95c79ffadc0eedbbb4a481a00556b78212e43.tar.gz
Added benchmarks on cacheable child serializers
Relates #1918
-rw-r--r--benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/ContextualOverheadBenchmark.kt72
-rw-r--r--benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/PolymorphismOverheadBenchmark.kt16
-rw-r--r--benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/UseSerializerOverheadBenchmark.kt123
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)
+
+}