Kotlinx.serialization: Poor performance compared to moshi (up to 37x) on Android device

Created on 21 Oct 2020  ·  18Comments  ·  Source: Kotlin/kotlinx.serialization

KxSerialization works mach slower than Moshi.

Benchmarks
I've measured performance using android instrumental tests on Xiaomi Mi box 3. Decoding string looks 1.9s using kxSerialization and 53ms using Moshi. It is huge difference in performance. I also tested it on Sony Bravia 4k 2015 and results are same.

Снимок экрана 2020-10-20 в 19 43 30

Снимок экрана 2020-10-21 в 12 25 47

To Reproduce
You can find benchmark test in following archive. I also add some middle size test strings and kxSerialization is slow for them too.
SerializationBenchmark.zip

Also after decoding objects Android log reports that GC actively trying to deallocate objects.

Environment

  • Kotlin version: 1.4.10
  • Library version: 1.0.0
  • Kotlin platforms: Android (JVM)
  • Gradle version: 6.5
  • Device: Xiaomi Mi box 3 and Sony Bravia 4k 2015
1 json runtime

Most helpful comment

Thanks for the self-contained report!
It's indeed a library problem we are going to fix in 1.0.1. Performance is affected only for Json.coerseInputValues set to true and when deserializing class with a lot of nullable fields.

After my fix, the original benchmark shows significant improvement:

benchmark:     6,599,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.moviesParkMoshi
benchmark:     4,319,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.southParkKxSerialization
benchmark:     4,415,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.moviesKxSerialization
benchmark:     6,007,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.southParkMoshi
benchmark:       261,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.seizadMoshi
benchmark:       204,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.seizadKxSerialization

All 18 comments

Same problem

++

This might be an issue with Android, as I conducted a benchmark with Jackson, Kotlin Serialization, and Moshi, and the Kotlin-based serialization consistently came in faster than Moshi (although slower than Jackson).
Base JMH profile:

Benchmark                 (iters)  Mode  Cnt            Score           Error  Units
JMHBenchmark.withJackson     1000  avgt    5      7767767,134 ±    344360,540  ns/op
JMHBenchmark.withJackson    10000  avgt    5     77088841,429 ±   2135684,202  ns/op
JMHBenchmark.withJackson   100000  avgt    5    784534770,000 ±  68284435,845  ns/op
JMHBenchmark.withJackson  1000000  avgt    5   7547759640,000 ± 181701955,670  ns/op
JMHBenchmark.withKotlin      1000  avgt    5      9118821,669 ±    242109,400  ns/op
JMHBenchmark.withKotlin     10000  avgt    5     93693552,727 ±   1817257,298  ns/op
JMHBenchmark.withKotlin    100000  avgt    5    968971400,000 ±  11859926,161  ns/op
JMHBenchmark.withKotlin   1000000  avgt    5   9412599200,000 ± 106118786,279  ns/op
JMHBenchmark.withMoshi       1000  avgt    5     14239516,434 ±   1466899,261  ns/op
JMHBenchmark.withMoshi      10000  avgt    5    137800597,500 ±   1295629,104  ns/op
JMHBenchmark.withMoshi     100000  avgt    5   1415653380,000 ±  32716407,175  ns/op
JMHBenchmark.withMoshi    1000000  avgt    5  14077281900,000 ± 651578031,344  ns/op

GC JMH profile:

