kotlinx.serialization icon indicating copy to clipboard operation
kotlinx.serialization copied to clipboard

Optimize JsonElement

Open swankjesse opened this issue 1 year ago • 1 comments

I’m using kotlinx.serialization on Kotlin/JS. I wrote some code that did something like this:

    val value = 1L
    val jsonElement = Json.encodeToJsonElement(value)
    val dynamic = Json.encodeToDynamic(jsonElement)

(In my actual code, each of these 3 lines happen in different parts of the application. And in my actual code, the value is a more sophisticated data class.)

When I ran this code, it was super slow! In particular I found that a severe bottleneck for my entire program was encoding 1L as a string, and then converting it back to a number.

In particular, this code in JsonElementSerializer was a hot spot:

https://github.com/Kotlin/kotlinx.serialization/blob/master/formats/json/commonMain/src/kotlinx/serialization/json/JsonElementSerializers.kt#L120-L122

        // use .content instead of .longOrNull as latter can process exponential notation,
        // and it should be delegated to double when encoding.
        value.content.toLongOrNull()?.let { return encoder.encodeLong(it) }

This is partly because Long is inefficient on Kotlin/JS, and partly because String.toLongOrNull() does a lot of work.

I was able to get dramatically better performance by skipping the JsonElement intermediate model:

    val value = 1L
    val dynamic = Json.encodeToDynamic(value)

Here’s the actual PR if you’re curious.

I would like for JsonElement to be a low-cost abstraction. In particular I believe the before & after samples above should have similar performance.

swankjesse avatar Aug 21 '24 20:08 swankjesse

Thanks for your investigation! I'll see what I can do with it. Since Double formatting is already different on JS, maybe we'll be able to make this part platform-specific

sandwwraith avatar Aug 22 '24 12:08 sandwwraith