mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-28 20:40:01 +00:00
[Kotlin][FlexBuffers] JSON support for Flexbuffers (#6417)
* [Kotlin][FlexBuffers] Add JSON support for FlexBuffers * [Kotlin][Flexbuffers] Re-implement JSON parser with a tokenizer.
This commit is contained in:
@@ -5,6 +5,7 @@ plugins {
|
||||
id("org.jetbrains.kotlin.plugin.allopen") version "1.4.20"
|
||||
id("kotlinx.benchmark") version "0.2.0-dev-20"
|
||||
id("io.morethan.jmhreport") version "0.9.0"
|
||||
id("de.undercouch.download") version "4.1.1"
|
||||
}
|
||||
|
||||
// allOpen plugin is needed for the benchmark annotations.
|
||||
@@ -32,6 +33,8 @@ benchmark {
|
||||
iterations = 5
|
||||
iterationTime = 300
|
||||
iterationTimeUnit = "ms"
|
||||
// uncomment for benchmarking JSON op only
|
||||
// include(".*JsonBenchmark.*")
|
||||
}
|
||||
}
|
||||
targets {
|
||||
@@ -76,6 +79,11 @@ kotlin {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.4.1")
|
||||
|
||||
//moshi
|
||||
implementation("com.squareup.moshi:moshi-kotlin:1.11.0")
|
||||
|
||||
//gson
|
||||
implementation("com.google.code.gson:gson:2.8.5")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,3 +96,16 @@ kotlin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This task download all JSON files used for benchmarking
|
||||
tasks.register<de.undercouch.gradle.tasks.download.Download>("downloadMultipleFiles") {
|
||||
// We are downloading json benchmark samples from serdes-rs project.
|
||||
// see: https://github.com/serde-rs/json-benchmark/blob/master/data
|
||||
val baseUrl = "https://github.com/serde-rs/json-benchmark/raw/master/data/"
|
||||
src(listOf("$baseUrl/canada.json", "$baseUrl/twitter.json", "$baseUrl/citm_catalog.json"))
|
||||
dest(File("${project.projectDir.absolutePath}/src/jvmMain/resources"))
|
||||
}
|
||||
|
||||
project.tasks.named("compileKotlinJvm") {
|
||||
dependsOn("downloadMultipleFiles")
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Measurement(iterations = 20, time = 1, timeUnit = TimeUnit.NANOSECONDS)
|
||||
class KotlinBenchmark {
|
||||
class FlexBuffersBenchmark {
|
||||
|
||||
var initialCapacity = 1024
|
||||
var value: Double = 0.0
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2021 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.flatbuffers.kotlin.benchmark
|
||||
|
||||
import com.google.flatbuffers.kotlin.ArrayReadBuffer
|
||||
import com.google.flatbuffers.kotlin.JSONParser
|
||||
import com.google.flatbuffers.kotlin.Reference
|
||||
import com.google.flatbuffers.kotlin.toJson
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import kotlinx.benchmark.Blackhole
|
||||
import okio.Buffer
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode
|
||||
import org.openjdk.jmh.annotations.Measurement
|
||||
import org.openjdk.jmh.annotations.Mode
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||
@Measurement(iterations = 100, time = 1, timeUnit = TimeUnit.MICROSECONDS)
|
||||
class JsonBenchmark {
|
||||
|
||||
final val moshi = Moshi.Builder()
|
||||
.addLast(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
final val moshiAdapter = moshi.adapter(Map::class.java)
|
||||
|
||||
final val gson = Gson()
|
||||
final val gsonParser = JsonParser()
|
||||
|
||||
val fbParser = JSONParser()
|
||||
|
||||
final val twitterData = this.javaClass.classLoader.getResourceAsStream("twitter.json")!!.readBytes()
|
||||
final val canadaData = this.javaClass.classLoader.getResourceAsStream("canada.json")!!.readBytes()
|
||||
final val citmData = this.javaClass.classLoader.getResourceAsStream("citm_catalog.json")!!.readBytes()
|
||||
|
||||
val fbCitmRef = JSONParser().parse(ArrayReadBuffer(citmData))
|
||||
val moshiCitmRef = moshi.adapter(Map::class.java).fromJson(citmData.decodeToString())
|
||||
val gsonCitmRef = gsonParser.parse(citmData.decodeToString())
|
||||
|
||||
fun readFlexBuffers(data: ByteArray): Reference = fbParser.parse(ArrayReadBuffer(data))
|
||||
|
||||
fun readMoshi(data: ByteArray): Map<*, *>? {
|
||||
val buffer = Buffer().write(data)
|
||||
return moshiAdapter.fromJson(buffer)
|
||||
}
|
||||
|
||||
fun readGson(data: ByteArray): JsonObject {
|
||||
val parser = JsonParser()
|
||||
val jsonReader = InputStreamReader(ByteArrayInputStream(data))
|
||||
return parser.parse(jsonReader).asJsonObject
|
||||
}
|
||||
|
||||
// TWITTER
|
||||
@Benchmark
|
||||
fun readTwitterFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(twitterData))
|
||||
@Benchmark
|
||||
fun readTwitterMoshi(hole: Blackhole?) = hole?.consume(readMoshi(twitterData))
|
||||
@Benchmark
|
||||
fun readTwitterGson(hole: Blackhole?) = hole?.consume(readGson(twitterData))
|
||||
|
||||
@Benchmark
|
||||
fun roundTripTwitterFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(twitterData).toJson())
|
||||
@Benchmark
|
||||
fun roundTripTwitterMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(twitterData)))
|
||||
@Benchmark
|
||||
fun roundTripTwitterGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(twitterData)))
|
||||
|
||||
// CITM
|
||||
@Benchmark
|
||||
fun readCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(citmData))
|
||||
@Benchmark
|
||||
fun readCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(citmData)))
|
||||
@Benchmark
|
||||
fun readCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(citmData)))
|
||||
|
||||
@Benchmark
|
||||
fun roundTripCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(citmData).toJson())
|
||||
@Benchmark
|
||||
fun roundTripCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(citmData)))
|
||||
@Benchmark
|
||||
fun roundTripCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(citmData)))
|
||||
|
||||
@Benchmark
|
||||
fun writeCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(fbCitmRef.toJson())
|
||||
@Benchmark
|
||||
fun writeCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(moshiCitmRef))
|
||||
@Benchmark
|
||||
fun writeCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(gsonCitmRef))
|
||||
|
||||
// CANADA
|
||||
@Benchmark
|
||||
fun readCanadaFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(canadaData))
|
||||
@Benchmark
|
||||
fun readCanadaMoshi(hole: Blackhole?) = hole?.consume(readMoshi(canadaData))
|
||||
@Benchmark
|
||||
fun readCanadaGson(hole: Blackhole?) = hole?.consume(readGson(canadaData))
|
||||
}
|
||||
Reference in New Issue
Block a user