Benchmark                                                  (iters)  Mode  Cnt            Score            Error   Units
JMHBenchmark.withJackson                                      1000  avgt    5      8773161,930 ±    2968281,174   ns/op
JMHBenchmark.withJackson:·gc.alloc.rate                       1000  avgt    5          822,138 ±        272,445  MB/sec
JMHBenchmark.withJackson:·gc.alloc.rate.norm                  1000  avgt    5     11273565,297 ±        327,071    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space              1000  avgt    5          821,496 ±        208,186  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space.norm         1000  avgt    5     11291695,676 ±    2421723,315    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space          1000  avgt    5            0,006 ±          0,007  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space.norm     1000  avgt    5           77,221 ±        104,197    B/op
JMHBenchmark.withJackson:·gc.count                            1000  avgt    5           34,000                   counts
JMHBenchmark.withJackson:·gc.time                             1000  avgt    5           33,000                       ms
JMHBenchmark.withJackson                                     10000  avgt    5     79325464,615 ±    7521586,077   ns/op
JMHBenchmark.withJackson:·gc.alloc.rate                      10000  avgt    5          906,786 ±         57,784  MB/sec
JMHBenchmark.withJackson:·gc.alloc.rate.norm                 10000  avgt    5    112093024,000 ±       4222,713    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space             10000  avgt    5          919,173 ±        332,564  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space.norm        10000  avgt    5    113568846,769 ±   37425984,221    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space         10000  avgt    5            0,006 ±          0,012  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space.norm    10000  avgt    5          696,246 ±       1535,174    B/op
JMHBenchmark.withJackson:·gc.count                           10000  avgt    5           32,000                   counts
JMHBenchmark.withJackson:·gc.time                            10000  avgt    5           34,000                       ms
JMHBenchmark.withJackson                                    100000  avgt    5    950925660,000 ±  847384787,163   ns/op
JMHBenchmark.withJackson:·gc.alloc.rate                     100000  avgt    5          866,131 ±        805,213  MB/sec
JMHBenchmark.withJackson:·gc.alloc.rate.norm                100000  avgt    5   1120928068,800 ±      33332,703    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space            100000  avgt    5          869,958 ±        763,803  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space.norm       100000  avgt    5   1130364928,000 ±  198628223,002    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space        100000  avgt    5            0,006 ±          0,008  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space.norm   100000  avgt    5         7788,800 ±       8054,048    B/op
JMHBenchmark.withJackson:·gc.count                          100000  avgt    5           39,000                   counts
JMHBenchmark.withJackson:·gc.time                           100000  avgt    5           40,000                       ms
JMHBenchmark.withJackson                                   1000000  avgt    5   7839193020,000 ±  553124059,456   ns/op
JMHBenchmark.withJackson:·gc.alloc.rate                    1000000  avgt    5         1281,988 ±         84,362  MB/sec
JMHBenchmark.withJackson:·gc.alloc.rate.norm               1000000  avgt    5  11209233857,600 ±      58591,307    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space           1000000  avgt    5         1282,299 ±        115,279  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Eden_Space.norm      1000000  avgt    5  11211374592,000 ±  486537794,870    B/op
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space       1000000  avgt    5            0,008 ±          0,007  MB/sec
JMHBenchmark.withJackson:·gc.churn.G1_Survivor_Space.norm  1000000  avgt    5        68044,800 ±      57419,714    B/op
JMHBenchmark.withJackson:·gc.count                         1000000  avgt    5          243,000                   counts
JMHBenchmark.withJackson:·gc.time                          1000000  avgt    5          256,000                       ms
JMHBenchmark.withKotlin                                       1000  avgt    5     10480215,940 ±    3781310,075   ns/op
JMHBenchmark.withKotlin:·gc.alloc.rate                        1000  avgt    5         1016,362 ±        343,840  MB/sec
JMHBenchmark.withKotlin:·gc.alloc.rate.norm                   1000  avgt    5     16618276,249 ±        225,474    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space               1000  avgt    5         1012,822 ±        410,313  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space.norm          1000  avgt    5     16540588,450 ±    1622298,633    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space           1000  avgt    5            0,008 ±          0,012  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space.norm      1000  avgt    5          130,728 ±        167,515    B/op
JMHBenchmark.withKotlin:·gc.count                             1000  avgt    5           42,000                   counts
JMHBenchmark.withKotlin:·gc.time                              1000  avgt    5           39,000                       ms
JMHBenchmark.withKotlin                                      10000  avgt    5    101500376,808 ±   30397249,444   ns/op
JMHBenchmark.withKotlin:·gc.alloc.rate                       10000  avgt    5         1068,960 ±        311,003  MB/sec
JMHBenchmark.withKotlin:·gc.alloc.rate.norm                  10000  avgt    5    167302612,928 ±       5696,288    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space              10000  avgt    5         1055,594 ±        296,890  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space.norm         10000  avgt    5    165433941,437 ±   33081177,264    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space          10000  avgt    5            0,008 ±          0,008  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space.norm     10000  avgt    5         1288,703 ±       1023,869    B/op
JMHBenchmark.withKotlin:·gc.count                            10000  avgt    5           45,000                   counts
JMHBenchmark.withKotlin:·gc.time                             10000  avgt    5           46,000                       ms
JMHBenchmark.withKotlin                                     100000  avgt    5    943987450,000 ±   30389112,331   ns/op
JMHBenchmark.withKotlin:·gc.alloc.rate                      100000  avgt    5         1326,362 ±         33,945  MB/sec
JMHBenchmark.withKotlin:·gc.alloc.rate.norm                 100000  avgt    5   1661819002,400 ±      21063,006    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space             100000  avgt    5         1325,167 ±        165,107  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space.norm        100000  avgt    5   1660315238,400 ±  201249724,242    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space         100000  avgt    5            0,009 ±          0,009  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space.norm    100000  avgt    5        10883,200 ±      10696,118    B/op
JMHBenchmark.withKotlin:·gc.count                           100000  avgt    5           87,000                   counts
JMHBenchmark.withKotlin:·gc.time                            100000  avgt    5           94,000                       ms
JMHBenchmark.withKotlin                                    1000000  avgt    5   9971825020,000 ± 1002910647,780   ns/op
JMHBenchmark.withKotlin:·gc.alloc.rate                     1000000  avgt    5         1524,046 ±        142,809  MB/sec
JMHBenchmark.withKotlin:·gc.alloc.rate.norm                1000000  avgt    5  16729673990,400 ±      50065,666    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space            1000000  avgt    5         1525,539 ±        114,963  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Eden_Space.norm       1000000  avgt    5  16747855872,000 ±  486537794,870    B/op
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space        1000000  avgt    5            0,009 ±          0,006  MB/sec
JMHBenchmark.withKotlin:·gc.churn.G1_Survivor_Space.norm   1000000  avgt    5        96545,600 ±      58726,789    B/op
JMHBenchmark.withKotlin:·gc.count                          1000000  avgt    5          363,000                   counts
JMHBenchmark.withKotlin:·gc.time                           1000000  avgt    5          384,000                       ms
JMHBenchmark.withMoshi                                        1000  avgt    5     14405638,591 ±    1287410,093   ns/op
JMHBenchmark.withMoshi:·gc.alloc.rate                         1000  avgt    5          647,162 ±         58,776  MB/sec
JMHBenchmark.withMoshi:·gc.alloc.rate.norm                    1000  avgt    5     14634493,658 ±        700,451    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space                1000  avgt    5          655,718 ±        203,924  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space.norm           1000  avgt    5     14824003,485 ±    4149445,195    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space            1000  avgt    5            0,006 ±          0,010  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space.norm       1000  avgt    5          142,242 ±        208,362    B/op
JMHBenchmark.withMoshi:·gc.count                              1000  avgt    5           33,000                   counts
JMHBenchmark.withMoshi:·gc.time                               1000  avgt    5           37,000                       ms
JMHBenchmark.withMoshi                                       10000  avgt    5    140962370,000 ±    2632153,446   ns/op
JMHBenchmark.withMoshi:·gc.alloc.rate                        10000  avgt    5          685,376 ±          9,332  MB/sec
JMHBenchmark.withMoshi:·gc.alloc.rate.norm                   10000  avgt    5    146344457,000 ±       6859,803    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space               10000  avgt    5          681,266 ±        187,061  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space.norm          10000  avgt    5    145489920,000 ±   41466289,336    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space           10000  avgt    5            0,006 ±          0,012  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space.norm      10000  avgt    5         1290,400 ±       2632,210    B/op
JMHBenchmark.withMoshi:·gc.count                             10000  avgt    5           37,000                   counts
JMHBenchmark.withMoshi:·gc.time                              10000  avgt    5           42,000                       ms
JMHBenchmark.withMoshi                                      100000  avgt    5   1386248360,000 ±   33354566,422   ns/op
JMHBenchmark.withMoshi:·gc.alloc.rate                       100000  avgt    5          739,259 ±         13,301  MB/sec
JMHBenchmark.withMoshi:·gc.alloc.rate.norm                  100000  avgt    5   1463401056,000 ±      55172,547    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space              100000  avgt    5          732,558 ±        195,202  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space.norm         100000  avgt    5   1450390323,200 ±  402499448,484    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space          100000  avgt    5            0,004 ±          0,006  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space.norm     100000  avgt    5         8644,800 ±      12590,013    B/op
JMHBenchmark.withMoshi:·gc.count                            100000  avgt    5           38,000                   counts
JMHBenchmark.withMoshi:·gc.time                             100000  avgt    5           45,000                       ms
JMHBenchmark.withMoshi                                     1000000  avgt    5  13792665340,000 ±   77353079,212   ns/op
JMHBenchmark.withMoshi:·gc.alloc.rate                      1000000  avgt    5          976,294 ±          5,477  MB/sec
JMHBenchmark.withMoshi:·gc.alloc.rate.norm                 1000000  avgt    5  14633463044,800 ±      45312,412    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space             1000000  avgt    5          975,766 ±         33,443  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Eden_Space.norm        1000000  avgt    5  14625538048,000 ±  486537794,870    B/op
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space         1000000  avgt    5            0,007 ±          0,003  MB/sec
JMHBenchmark.withMoshi:·gc.churn.G1_Survivor_Space.norm    1000000  avgt    5        97988,800 ±      39811,655    B/op
JMHBenchmark.withMoshi:·gc.count                           1000000  avgt    5          317,000                   counts
JMHBenchmark.withMoshi:·gc.time                            1000000  avgt    5          384,000                       ms

