Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poor performance compared to moshi (up to 37x) on Android device #1156

Closed
ikarenkov opened this issue Oct 21, 2020 · 18 comments
Closed

Poor performance compared to moshi (up to 37x) on Android device #1156

ikarenkov opened this issue Oct 21, 2020 · 18 comments

Comments

@ikarenkov
Copy link

ikarenkov commented Oct 21, 2020

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
@Merlinkoss
Copy link

Same problem

@osinniy
Copy link

osinniy commented Oct 22, 2020

++

@severn-everett
Copy link

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

@JakeWharton
Copy link
Contributor

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).

@severn-everett
Copy link

severn-everett commented Oct 22, 2020

@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.

@JakeWharton
Copy link
Contributor

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

@severn-everett
Copy link

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.

@ikarenkov
Copy link
Author

@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.

@severn-everett
Copy link

severn-everett commented Oct 22, 2020

@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

@ikarenkov
Copy link
Author

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

@severn-everett
Copy link

severn-everett commented Oct 22, 2020 via email

qwwdfsad added a commit that referenced this issue Oct 22, 2020
…or in order to avoid allocation of nullable serializer and descriptor.

Also, slightly reduce bytecode size

Fixes #1156
@qwwdfsad
Copy link
Collaborator

qwwdfsad commented Oct 22, 2020

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

@ikarenkov
Copy link
Author

@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.

@pdvrieze
Copy link
Contributor

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

@ikarenkov
Copy link
Author

I know, but it's not released)

@qwwdfsad
Copy link
Collaborator

1.0.x is going to be released around next week

@qwwdfsad
Copy link
Collaborator

@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?

@ikarenkov
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants