From 8c0115698a72afce2a26656b89bb05b6d524595e Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Tue, 10 Dec 2024 20:16:14 -0500 Subject: [PATCH 1/3] Add map-related protobuf benchmark --- .../benchmarks/protobuf/ProtoMapBenchmark.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 benchmark/src/jmh/kotlin/kotlinx/benchmarks/protobuf/ProtoMapBenchmark.kt diff --git a/benchmark/src/jmh/kotlin/kotlinx/benchmarks/protobuf/ProtoMapBenchmark.kt b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/protobuf/ProtoMapBenchmark.kt new file mode 100644 index 0000000000..f3de66d4eb --- /dev/null +++ b/benchmark/src/jmh/kotlin/kotlinx/benchmarks/protobuf/ProtoMapBenchmark.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.benchmarks.protobuf + +import kotlinx.serialization.Serializable +import kotlinx.serialization.encodeToByteArray +import kotlinx.serialization.protobuf.ProtoBuf +import org.openjdk.jmh.annotations.* +import java.util.concurrent.TimeUnit + +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Fork(1) +open class ProtoMapBenchmark { + + @Serializable + class Holder(val map: Map) + + private val value = Holder((0..128).associateBy { it.toString() }) + private val bytes = ProtoBuf.encodeToByteArray(value) + + @Benchmark + fun toBytes() = ProtoBuf.encodeToByteArray(Holder.serializer(), value) + + @Benchmark + fun fromBytes() = ProtoBuf.decodeFromByteArray(Holder.serializer(), bytes) +} From 2aa911c4249e0cd9735081d0e72c1f46f92776e9 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Tue, 10 Dec 2024 20:39:03 -0500 Subject: [PATCH 2/3] Reimplement ProtoWireType lookup --- .../kotlinx/serialization/protobuf/internal/Helpers.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt index ea6d4b6823..da53c1f621 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt @@ -22,8 +22,15 @@ internal enum class ProtoWireType(val typeId: Int) { ; companion object { + private val entryArray = Array(8) { typeId -> + ProtoWireType.entries.find { it.typeId == typeId } ?: INVALID + } + fun from(typeId: Int): ProtoWireType { - return ProtoWireType.entries.find { it.typeId == typeId } ?: INVALID + if (typeId < 0 || typeId >= entryArray.size) { + return INVALID + } + return entryArray[typeId] } } From 3b6ab740967b7410d26c629c14f01f54ed4d96ea Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Wed, 11 Dec 2024 07:49:04 -0500 Subject: [PATCH 3/3] Embed masking into ProtoWireType.from --- .../serialization/protobuf/internal/Helpers.kt | 12 +++++++----- .../protobuf/internal/ProtobufReader.kt | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt index da53c1f621..33e1c78ccd 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt @@ -26,11 +26,13 @@ internal enum class ProtoWireType(val typeId: Int) { ProtoWireType.entries.find { it.typeId == typeId } ?: INVALID } - fun from(typeId: Int): ProtoWireType { - if (typeId < 0 || typeId >= entryArray.size) { - return INVALID - } - return entryArray[typeId] + /** + * Extracts three least significant bits from the [value] and + * returns [ProtoWireType] with corresponding type id, or [ProtoWireType.INVALID] + * if there are no such a type. + */ + fun fromLeastSignificantBits(value: Int): ProtoWireType { + return entryArray[value and 0b111] } } diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt index 5b8ce1c292..674224a718 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt @@ -42,7 +42,7 @@ internal class ProtobufReader(private val input: ByteArrayInput) { -1 } else { currentId = header ushr 3 - currentType = ProtoWireType.from(header and 0b111) + currentType = ProtoWireType.fromLeastSignificantBits(header) currentId } }