Stack JMH profile:

Secondary result "com.portofrotterdam.jmh.JMHBenchmark.withJackson:·stack":
Stack profiler:

....[Thread state distributions]....................................................................
 66,7%         RUNNABLE
 33,3%         TIMED_WAITING

....[Thread state: RUNNABLE]........................................................................
 33,3%  50,0% <stack is empty, everything is filtered?>
  6,7%  10,0% com.fasterxml.jackson.databind.deser.std.StringCollectionDeserializer.deserialize
  4,2%   6,4% com.fasterxml.jackson.databind.ser.impl.IndexedStringListSerializer.serializeContents
  3,1%   4,6% com.fasterxml.jackson.core.json.ReaderBasedJsonParser.getText
  2,8%   4,2% com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextTextValue
  2,5%   3,7% com.fasterxml.jackson.databind.ser.std.StringSerializer.serialize
  1,6%   2,4% com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer.findSymbol
  1,6%   2,4% com.fasterxml.jackson.module.kotlin.KotlinValueInstantiator.createFromObjectWith
  1,3%   1,9% com.fasterxml.jackson.core.JsonGenerator.writeFieldId
  0,8%   1,2% com.fasterxml.jackson.core.io.SegmentedStringWriter.getAndClear
  8,8%  13,1% <other>

....[Thread state: TIMED_WAITING]...................................................................
 33,3% 100,0% java.lang.Object.wait

Secondary result "com.portofrotterdam.jmh.JMHBenchmark.withKotlin:·stack":
Stack profiler:

....[Thread state distributions]....................................................................
 66,7%         RUNNABLE
 33,3%         TIMED_WAITING

....[Thread state: RUNNABLE]........................................................................
 33,3%  50,0% <stack is empty, everything is filtered?>
  5,5%   8,3% kotlinx.serialization.json.internal.JsonReader.nextString
  4,5%   6,8% kotlinx.serialization.json.internal.JsonReader.takeStringInternal
  4,2%   6,3% kotlinx.serialization.json.internal.StreamingJsonEncoder$Composer.printQuoted
  3,2%   4,8% java.lang.StringUTF16.putCharsSB
  2,7%   4,0% kotlinx.serialization.json.internal.StringOpsKt.printQuoted
  1,9%   2,8% kotlinx.serialization.internal.AbstractCollectionSerializer.merge
  1,7%   2,5% kotlinx.serialization.json.internal.WriteModeKt.switchMode
  1,0%   1,5% kotlinx.serialization.internal.ArrayListSerializer.insert
  0,9%   1,4% kotlinx.serialization.json.internal.JsonReader.takeStringInternal$default
  7,8%  11,7% <other>

....[Thread state: TIMED_WAITING]...................................................................
 33,3% 100,0% java.lang.Object.wait

