Skip to content

Commit

Permalink
test: add benchmarks to compare with msgpack-javascript
Browse files Browse the repository at this point in the history
  • Loading branch information
esensar committed Dec 24, 2024
1 parent 0a5ad92 commit 110dc63
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 0 deletions.
11 changes: 11 additions & 0 deletions serialization-msgpack/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ kotlin {
}
}
js {
compilations.create("benchmark") {
associateWith(this@js.compilations.getByName("main"))
}
browser {
testTask {
useKarma {
useChromeHeadless()
}
}
}
nodejs {}
}
applyDefaultHierarchyTemplate()
iosArm64()
Expand Down Expand Up @@ -76,11 +80,18 @@ kotlin {
implementation(kotlin("test-js"))
}
}
val jsBenchmark by getting {
dependencies {
implementation(kotlinx("benchmark-runtime", Dependencies.Versions.benchmark))
implementation(npm("@msgpack/msgpack", ">2.0.0 <3.0.0"))
}
}
}
}

benchmark {
targets {
register("jvmBenchmark")
register("jsBenchmark")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack

import com.ensarsarajcic.kotlinx.serialization.msgpack.internal.BasicMsgPackDecoder
import com.ensarsarajcic.kotlinx.serialization.msgpack.stream.toMsgPackBuffer
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.BenchmarkMode
import kotlinx.benchmark.BenchmarkTimeUnit
import kotlinx.benchmark.Measurement
import kotlinx.benchmark.Mode
import kotlinx.benchmark.OutputTimeUnit
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import kotlinx.serialization.Serializable
import kotlinx.serialization.modules.SerializersModule

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Measurement(iterations = 20, time = 1, timeUnit = BenchmarkTimeUnit.SECONDS)
@State(Scope.Benchmark)
open class DeserializeBenchmarks {
@Serializable
class SampleClassWithNestedClass(
var testString: String,
var testInt: Int,
var testBoolean: Boolean,
var testNested: NestedClass,
var secondNested: NestedClass? = null,
) {
@Serializable
class NestedClass(
var testInt: Int? = null,
)
}

// The actual benchmark method
@Benchmark
fun benchmarkKotlinxSerializationMsgpack() {
val decoder =
BasicMsgPackDecoder(
MsgPackConfiguration.default.copy(ignoreUnknownKeys = true),
SerializersModule {
},
@Suppress("ktlint:standard:max-line-length")
"85aa74657374537472696e67a3646566a774657374496e747bab74657374426f6f6c65616ec3aa746573744e657374656483aa74657374537472696e67a3646566ab74657374426f6f6c65616ec3ae616e6f74686572556e6b6e6f776ea474657374ac7365636f6e644e657374656481ab74657374426f6f6c65616ec2".hexStringToByteArray().toMsgPackBuffer(),
)
SampleClassWithNestedClass.serializer().deserialize(decoder)
}

@Benchmark
fun benchmarkMsgpackJs() {
@Suppress("ktlint:standard:max-line-length")
decode<SampleClassWithNestedClass>(
"85aa74657374537472696e67a3646566a774657374496e747bab74657374426f6f6c65616ec3aa746573744e657374656483aa74657374537472696e67a3646566ab74657374426f6f6c65616ec3ae616e6f74686572556e6b6e6f776ea474657374ac7365636f6e644e657374656481ab74657374426f6f6c65616ec2".hexStringToByteArray(),
)
}
}

fun String.hexStringToByteArray() = ByteArray(this.length / 2) { this.substring(it * 2, it * 2 + 2).toInt(16).toByte() }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@file:JsModule("@msgpack/msgpack")
@file:JsNonModule

package com.ensarsarajcic.kotlinx.serialization.msgpack

external fun encode(obj: Any): ByteArray

external fun <T> decode(bytes: ByteArray): T
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.ensarsarajcic.kotlinx.serialization.msgpack

import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.BenchmarkMode
import kotlinx.benchmark.BenchmarkTimeUnit
import kotlinx.benchmark.Measurement
import kotlinx.benchmark.Mode
import kotlinx.benchmark.OutputTimeUnit
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToByteArray

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Measurement(iterations = 20, time = 1, timeUnit = BenchmarkTimeUnit.SECONDS)
@State(Scope.Benchmark)
open class SerializeBenchmarks {
@Serializable
data class SampleClass(
val testString: String,
val testInt: Int,
val testBoolean: Boolean,
)

@Serializable
data class SampleClassWithNestedClass(
val testString: String,
val testInt: Int,
val testBoolean: Boolean,
val testNested: NestedClass,
val testSample: SampleClass,
val testSampleList: List<SampleClass>,
val testSampleMap: Map<String, SampleClass>,
val extraBytes: ByteArray,
val secondNested: NestedClass? = null,
) {
@Serializable
data class NestedClass(
val testInt: Int? = null,
)
}

// The actual benchmark method
@Benchmark
fun benchmarkKotlinxSerializationMsgpack() {
val instance =
SampleClassWithNestedClass(
testString = "testString",
testInt = 10,
testBoolean = true,
testNested = SampleClassWithNestedClass.NestedClass(5),
testSample = SampleClass(testString = "testString2", testInt = 17, testBoolean = false),
testSampleList =
listOf(
SampleClass("testString3", testInt = 25, testBoolean = true),
SampleClass("testString4", testInt = 100, testBoolean = false),
),
testSampleMap =
mapOf(
"testString5" to SampleClass("testString5", testInt = 12, testBoolean = false),
"testString6" to SampleClass("testString6", testInt = 15, testBoolean = true),
),
extraBytes = byteArrayOf(0x12, 0x13, 0x14, 0x15),
secondNested = SampleClassWithNestedClass.NestedClass(null),
)
MsgPack.encodeToByteArray(instance)
}

@Benchmark
fun benchmarkMsgpackJs() {
val instance =
SampleClassWithNestedClass(
testString = "testString",
testInt = 10,
testBoolean = true,
testNested = SampleClassWithNestedClass.NestedClass(5),
testSample = SampleClass(testString = "testString2", testInt = 17, testBoolean = false),
testSampleList =
listOf(
SampleClass("testString3", testInt = 25, testBoolean = true),
SampleClass("testString4", testInt = 100, testBoolean = false),
),
testSampleMap =
mapOf(
"testString5" to SampleClass("testString5", testInt = 12, testBoolean = false),
"testString6" to SampleClass("testString6", testInt = 15, testBoolean = true),
),
extraBytes = byteArrayOf(0x12, 0x13, 0x14, 0x15),
secondNested = SampleClassWithNestedClass.NestedClass(null),
)
encode(instance)
}
}

0 comments on commit 110dc63

Please sign in to comment.