• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package kotlinx.benchmarks.json
2 
3 import kotlinx.benchmarks.model.*
4 import kotlinx.serialization.*
5 import kotlinx.serialization.json.*
6 import org.openjdk.jmh.annotations.*
7 import java.util.concurrent.*
8 
9 @Warmup(iterations = 7, time = 1)
10 @Measurement(iterations = 7, time = 1)
11 @BenchmarkMode(Mode.Throughput)
12 @OutputTimeUnit(TimeUnit.SECONDS)
13 @State(Scope.Benchmark)
14 @Fork(2)
15 open class TwitterFeedBenchmark {
16 
17     /*
18      * Macro feed benchmark with a lot of UTF-16 used to track general regressions.
19      *
20      * This is a small piece of twitter feed taken from one of the simdjson repository
21      * with Kotlin classes generated by Json2Kotlin plugin (and also manually adjusted)
22      */
23     private val input = TwitterFeedBenchmark::class.java.getResource("/twitter_macro.json").readBytes().decodeToString()
24     private val twitter = Json.decodeFromString(MacroTwitterFeed.serializer(), input)
25 
<lambda>null26     private val jsonNoAltNames = Json { useAlternativeNames = false }
<lambda>null27     private val jsonIgnoreUnknwn = Json { ignoreUnknownKeys = true }
<lambda>null28     private val jsonIgnoreUnknwnNoAltNames = Json { ignoreUnknownKeys = true; useAlternativeNames = false }
<lambda>null29     private val jsonNamingStrategy = Json { namingStrategy = JsonNamingStrategy.SnakeCase }
<lambda>null30     private val jsonNamingStrategyIgnoreUnknwn = Json(jsonNamingStrategy) { ignoreUnknownKeys = true }
31 
32     private val twitterKt = jsonNamingStrategy.decodeFromString(MacroTwitterFeedKt.serializer(), input)
33 
34     @Setup
initnull35     fun init() {
36         require(twitter == Json.decodeFromString(MacroTwitterFeed.serializer(), Json.encodeToString(MacroTwitterFeed.serializer(), twitter)))
37     }
38 
39     // Order of magnitude: ~500 op/s
40     @Benchmark
decodeTwitternull41     fun decodeTwitter() = Json.decodeFromString(MacroTwitterFeed.serializer(), input)
42 
43     // Should be the same as decodeTwitter, since decodeTwitter never hit unknown name and therefore should never build deserializationNamesMap anyway
44     @Benchmark
45     fun decodeTwitterNoAltNames() = jsonNoAltNames.decodeFromString(MacroTwitterFeed.serializer(), input)
46 
47     @Benchmark
48     fun encodeTwitter() = Json.encodeToString(MacroTwitterFeed.serializer(), twitter)
49 
50     @Benchmark
51     fun decodeMicroTwitter() = jsonIgnoreUnknwn.decodeFromString(MicroTwitterFeed.serializer(), input)
52 
53     // Should be faster than decodeMicroTwitter, as we explicitly opt-out from deserializationNamesMap on unknown name
54     @Benchmark
55     fun decodeMicroTwitterNoAltNames() = jsonIgnoreUnknwnNoAltNames.decodeFromString(MicroTwitterFeed.serializer(), input)
56 
57     // Should be just a bit slower than decodeMicroTwitter, because alternative names map is created in both cases
58     @Benchmark
59     fun decodeMicroTwitterWithNamingStrategy(): MicroTwitterFeedKt = jsonNamingStrategyIgnoreUnknwn.decodeFromString(MicroTwitterFeedKt.serializer(), input)
60 
61     // Can be slower than decodeTwitter, as we always build deserializationNamesMap when naming strategy is used
62     @Benchmark
63     fun decodeTwitterWithNamingStrategy(): MacroTwitterFeedKt = jsonNamingStrategy.decodeFromString(MacroTwitterFeedKt.serializer(), input)
64 
65     // 15-20% slower than without the strategy. Without serializationNamesMap (invoking strategy on every write), up to 50% slower
66     @Benchmark
67     fun encodeTwitterWithNamingStrategy(): String = jsonNamingStrategy.encodeToString(MacroTwitterFeedKt.serializer(), twitterKt)
68 
69 }
70