Secondary result "com.portofrotterdam.jmh.JMHBenchmark.withMoshi:·stack":
Stack profiler:

....[Thread state distributions]....................................................................
 66,7%         RUNNABLE
 33,3%         TIMED_WAITING

....[Thread state: RUNNABLE]........................................................................
 33,3%  50,0% <stack is empty, everything is filtered?>
  7,5%  11,2% okio.Buffer.writeUtf8
  7,0%  10,5% java.lang.StringCoding.decodeUTF8_0
  3,7%   5,5% java.lang.String.<init>
  2,3%   3,5% okio.Buffer.indexOfElement
  2,1%   3,2% com.squareup.moshi.JsonUtf8Writer.string
  2,1%   3,1% com.squareup.moshi.JsonUtf8Reader.hasNext
  1,5%   2,3% java.lang.StringCoding.decodeUTF8
  0,9%   1,3% com.squareup.moshi.JsonUtf8Writer.value
  0,7%   1,0% com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson
  5,6%   8,4% <other>

....[Thread state: TIMED_WAITING]...................................................................
 33,3% 100,0% java.lang.Object.wait

You can download the source code for this benchmark here.

Environment

  • Kotlin Version: 1.4.10
  • Library Version: 1.0.0
  • Java Version: 15
  • Operating System: Windows 10
  • CPU: Intel(R) Core(TM) i7-8550U
  • Memory: 16GB

Just from glancing at those stackframes in Moshi, you appear to be using a String as your JSON input. Moshi operates on bytes. So you're benchmark is including a bunch of UTF-8 encoding to convert the input into bytes and then suffering the required UTF-8 decoding to turn those bytes back into strings (assuming the JSON contains strings).

It's also worth noting that in the common cases such as deserializing from the file system or the network, Moshi can stream the bytes into the decoder whereas this library requires them to have been fully buffered (and UTF-8 decoded, for JSON).

@JakeWharton I'm not sure who you're responding to, as both my benchmark and the benchmark from @KarenkovID are deserializing JSON from a string value, both with Moshi and with the Kotlin Serialization library.

That's leaving a lot of performance on the table for Moshi and is generally not how it's used in practice.

But what @KarenkovID is reporting is that even when using Moshi in an inefficient manner vis-a-vis passing in a string, it's *still* markedly faster than using Kotlin's serialization library.

@severn-everett , you benchmark example doesn't use my models and responses. You can compare models and json strings from my and your archive. My responses are huge and Kotlin data classes has a lot of fields and classes. You can try to run you benchmark with my models and responses.

@KarenkovID I did that and was compiling the result just now.
Here is the updated JMH benchmark project, and it indeed shows Kotlin's serializer as slower than both Moshi and Jackson.

Benchmark                      (iters)  Mode  Cnt           Score           Error  Units
JMHBenchmark.moviesJackson          10  avgt    5   100765746,000 ±   2050939,579  ns/op
JMHBenchmark.moviesJackson         100  avgt    5  1018397360,000 ±  77567945,409  ns/op
JMHBenchmark.moviesKotlin           10  avgt    5   341496940,000 ±  23319182,807  ns/op
JMHBenchmark.moviesKotlin          100  avgt    5  3457663480,000 ± 122944805,618  ns/op
JMHBenchmark.moviesMoshi            10  avgt    5    68028016,000 ±   2326413,137  ns/op
JMHBenchmark.moviesMoshi           100  avgt    5   677281610,000 ±  25227145,677  ns/op
JMHBenchmark.seizadJackson          10  avgt    5     4285756,337 ±     93580,033  ns/op
JMHBenchmark.seizadJackson         100  avgt    5    43386122,138 ±   1712598,655  ns/op
JMHBenchmark.seizadKotlin           10  avgt    5     8894774,896 ±   2394581,154  ns/op
JMHBenchmark.seizadKotlin          100  avgt    5    85039103,333 ±   2881714,210  ns/op
JMHBenchmark.seizadMoshi            10  avgt    5     2931547,281 ±     53994,716  ns/op
JMHBenchmark.seizadMoshi           100  avgt    5    28913633,714 ±    273431,003  ns/op
JMHBenchmark.southParkJackson       10  avgt    5   172757680,000 ±   1423144,811  ns/op
JMHBenchmark.southParkJackson      100  avgt    5  1863368580,000 ±  17118317,888  ns/op
JMHBenchmark.southParkKotlin        10  avgt    5   381088673,333 ±  70934151,519  ns/op
JMHBenchmark.southParkKotlin       100  avgt    5  3569701960,000 ± 105105788,922  ns/op
JMHBenchmark.southParkMoshi         10  avgt    5   121829929,722 ±  16881438,775  ns/op
JMHBenchmark.southParkMoshi        100  avgt    5  1085278680,000 ±   8757413,461  ns/op

Here's one of the stack analyses for Kotlin's serializer:

Secondary result "com.portofrotterdam.jmh.JMHBenchmark.moviesKotlin:·stack":
Stack profiler:

....[Thread state distributions]....................................................................
 66,7%         RUNNABLE
 33,3%         TIMED_WAITING

....[Thread state: RUNNABLE]........................................................................
 33,3%  50,0% <stack is empty, everything is filtered?>
 14,6%  22,0% com.portofrotterdam.jmh.model.response.ElementResponse$$serializer.childSerializers
  7,6%  11,3% kotlinx.serialization.builtins.BuiltinSerializersKt.getNullable
  4,5%   6,7% kotlinx.serialization.internal.SerialDescriptorForNullable.<init>
  4,1%   6,1% kotlinx.serialization.internal.NullableSerializer.<init>
  0,5%   0,8% kotlinx.serialization.json.internal.JsonReader.nextString
  0,5%   0,7% kotlinx.serialization.json.internal.JsonReader.takeStringInternal
  0,2%   0,3% kotlinx.serialization.encoding.AbstractDecoder.decodeNullableSerializableElement
  0,2%   0,2% java.util.Arrays.copyOf
  0,1%   0,2% com.portofrotterdam.jmh.model.response.ElementResponse$$serializer.deserialize
  1,1%   1,7% <other>

....[Thread state: TIMED_WAITING]...................................................................
 33,3% 100,0% java.lang.Object.wait

@severn-everett and you test machine uses i7-8550U with 16gb ram, which match more powerful than average android devise, which uses ARM cpu

I wanted to check for whether this was an Android/limited device issue or a
library issue, and given that the updated JMH tests produce the same
results as your tests, it looks like it's the latter.

Op do 22 okt. 2020 19:24 schreef Karenkov Igor notifications@github.com:

@severn-everett https://github.com/severn-everett and you test machine
uses i7-8550U with 16gb ram, which match more powerful than average android
devise, which uses ARM cpu


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Kotlin/kotlinx.serialization/issues/1156#issuecomment-714642548,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AC7SZ4LPACM4Q6J36UFCVALSMBTD5ANCNFSM4SZQJCEA
.

Thanks for the self-contained report!
It's indeed a library problem we are going to fix in 1.0.1. Performance is affected only for Json.coerseInputValues set to true and when deserializing class with a lot of nullable fields.

After my fix, the original benchmark shows significant improvement:

benchmark:     6,599,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.moviesParkMoshi
benchmark:     4,319,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.southParkKxSerialization
benchmark:     4,415,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.moviesKxSerialization
benchmark:     6,007,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.southParkMoshi
benchmark:       261,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.seizadMoshi
benchmark:       204,000 ns EMULATOR_UNLOCKED_SerializationBenchmark.seizadKxSerialization

@qwwdfsad thank you for quick solving the problem! It is really nice that I can stop migration to moshi now 😄 Can you tell when it will be released? It is really important performance fix for our project and it'll be nice to have opportunity just upgrade lib version. Otherwise, I will have to fork project.

No need to fork. It is already in a branch (and pull request) #1159

I know, but it's not released)

1.0.x is going to be released around next week

@KarenkovID @OsinniyApps @Merlinkoss it's great that you've published your benchmarks based on the real world Okko data.
I would be thrilled to evaluate and, if possible, use them for our integrated benchmark suite, but for that I need it to be published either under Apache 2.0 or Creative Commons license. Is it possible for you to publish it on GitHub under any of these licenses?

@qwwdfsad you can publish our code. Response structure is public and can be taken from Non-auth response to https://okko.tv

Was this page helpful?
0 / 5 - 0 ratings