Rewrote application with benchmarks using MPP plugin and added collec… (#2471)
Rewrote application with benchmarks using MPP plugin and added collecting information in json format.
This commit is contained in:
+104
-51
@@ -1,95 +1,148 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
|
ext.rootBuildDirectory = file('..')
|
||||||
|
|
||||||
|
apply from: "$rootBuildDirectory/gradle/loadRootProperties.gradle"
|
||||||
|
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url 'https://cache-redirector.jetbrains.com/maven-central'
|
url 'https://cache-redirector.jetbrains.com/jcenter'
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
url buildKotlinCompilerRepo
|
url kotlinCompilerRepo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$buildKotlinVersion"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:$gradlePluginVersion"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: 'kotlin-multiplatform'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
maven {
|
||||||
|
url 'https://cache-redirector.jetbrains.com/jcenter'
|
||||||
|
}
|
||||||
maven {
|
maven {
|
||||||
url kotlinCompilerRepo
|
url kotlinCompilerRepo
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
url buildKotlinCompilerRepo
|
url buildKotlinCompilerRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: property
|
private def determinePreset() {
|
||||||
def jvmWarmup = 10000
|
def preset = MPPTools.defaultHostPreset(project)
|
||||||
def nativeWarmup = 10
|
println("$project has been configured for ${preset.name} platform.")
|
||||||
def attempts = 10
|
preset
|
||||||
|
}
|
||||||
|
|
||||||
ext."konan.home" = distDir
|
def hostPreset = determinePreset()
|
||||||
|
|
||||||
apply plugin: 'kotlin'
|
kotlin {
|
||||||
apply plugin: 'application'
|
sourceSets {
|
||||||
apply plugin: 'konan'
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
|
||||||
|
}
|
||||||
|
kotlin.srcDir '../tools/benchmarks/shared/src'
|
||||||
|
kotlin.srcDir 'src/main/kotlin'
|
||||||
|
|
||||||
checkKonanCompiler.dependsOn ':dist'
|
}
|
||||||
|
nativeMain {
|
||||||
|
kotlin.srcDir 'src/main/kotlin-native'
|
||||||
|
}
|
||||||
|
jvmMain {
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
||||||
|
}
|
||||||
|
kotlin.srcDir 'src/main/kotlin-jvm'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
konanArtifacts {
|
targets {
|
||||||
program('Ring') {
|
fromPreset(presets.jvm, 'jvm') {
|
||||||
srcDir 'src/main/kotlin'
|
def mainOutput = compilations.main.output
|
||||||
srcDir 'src/main/kotlin-native'
|
compilations.all {
|
||||||
enableOptimizations true
|
tasks[compileKotlinTaskName].kotlinOptions {
|
||||||
|
jvmTarget = '1.8'
|
||||||
|
}
|
||||||
|
tasks[compileKotlinTaskName].kotlinOptions.suppressWarnings = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fromPreset(hostPreset, 'native') {
|
||||||
|
compilations.main.outputKinds('EXECUTABLE')
|
||||||
|
compilations.main.extraOpts '-opt'
|
||||||
|
compilations.main.buildTypes = [RELEASE]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
MPPTools.createRunTask(project, 'konanRun', kotlin.targets.native) {
|
||||||
main.kotlin.srcDir 'src/main/kotlin'
|
workingDir = project.provider {
|
||||||
main.kotlin.srcDir 'src/main/kotlin-jvm'
|
kotlin.targets.native.compilations.main.getBinary('EXECUTABLE', buildType).parentFile
|
||||||
}
|
|
||||||
|
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions.suppressWarnings = true
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
}
|
||||||
|
args("$nativeWarmup", "$attempts", "${buildDir.absolutePath}/${nativeBenchResults}")
|
||||||
|
outputFileName("${buildDir.absolutePath}/${nativeTextReport}")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
task jvmRun(type: JavaExec) {
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$buildKotlinVersion"
|
|
||||||
}
|
|
||||||
|
|
||||||
task jvmRun(type: JavaExec) {
|
|
||||||
dependsOn 'build'
|
dependsOn 'build'
|
||||||
def output = new ByteArrayOutputStream()
|
def output = new ByteArrayOutputStream()
|
||||||
classpath sourceSets.main.runtimeClasspath
|
def runtimeClasspath = files(
|
||||||
|
kotlin.targets.jvm.compilations.main.output.allOutputs,
|
||||||
|
project.configurations.getByName(kotlin.targets.jvm.compilations.main.runtimeDependencyConfigurationName)
|
||||||
|
)
|
||||||
|
classpath runtimeClasspath
|
||||||
main = "MainKt"
|
main = "MainKt"
|
||||||
args "$jvmWarmup", "$attempts"
|
args "$jvmWarmup", "$attempts", "${buildDir.absolutePath}/${jvmBenchResults}"
|
||||||
standardOutput = output
|
standardOutput = output
|
||||||
doLast {
|
doLast {
|
||||||
dumpReport('jvmReport', output)
|
dumpReport("${buildDir.absolutePath}/${jvmTextReport}", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task konanJsonReport {
|
||||||
|
doLast {
|
||||||
|
String benchContents = new File("${buildDir.absolutePath}/${nativeBenchResults}").text
|
||||||
|
def properties = getCommonProperties() + ['type' : 'native',
|
||||||
|
'compilerVersion': "${konanVersion}".toString(),
|
||||||
|
'flags' : kotlin.targets.native.compilations.main.extraOpts.collect{ '"' + it + '"'},
|
||||||
|
'benchmarks' : benchContents]
|
||||||
|
def output = MPPTools.createJsonReport(properties)
|
||||||
|
new File("${buildDir.absolutePath}/${nativeJson}").write(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task jvmJsonReport {
|
||||||
|
doLast {
|
||||||
|
String benchContents = new File("${buildDir.absolutePath}/${jvmBenchResults}").text
|
||||||
|
def properties = getCommonProperties() + ['type' : 'jvm',
|
||||||
|
'compilerVersion': "${buildKotlinVersion}".toString(),
|
||||||
|
'benchmarks' : benchContents]
|
||||||
|
println(properties['compilerVersion'])
|
||||||
|
def output = MPPTools.createJsonReport(properties)
|
||||||
|
new File("${buildDir.absolutePath}/${jvmJson}").write(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvmRun.finalizedBy jvmJsonReport
|
||||||
|
konanRun.finalizedBy konanJsonReport
|
||||||
|
|
||||||
private void dumpReport(String name, ByteArrayOutputStream output) {
|
private void dumpReport(String name, ByteArrayOutputStream output) {
|
||||||
new File("${buildDir.absolutePath}/${name}.txt").withOutputStream {
|
new File("${name}").withOutputStream {
|
||||||
it.write(output.toByteArray())
|
it.write(output.toByteArray())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task konanRun(type: Exec) {
|
private def getCommonProperties() {
|
||||||
dependsOn 'build'
|
return ['cpu': System.getProperty("os.arch"),
|
||||||
def output = new ByteArrayOutputStream()
|
'os': System.getProperty("os.name"), // OperatingSystem.current().getName()
|
||||||
commandLine konanArtifacts.Ring.getByTarget('host').artifact.absolutePath, "$nativeWarmup", "$attempts"
|
'jdkVersion': System.getProperty("java.version"), // org.gradle.internal.jvm.Jvm.current().javaVersion
|
||||||
standardOutput = output
|
'jdkVendor': System.getProperty("java.vendor"),
|
||||||
doLast {
|
'kotlinVersion': "${kotlinVersion}".toString()]
|
||||||
dumpReport('konanReport', output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startScripts{
|
|
||||||
setEnabled(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task bench(type:DefaultTask) {
|
task bench(type:DefaultTask) {
|
||||||
@@ -97,8 +150,8 @@ task bench(type:DefaultTask) {
|
|||||||
dependsOn konanRun
|
dependsOn konanRun
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
def jvmReport = new Report(project.file("build/jvmReport.txt"))
|
def jvmReport = new Report(project.file("${buildDir.absolutePath}/${jvmTextReport}"))
|
||||||
def konanReport = new Report(project.file("build/konanReport.txt"))
|
def konanReport = new Report(project.file("${buildDir.absolutePath}/${nativeTextReport}"))
|
||||||
def average = "none"
|
def average = "none"
|
||||||
def absoluteAverage = "none"
|
def absoluteAverage = "none"
|
||||||
jvmReport.report
|
jvmReport.report
|
||||||
@@ -138,7 +191,7 @@ class Results {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Report {
|
class Report {
|
||||||
def Map<String, Results> report = new TreeMap()
|
Map<String, Results> report = new TreeMap()
|
||||||
|
|
||||||
Report(File path) {
|
Report(File path) {
|
||||||
path.readLines().drop(3).findAll { it.split(':').length == 3 }.each {
|
path.readLines().drop(3).findAll { it.split(':').length == 3 }.each {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url 'https://cache-redirector.jetbrains.com/maven-central'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url kotlinCompilerRepo
|
||||||
|
}
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'kotlin'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url kotlinCompilerRepo
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url buildKotlinCompilerRepo
|
||||||
|
}
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly gradleApi()
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main.kotlin.srcDirs = ["src", "$projectDir/../../tools/benchmarks/shared/src"]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Reuse Kotlin version from the root project.
|
||||||
|
File rootProjectGradlePropertiesFile = file("${rootProject.projectDir}/../../gradle.properties")
|
||||||
|
if (!rootProjectGradlePropertiesFile.isFile()) {
|
||||||
|
throw new Exception("File $rootProjectGradlePropertiesFile does not exist or is not a file")
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties rootProjectProperties = new Properties()
|
||||||
|
rootProjectGradlePropertiesFile.withInputStream { inputStream ->
|
||||||
|
rootProjectProperties.load(inputStream)
|
||||||
|
if (!rootProjectProperties.containsKey('kotlinVersion')) {
|
||||||
|
throw new Exception("No 'kotlinVersion' property in $rootProjectGradlePropertiesFile file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gradle.beforeProject { project ->
|
||||||
|
rootProjectProperties.forEach { String key, value ->
|
||||||
|
if (!project.hasProperty(key))
|
||||||
|
project.ext[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.gradle.api.NamedDomainObjectCollection
|
||||||
|
import org.gradle.api.NamedDomainObjectContainer
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file includes internal short-cuts visible only inside of the 'buildSrc' module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
internal val hostOs by lazy { System.getProperty("os.name") }
|
||||||
|
internal val userHome by lazy { System.getProperty("user.home") }
|
||||||
|
|
||||||
|
internal val Project.ext: ExtraPropertiesExtension
|
||||||
|
get() = extensions.getByName("ext") as ExtraPropertiesExtension
|
||||||
|
|
||||||
|
internal val Project.kotlin: KotlinMultiplatformExtension
|
||||||
|
get() = extensions.getByName("kotlin") as KotlinMultiplatformExtension
|
||||||
|
|
||||||
|
internal val NamedDomainObjectCollection<KotlinTargetPreset<*>>.macosX64: KotlinTargetPreset<*>
|
||||||
|
get() = getByName(::macosX64.name) as KotlinTargetPreset<*>
|
||||||
|
|
||||||
|
internal val NamedDomainObjectCollection<KotlinTargetPreset<*>>.linuxX64: KotlinTargetPreset<*>
|
||||||
|
get() = getByName(::linuxX64.name) as KotlinTargetPreset<*>
|
||||||
|
|
||||||
|
internal val NamedDomainObjectCollection<KotlinTargetPreset<*>>.mingwX64: KotlinTargetPreset<*>
|
||||||
|
get() = getByName(::mingwX64.name) as KotlinTargetPreset<*>
|
||||||
|
|
||||||
|
internal val NamedDomainObjectContainer<out KotlinCompilation<*>>.main: KotlinNativeCompilation
|
||||||
|
get() = getByName(::main.name) as KotlinNativeCompilation
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:JvmName("MPPTools")
|
||||||
|
|
||||||
|
import groovy.lang.Closure
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.Task
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
|
||||||
|
import org.jetbrains.report.*
|
||||||
|
import org.jetbrains.report.json.*
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file includes short-cuts that may potentially be implemented in Kotlin MPP Gradle plugin in the future.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Short-cuts for detecting the host OS.
|
||||||
|
@get:JvmName("isMacos")
|
||||||
|
val isMacos by lazy { hostOs == "Mac OS X" }
|
||||||
|
|
||||||
|
@get:JvmName("isWindows")
|
||||||
|
val isWindows by lazy { hostOs.startsWith("Windows") }
|
||||||
|
|
||||||
|
@get:JvmName("isLinux")
|
||||||
|
val isLinux by lazy { hostOs == "Linux" }
|
||||||
|
|
||||||
|
// Short-cuts for mostly used paths.
|
||||||
|
@get:JvmName("mingwPath")
|
||||||
|
val mingwPath by lazy { System.getenv("MINGW64_DIR") ?: "c:/msys64/mingw64" }
|
||||||
|
|
||||||
|
@get:JvmName("kotlinNativeDataPath")
|
||||||
|
val kotlinNativeDataPath by lazy {
|
||||||
|
System.getenv("KONAN_DATA_DIR") ?: Paths.get(userHome, ".konan").toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A short-cut for evaluation of the default host Kotlin/Native preset.
|
||||||
|
@JvmOverloads
|
||||||
|
fun defaultHostPreset(
|
||||||
|
subproject: Project,
|
||||||
|
whitelist: List<KotlinTargetPreset<*>> = listOf(subproject.kotlin.presets.macosX64, subproject.kotlin.presets.linuxX64, subproject.kotlin.presets.mingwX64)
|
||||||
|
): KotlinTargetPreset<*> {
|
||||||
|
|
||||||
|
if (whitelist.isEmpty())
|
||||||
|
throw Exception("Preset whitelist must not be empty in Kotlin/Native ${subproject.displayName}.")
|
||||||
|
|
||||||
|
val presetCandidate = when {
|
||||||
|
isMacos -> subproject.kotlin.presets.macosX64
|
||||||
|
isLinux -> subproject.kotlin.presets.linuxX64
|
||||||
|
isWindows -> subproject.kotlin.presets.mingwX64
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (presetCandidate != null && presetCandidate in whitelist)
|
||||||
|
presetCandidate
|
||||||
|
else
|
||||||
|
throw Exception("Host OS '$hostOs' is not supported in Kotlin/Native ${subproject.displayName}.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create benchmarks json report based on information get from gradle project
|
||||||
|
fun createJsonReport(projectProperties: Map<String, Any>): String {
|
||||||
|
fun getValue(key: String): String = projectProperties[key] as? String ?: "uknown"
|
||||||
|
val machine = Environment.Machine(getValue("cpu"), getValue("os"))
|
||||||
|
val jdk = Environment.JDKInstance(getValue("jdkVersion"), getValue("jdkVendor"))
|
||||||
|
val env = Environment(machine, jdk)
|
||||||
|
val flags = (projectProperties["flags"] ?: emptyList<String>()) as List<String>
|
||||||
|
val backend = Compiler.Backend(Compiler.backendTypeFromString(getValue("type"))!! ,
|
||||||
|
getValue("compilerVersion"), flags)
|
||||||
|
val kotlin = Compiler(backend, getValue("kotlinVersion"))
|
||||||
|
val benchDesc = getValue("benchmarks")
|
||||||
|
val benchmarksArray = JsonTreeParser.parse(benchDesc)
|
||||||
|
val benchmarks = BenchmarksReport.parseBenchmarksArray(benchmarksArray)
|
||||||
|
val report = BenchmarksReport(env, benchmarks, kotlin)
|
||||||
|
return report.toJson()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A short-cut to add a Kotlin/Native run task.
|
||||||
|
@JvmOverloads
|
||||||
|
fun createRunTask(
|
||||||
|
subproject: Project,
|
||||||
|
name: String,
|
||||||
|
target: KotlinTarget,
|
||||||
|
configureClosure: Closure<Any>? = null
|
||||||
|
): Task {
|
||||||
|
val task = subproject.tasks.create(name, RunKotlinNativeTask::class.java, target)
|
||||||
|
task.configure(configureClosure ?: task.emptyConfigureClosure())
|
||||||
|
return task
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import groovy.lang.Closure
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.Task
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
|
import javax.inject.Inject
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
open class RunKotlinNativeTask @Inject constructor(
|
||||||
|
private val curTarget: KotlinTarget
|
||||||
|
): DefaultTask() {
|
||||||
|
|
||||||
|
var buildType = "RELEASE"
|
||||||
|
var workingDir: Any = project.projectDir
|
||||||
|
var outputFileName: String? = null
|
||||||
|
private var curArgs: List<String> = emptyList()
|
||||||
|
private val curEnvironment: MutableMap<String, Any> = mutableMapOf()
|
||||||
|
|
||||||
|
fun args(vararg args: Any) {
|
||||||
|
curArgs = args.map { it.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun environment(map: Map<String, Any>) {
|
||||||
|
curEnvironment += map
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configure(configureClosure: Closure<Any>): Task {
|
||||||
|
val task = super.configure(configureClosure)
|
||||||
|
this.dependsOn += curTarget.compilations.main.linkTaskName("EXECUTABLE", buildType)
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
fun depends(taskName: String) {
|
||||||
|
this.dependsOn += taskName
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeTask(output: java.io.OutputStream? = null) {
|
||||||
|
project.exec {
|
||||||
|
it.executable = curTarget.compilations.main.getBinary("EXECUTABLE", buildType).toString()
|
||||||
|
it.args = curArgs
|
||||||
|
it.environment = curEnvironment
|
||||||
|
it.workingDir(workingDir)
|
||||||
|
if (output != null)
|
||||||
|
it.standardOutput = output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun run() {
|
||||||
|
if (outputFileName != null)
|
||||||
|
File(outputFileName).outputStream().use { output -> executeTask(output)}
|
||||||
|
else
|
||||||
|
executeTask()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun emptyConfigureClosure() = object : Closure<Any>(this) {
|
||||||
|
override fun call(): RunKotlinNativeTask {
|
||||||
|
return this@RunKotlinNativeTask
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
org.jetbrains.kotlin.native.home=../dist
|
||||||
|
jvmWarmup = 10000
|
||||||
|
nativeWarmup = 10
|
||||||
|
attempts = 10
|
||||||
|
jvmBenchResults = jvmBenchResults.json
|
||||||
|
nativeBenchResults = nativeBenchResults.json
|
||||||
|
nativeTextReport = nativeReport.txt
|
||||||
|
jvmTextReport = jvmReport.txt
|
||||||
|
nativeJson = nativeReport.json
|
||||||
|
jvmJson = jvmReport.json
|
||||||
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
package org.jetbrains.ring
|
package org.jetbrains.ring
|
||||||
|
|
||||||
fun cleanup() { }
|
actual fun cleanup() { }
|
||||||
@@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.ring
|
package org.jetbrains.ring
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
class Blackhole {
|
actual class Blackhole {
|
||||||
companion object {
|
actual companion object {
|
||||||
var consumer = 0
|
actual var consumer = 0
|
||||||
fun consume(value: Any) {
|
actual fun consume(value: Any) {
|
||||||
consumer += value.hashCode()
|
consumer += value.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,18 +31,37 @@ class Blackhole {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
class Random() {
|
actual class Random actual constructor() {
|
||||||
companion object {
|
actual companion object {
|
||||||
var seedInt = 0
|
actual var seedInt = 0
|
||||||
fun nextInt(boundary: Int = 100): Int {
|
actual fun nextInt(boundary: Int): Int {
|
||||||
seedInt = (3 * seedInt + 11) % boundary
|
seedInt = (3 * seedInt + 11) % boundary
|
||||||
return seedInt
|
return seedInt
|
||||||
}
|
}
|
||||||
|
|
||||||
var seedDouble: Double = 0.1
|
actual var seedDouble: Double = 0.1
|
||||||
fun nextDouble(boundary: Double = 100.0): Double {
|
actual fun nextDouble(boundary: Double): Double {
|
||||||
seedDouble = (7.0 * seedDouble + 7.0) % boundary
|
seedDouble = (7.0 * seedDouble + 7.0) % boundary
|
||||||
return seedDouble
|
return seedDouble
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
actual fun writeToFile(fileName: String, text: String) {
|
||||||
|
File(fileName).printWriter().use { out ->
|
||||||
|
out.println(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for assert funtion in stdlib
|
||||||
|
actual fun assert(value: Boolean) {
|
||||||
|
kotlin.assert(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for measureNanoTime funtion in stdlib
|
||||||
|
actual inline fun measureNanoTime(block: () -> Unit): Long {
|
||||||
|
return kotlin.system.measureNanoTime(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ package org.jetbrains.ring
|
|||||||
|
|
||||||
import kotlin.native.internal.GC
|
import kotlin.native.internal.GC
|
||||||
|
|
||||||
fun cleanup() { GC.collect() }
|
actual fun cleanup() { GC.collect() }
|
||||||
@@ -16,13 +16,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.ring
|
package org.jetbrains.ring
|
||||||
|
|
||||||
|
import platform.posix.*
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
class Blackhole {
|
actual class Blackhole {
|
||||||
@kotlin.native.ThreadLocal
|
@kotlin.native.ThreadLocal
|
||||||
companion object {
|
actual companion object {
|
||||||
var consumer = 0
|
actual var consumer = 0
|
||||||
fun consume(value: Any) {
|
actual fun consume(value: Any) {
|
||||||
consumer += value.hashCode()
|
consumer += value.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,19 +32,41 @@ class Blackhole {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
class Random() {
|
actual class Random actual constructor() {
|
||||||
@kotlin.native.ThreadLocal
|
@kotlin.native.ThreadLocal
|
||||||
companion object {
|
actual companion object {
|
||||||
var seedInt = 0
|
actual var seedInt = 0
|
||||||
fun nextInt(boundary: Int = 100): Int {
|
actual fun nextInt(boundary: Int): Int {
|
||||||
seedInt = (3 * seedInt + 11) % boundary
|
seedInt = (3 * seedInt + 11) % boundary
|
||||||
return seedInt
|
return seedInt
|
||||||
}
|
}
|
||||||
|
|
||||||
var seedDouble: Double = 0.1
|
actual var seedDouble: Double = 0.1
|
||||||
fun nextDouble(boundary: Double = 100.0): Double {
|
actual fun nextDouble(boundary: Double): Double {
|
||||||
seedDouble = (7.0 * seedDouble + 7.0) % boundary
|
seedDouble = (7.0 * seedDouble + 7.0) % boundary
|
||||||
return seedDouble
|
return seedDouble
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
|
||||||
|
actual fun writeToFile(fileName: String, text: String) {
|
||||||
|
val file = fopen(fileName, "wt") ?: error("Cannot write file '$fileName'")
|
||||||
|
try {
|
||||||
|
if (fputs(text, file) == EOF) throw Error("File write error")
|
||||||
|
} finally {
|
||||||
|
fclose(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for assert funtion in stdlib
|
||||||
|
actual fun assert(value: Boolean) {
|
||||||
|
kotlin.assert(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper for measureNanoTime funtion in stdlib
|
||||||
|
actual inline fun measureNanoTime(block: () -> Unit): Long {
|
||||||
|
return kotlin.system.measureNanoTime(block)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package org.jetbrains.ring
|
||||||
|
|
||||||
|
expect fun cleanup()
|
||||||
@@ -15,10 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import org.jetbrains.ring.Launcher
|
import org.jetbrains.ring.Launcher
|
||||||
|
import org.jetbrains.ring.JsonReportCreator
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
var numWarmIterations = 0 // Should be 100000 for jdk based run
|
var numWarmIterations = 0 // Should be 100000 for jdk based run
|
||||||
var numberOfAttempts = 10
|
var numberOfAttempts = 10
|
||||||
|
var jsonReport: String? = null
|
||||||
|
|
||||||
when (args.size) {
|
when (args.size) {
|
||||||
0 -> { }
|
0 -> { }
|
||||||
@@ -27,13 +29,20 @@ fun main(args: Array<String>) {
|
|||||||
numWarmIterations = args[0].toInt()
|
numWarmIterations = args[0].toInt()
|
||||||
numberOfAttempts = args[1].toInt()
|
numberOfAttempts = args[1].toInt()
|
||||||
}
|
}
|
||||||
|
3 -> {
|
||||||
|
numWarmIterations = args[0].toInt()
|
||||||
|
numberOfAttempts = args[1].toInt()
|
||||||
|
jsonReport = args[2].toString()
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
println("Usage: perf [# warmup iterations] [# attempts]")
|
println("Usage: perf [# warmup iterations] [# attempts] [# path of json report]")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Ring starting")
|
println("Ring starting")
|
||||||
println(" warmup iterations count: $numWarmIterations")
|
println(" warmup iterations count: $numWarmIterations")
|
||||||
Launcher(numWarmIterations, numberOfAttempts).runBenchmarks()
|
val results = Launcher(numWarmIterations, numberOfAttempts).runBenchmarks()
|
||||||
|
if (jsonReport != null)
|
||||||
|
JsonReportCreator(results).printJsonReport(jsonReport)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.ring
|
||||||
|
|
||||||
|
import org.jetbrains.report.BenchmarkResult
|
||||||
|
|
||||||
|
class JsonReportCreator(val data: Iterable<BenchmarkResult>) {
|
||||||
|
fun printJsonReport(jsonReport: String): Unit {
|
||||||
|
val reportText = data.joinToString(prefix = "[", postfix = "]") {
|
||||||
|
it.toJson()
|
||||||
|
}
|
||||||
|
writeToFile(jsonReport, reportText)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* Created by semoro on 07.07.17.
|
* Created by semoro on 07.07.17.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import org.jetbrains.ring.assert
|
||||||
|
|
||||||
fun octoTest() {
|
fun octoTest() {
|
||||||
val tree = OctoTree<Boolean>(4)
|
val tree = OctoTree<Boolean>(4)
|
||||||
val to = (2 shl tree.depth)
|
val to = (2 shl tree.depth)
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.ring
|
||||||
|
|
||||||
|
expect fun writeToFile(fileName: String, text: String)
|
||||||
|
|
||||||
|
expect class Blackhole {
|
||||||
|
companion object {
|
||||||
|
var consumer: Int
|
||||||
|
fun consume(value: Any)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect class Random() {
|
||||||
|
companion object {
|
||||||
|
var seedInt: Int
|
||||||
|
fun nextInt(boundary: Int = 100): Int
|
||||||
|
|
||||||
|
var seedDouble: Double
|
||||||
|
fun nextDouble(boundary: Double = 100.0): Double
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect fun assert(value: Boolean)
|
||||||
|
|
||||||
|
expect inline fun measureNanoTime(block: () -> Unit): Long
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ package org.jetbrains.ring
|
|||||||
|
|
||||||
import octoTest
|
import octoTest
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
import kotlin.system.measureNanoTime
|
import org.jetbrains.report.BenchmarkResult
|
||||||
|
|
||||||
val BENCHMARK_SIZE = 100
|
val BENCHMARK_SIZE = 100
|
||||||
|
|
||||||
@@ -28,8 +28,9 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
class Results(val mean: Double, val variance: Double)
|
class Results(val mean: Double, val variance: Double)
|
||||||
|
|
||||||
val results = mutableMapOf<String, Results>()
|
val results = mutableMapOf<String, Results>()
|
||||||
|
val benchmarkResults = mutableListOf<BenchmarkResult>()
|
||||||
|
|
||||||
fun launch(benchmark: () -> Any?): Results { // If benchmark runs too long - use coeff to speed it up.
|
fun launch(benchmark: () -> Any?, name: String) { // If benchmark runs too long - use coeff to speed it up.
|
||||||
var i = numWarmIterations
|
var i = numWarmIterations
|
||||||
|
|
||||||
while (i-- > 0) benchmark()
|
while (i-- > 0) benchmark()
|
||||||
@@ -58,17 +59,22 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
}
|
}
|
||||||
cleanup()
|
cleanup()
|
||||||
}
|
}
|
||||||
samples[k] = time * 1.0 / autoEvaluatedNumberOfMeasureIteration
|
val scaledTime = time * 1.0 / autoEvaluatedNumberOfMeasureIteration
|
||||||
|
samples[k] = scaledTime
|
||||||
|
// Save benchmark object
|
||||||
|
benchmarkResults.add(BenchmarkResult(name, BenchmarkResult.Status.PASSED,
|
||||||
|
scaledTime / 1000, scaledTime / 1000,
|
||||||
|
k + 1, numWarmIterations))
|
||||||
}
|
}
|
||||||
val mean = samples.sum() / numberOfAttempts
|
val mean = samples.sum() / numberOfAttempts
|
||||||
val variance = samples.indices.sumByDouble { (samples[it] - mean) * (samples[it] - mean) } / numberOfAttempts
|
val variance = samples.indices.sumByDouble { (samples[it] - mean) * (samples[it] - mean) } / numberOfAttempts
|
||||||
|
|
||||||
return Results(mean, variance)
|
results[name] = Results(mean, variance)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun runBenchmarks() {
|
fun runBenchmarks(): List<BenchmarkResult> {
|
||||||
runAbstractMethodBenchmark()
|
runAbstractMethodBenchmark()
|
||||||
runClassArrayBenchmark()
|
runClassArrayBenchmark()
|
||||||
runClassBaselineBenchmark()
|
runClassBaselineBenchmark()
|
||||||
@@ -96,6 +102,7 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
runOctoTest()
|
runOctoTest()
|
||||||
|
|
||||||
printResultsNormalized()
|
printResultsNormalized()
|
||||||
|
return benchmarkResults
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -135,8 +142,8 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runAbstractMethodBenchmark() {
|
fun runAbstractMethodBenchmark() {
|
||||||
val benchmark = AbstractMethodBenchmark()
|
val benchmark = AbstractMethodBenchmark()
|
||||||
|
|
||||||
results["AbstractMethod.sortStrings"] = launch(benchmark::sortStrings)
|
launch(benchmark::sortStrings, "AbstractMethod.sortStrings")
|
||||||
results["AbstractMethod.sortStringsWithComparator"] = launch(benchmark::sortStringsWithComparator)
|
launch(benchmark::sortStringsWithComparator, "AbstractMethod.sortStringsWithComparator")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -145,16 +152,16 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = ClassArrayBenchmark()
|
val benchmark = ClassArrayBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["ClassArray.copy"] = launch(benchmark::copy)
|
launch(benchmark::copy,"ClassArray.copy")
|
||||||
results["ClassArray.copyManual"] = launch(benchmark::copyManual)
|
launch(benchmark::copyManual, "ClassArray.copyManual")
|
||||||
results["ClassArray.filterAndCount"] = launch(benchmark::filterAndCount)
|
launch(benchmark::filterAndCount, "ClassArray.filterAndCount")
|
||||||
results["ClassArray.filterAndMap"] = launch(benchmark::filterAndMap)
|
launch(benchmark::filterAndMap, "ClassArray.filterAndMap")
|
||||||
results["ClassArray.filterAndMapManual"] = launch(benchmark::filterAndMapManual)
|
launch(benchmark::filterAndMapManual, "ClassArray.filterAndMapManual")
|
||||||
results["ClassArray.filter"] = launch(benchmark::filter)
|
launch(benchmark::filter, "ClassArray.filter")
|
||||||
results["ClassArray.filterManual"] = launch(benchmark::filterManual)
|
launch(benchmark::filterManual, "ClassArray.filterManual")
|
||||||
results["ClassArray.countFilteredManual"] = launch(benchmark::countFilteredManual)
|
launch(benchmark::countFilteredManual, "ClassArray.countFilteredManual")
|
||||||
results["ClassArray.countFiltered"] = launch(benchmark::countFiltered)
|
launch(benchmark::countFiltered, "ClassArray.countFiltered")
|
||||||
results["ClassArray.countFilteredLocal"] = launch(benchmark::countFilteredLocal)
|
launch(benchmark::countFilteredLocal, "ClassArray.countFilteredLocal")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -162,13 +169,13 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runClassBaselineBenchmark() {
|
fun runClassBaselineBenchmark() {
|
||||||
val benchmark = ClassBaselineBenchmark()
|
val benchmark = ClassBaselineBenchmark()
|
||||||
|
|
||||||
results["ClassBaseline.consume"] = launch(benchmark::consume)
|
launch(benchmark::consume, "ClassBaseline.consume")
|
||||||
results["ClassBaseline.consumeField"] = launch(benchmark::consumeField)
|
launch(benchmark::consumeField, "ClassBaseline.consumeField")
|
||||||
results["ClassBaseline.allocateList"] = launch(benchmark::allocateList)
|
launch(benchmark::allocateList, "ClassBaseline.allocateList")
|
||||||
results["ClassBaseline.allocateArray"] = launch(benchmark::allocateArray)
|
launch(benchmark::allocateArray, "ClassBaseline.allocateArray")
|
||||||
results["ClassBaseline.allocateListAndFill"] = launch(benchmark::allocateListAndFill)
|
launch(benchmark::allocateListAndFill, "ClassBaseline.allocateListAndFill")
|
||||||
results["ClassBaseline.allocateListAndWrite"] = launch(benchmark::allocateListAndWrite)
|
launch(benchmark::allocateListAndWrite, "ClassBaseline.allocateListAndWrite")
|
||||||
results["ClassBaseline.allocateArrayAndFill"] = launch(benchmark::allocateArrayAndFill)
|
launch(benchmark::allocateArrayAndFill, "ClassBaseline.allocateArrayAndFill")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -177,22 +184,22 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = ClassListBenchmark()
|
val benchmark = ClassListBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["ClassList.copy"] = launch(benchmark::copy)
|
launch(benchmark::copy, "ClassList.copy")
|
||||||
results["ClassList.copyManual"] = launch(benchmark::copyManual)
|
launch(benchmark::copyManual, "ClassList.copyManual")
|
||||||
results["ClassList.filterAndCount"] = launch(benchmark::filterAndCount)
|
launch(benchmark::filterAndCount, "ClassList.filterAndCount")
|
||||||
results["ClassList.filterAndCountWithLambda"] = launch(benchmark::filterAndCountWithLambda)
|
launch(benchmark::filterAndCountWithLambda, "ClassList.filterAndCountWithLambda")
|
||||||
results["ClassList.filterWithLambda"] = launch(benchmark::filterWithLambda)
|
launch(benchmark::filterWithLambda, "ClassList.filterWithLambda")
|
||||||
results["ClassList.mapWithLambda"] = launch(benchmark::mapWithLambda)
|
launch(benchmark::mapWithLambda, "ClassList.mapWithLambda")
|
||||||
results["ClassList.countWithLambda"] = launch(benchmark::countWithLambda)
|
launch(benchmark::countWithLambda, "ClassList.countWithLambda")
|
||||||
results["ClassList.filterAndMapWithLambda"] = launch(benchmark::filterAndMapWithLambda)
|
launch(benchmark::filterAndMapWithLambda, "ClassList.filterAndMapWithLambda")
|
||||||
results["ClassList.filterAndMapWithLambdaAsSequence"] = launch(benchmark::filterAndMapWithLambdaAsSequence)
|
launch(benchmark::filterAndMapWithLambdaAsSequence, "ClassList.filterAndMapWithLambdaAsSequence")
|
||||||
results["ClassList.filterAndMap"] = launch(benchmark::filterAndMap)
|
launch(benchmark::filterAndMap, "ClassList.filterAndMap")
|
||||||
results["ClassList.filterAndMapManual"] = launch(benchmark::filterAndMapManual)
|
launch(benchmark::filterAndMapManual, "ClassList.filterAndMapManual")
|
||||||
results["ClassList.filter"] = launch(benchmark::filter)
|
launch(benchmark::filter, "ClassList.filter")
|
||||||
results["ClassList.filterManual"] = launch(benchmark::filterManual)
|
launch(benchmark::filterManual, "ClassList.filterManual")
|
||||||
results["ClassList.countFilteredManual"] = launch(benchmark::countFilteredManual)
|
launch(benchmark::countFilteredManual, "ClassList.countFilteredManual")
|
||||||
results["ClassList.countFiltered"] = launch(benchmark::countFiltered)
|
launch(benchmark::countFiltered, "ClassList.countFiltered")
|
||||||
results["ClassList.reduce"] = launch(benchmark::reduce)
|
launch(benchmark::reduce, "ClassList.reduce")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -201,16 +208,16 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = ClassStreamBenchmark()
|
val benchmark = ClassStreamBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["ClassStream.copy"] = launch(benchmark::copy)
|
launch(benchmark::copy, "ClassStream.copy")
|
||||||
results["ClassStream.copyManual"] = launch(benchmark::copyManual)
|
launch(benchmark::copyManual, "ClassStream.copyManual")
|
||||||
results["ClassStream.filterAndCount"] = launch(benchmark::filterAndCount)
|
launch(benchmark::filterAndCount, "ClassStream.filterAndCount")
|
||||||
results["ClassStream.filterAndMap"] = launch(benchmark::filterAndMap)
|
launch(benchmark::filterAndMap, "ClassStream.filterAndMap")
|
||||||
results["ClassStream.filterAndMapManual"] = launch(benchmark::filterAndMapManual)
|
launch(benchmark::filterAndMapManual, "ClassStream.filterAndMapManual")
|
||||||
results["ClassStream.filter"] = launch(benchmark::filter)
|
launch(benchmark::filter, "ClassStream.filter")
|
||||||
results["ClassStream.filterManual"] = launch(benchmark::filterManual)
|
launch(benchmark::filterManual, "ClassStream.filterManual")
|
||||||
results["ClassStream.countFilteredManual"] = launch(benchmark::countFilteredManual)
|
launch(benchmark::countFilteredManual, "ClassStream.countFilteredManual")
|
||||||
results["ClassStream.countFiltered"] = launch(benchmark::countFiltered)
|
launch(benchmark::countFiltered, "ClassStream.countFiltered")
|
||||||
results["ClassStream.reduce"] = launch(benchmark::reduce)
|
launch(benchmark::reduce, "ClassStream.reduce")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -218,8 +225,8 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runCompanionObjectBenchmark() {
|
fun runCompanionObjectBenchmark() {
|
||||||
val benchmark = CompanionObjectBenchmark()
|
val benchmark = CompanionObjectBenchmark()
|
||||||
|
|
||||||
results["CompanionObject.invokeRegularFunction"] = launch(benchmark::invokeRegularFunction)
|
launch(benchmark::invokeRegularFunction, "CompanionObject.invokeRegularFunction")
|
||||||
results["CompanionObject.invokeJvmStaticFunction"] = launch(benchmark::invokeJvmStaticFunction)
|
launch(benchmark::invokeJvmStaticFunction, "CompanionObject.invokeJvmStaticFunction")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -228,12 +235,12 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = DefaultArgumentBenchmark()
|
val benchmark = DefaultArgumentBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["DefaultArgument.testOneOfTwo"] = launch(benchmark::testOneOfTwo)
|
launch(benchmark::testOneOfTwo, "DefaultArgument.testOneOfTwo")
|
||||||
results["DefaultArgument.testTwoOfTwo"] = launch(benchmark::testTwoOfTwo)
|
launch(benchmark::testTwoOfTwo, "DefaultArgument.testTwoOfTwo")
|
||||||
results["DefaultArgument.testOneOfFour"] = launch(benchmark::testOneOfFour)
|
launch(benchmark::testOneOfFour, "DefaultArgument.testOneOfFour")
|
||||||
results["DefaultArgument.testFourOfFour"] = launch(benchmark::testFourOfFour)
|
launch(benchmark::testFourOfFour, "DefaultArgument.testFourOfFour")
|
||||||
results["DefaultArgument.testOneOfEight"] = launch(benchmark::testOneOfEight)
|
launch(benchmark::testOneOfEight, "DefaultArgument.testOneOfEight")
|
||||||
results["DefaultArgument.testEightOfEight"] = launch(benchmark::testEightOfEight)
|
launch(benchmark::testEightOfEight, "DefaultArgument.testEightOfEight")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -242,7 +249,7 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = ElvisBenchmark()
|
val benchmark = ElvisBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["Elvis.testElvis"] = launch(benchmark::testElvis)
|
launch(benchmark::testElvis, "Elvis.testElvis")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -250,14 +257,14 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runEulerBenchmark() {
|
fun runEulerBenchmark() {
|
||||||
val benchmark = EulerBenchmark()
|
val benchmark = EulerBenchmark()
|
||||||
|
|
||||||
results["Euler.problem1bySequence"] = launch(benchmark::problem1bySequence)
|
launch(benchmark::problem1bySequence, "Euler.problem1bySequence")
|
||||||
results["Euler.problem1"] = launch(benchmark::problem1)
|
launch(benchmark::problem1, "Euler.problem1")
|
||||||
results["Euler.problem2"] = launch(benchmark::problem2)
|
launch(benchmark::problem2, "Euler.problem2")
|
||||||
results["Euler.problem4"] = launch(benchmark::problem4)
|
launch(benchmark::problem4, "Euler.problem4")
|
||||||
results["Euler.problem8"] = launch(benchmark::problem8)
|
launch(benchmark::problem8, "Euler.problem8")
|
||||||
results["Euler.problem9"] = launch(benchmark::problem9)
|
launch(benchmark::problem9, "Euler.problem9")
|
||||||
results["Euler.problem14"] = launch(benchmark::problem14)
|
launch(benchmark::problem14, "Euler.problem14")
|
||||||
results["Euler.problem14full"] = launch(benchmark::problem14full)
|
launch(benchmark::problem14full, "Euler.problem14full")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -265,10 +272,10 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
|
|
||||||
fun runFibonacciBenchmark() {
|
fun runFibonacciBenchmark() {
|
||||||
val benchmark = FibonacciBenchmark()
|
val benchmark = FibonacciBenchmark()
|
||||||
results["Fibonacci.calcClassic"] = launch(benchmark::calcClassic)
|
launch(benchmark::calcClassic, "Fibonacci.calcClassic")
|
||||||
results["Fibonacci.calc"] = launch(benchmark::calc)
|
launch(benchmark::calc, "Fibonacci.calc")
|
||||||
results["Fibonacci.calcWithProgression"] = launch(benchmark::calcWithProgression)
|
launch(benchmark::calcWithProgression, "Fibonacci.calcWithProgression")
|
||||||
results["Fibonacci.calcSquare"] = launch(benchmark::calcSquare)
|
launch(benchmark::calcSquare, "Fibonacci.calcSquare")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -276,27 +283,27 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runForLoopBenchmark() {
|
fun runForLoopBenchmark() {
|
||||||
val benchmark = ForLoopsBenchmark()
|
val benchmark = ForLoopsBenchmark()
|
||||||
|
|
||||||
results["ForLoops.arrayLoop"] = launch(benchmark::arrayLoop)
|
launch(benchmark::arrayLoop, "ForLoops.arrayLoop")
|
||||||
results["ForLoops.intArrayLoop"] = launch(benchmark::intArrayLoop)
|
launch(benchmark::intArrayLoop, "ForLoops.intArrayLoop")
|
||||||
results["ForLoops.floatArrayLoop"] = launch(benchmark::floatArrayLoop)
|
launch(benchmark::floatArrayLoop, "ForLoops.floatArrayLoop")
|
||||||
results["ForLoops.charArrayLoop"] = launch(benchmark::charArrayLoop)
|
launch(benchmark::charArrayLoop, "ForLoops.charArrayLoop")
|
||||||
results["ForLoops.stringLoop"] = launch(benchmark::stringLoop)
|
launch(benchmark::stringLoop, "ForLoops.stringLoop")
|
||||||
|
|
||||||
results["ForLoops.arrayIndicesLoop"] = launch(benchmark::arrayIndicesLoop)
|
launch(benchmark::arrayIndicesLoop, "ForLoops.arrayIndicesLoop")
|
||||||
results["ForLoops.intArrayIndicesLoop"] = launch(benchmark::intArrayIndicesLoop)
|
launch(benchmark::intArrayIndicesLoop, "ForLoops.intArrayIndicesLoop")
|
||||||
results["ForLoops.floatArrayIndicesLoop"] = launch(benchmark::floatArrayIndicesLoop)
|
launch(benchmark::floatArrayIndicesLoop, "ForLoops.floatArrayIndicesLoop")
|
||||||
results["ForLoops.charArrayIndicesLoop"] = launch(benchmark::charArrayIndicesLoop)
|
launch(benchmark::charArrayIndicesLoop, "ForLoops.charArrayIndicesLoop")
|
||||||
results["ForLoops.stringIndicesLoop"] = launch(benchmark::stringIndicesLoop)
|
launch(benchmark::stringIndicesLoop, "ForLoops.stringIndicesLoop")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun runInlineBenchmark() {
|
fun runInlineBenchmark() {
|
||||||
val benchmark = InlineBenchmark()
|
val benchmark = InlineBenchmark()
|
||||||
results["Inline.calculate"] = launch(benchmark::calculate)
|
launch(benchmark::calculate, "Inline.calculate")
|
||||||
results["Inline.calculateInline"] = launch(benchmark::calculateInline)
|
launch(benchmark::calculateInline, "Inline.calculateInline")
|
||||||
results["Inline.calculateGeneric"] = launch(benchmark::calculateGeneric)
|
launch(benchmark::calculateGeneric, "Inline.calculateGeneric")
|
||||||
results["Inline.calculateGenericInline"] = launch(benchmark::calculateGenericInline)
|
launch(benchmark::calculateGenericInline, "Inline.calculateGenericInline")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -305,26 +312,26 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = IntArrayBenchmark()
|
val benchmark = IntArrayBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["IntArray.copy"] = launch(benchmark::copy)
|
launch(benchmark::copy, "IntArray.copy")
|
||||||
results["IntArray.copyManual"] = launch(benchmark::copyManual)
|
launch(benchmark::copyManual, "IntArray.copyManual")
|
||||||
results["IntArray.filterAndCount"] = launch(benchmark::filterAndCount)
|
launch(benchmark::filterAndCount, "IntArray.filterAndCount")
|
||||||
results["IntArray.filterSomeAndCount"] = launch(benchmark::filterSomeAndCount)
|
launch(benchmark::filterSomeAndCount, "IntArray.filterSomeAndCount")
|
||||||
results["IntArray.filterAndMap"] = launch(benchmark::filterAndMap)
|
launch(benchmark::filterAndMap, "IntArray.filterAndMap")
|
||||||
results["IntArray.filterAndMapManual"] = launch(benchmark::filterAndMapManual)
|
launch(benchmark::filterAndMapManual, "IntArray.filterAndMapManual")
|
||||||
results["IntArray.filter"] = launch(benchmark::filter)
|
launch(benchmark::filter, "IntArray.filter")
|
||||||
results["IntArray.filterSome"] = launch(benchmark::filterSome)
|
launch(benchmark::filterSome, "IntArray.filterSome")
|
||||||
results["IntArray.filterPrime"] = launch(benchmark::filterPrime)
|
launch(benchmark::filterPrime, "IntArray.filterPrime")
|
||||||
results["IntArray.filterManual"] = launch(benchmark::filterManual)
|
launch(benchmark::filterManual, "IntArray.filterManual")
|
||||||
results["IntArray.filterSomeManual"] = launch(benchmark::filterSomeManual)
|
launch(benchmark::filterSomeManual, "IntArray.filterSomeManual")
|
||||||
results["IntArray.countFilteredManual"] = launch(benchmark::countFilteredManual)
|
launch(benchmark::countFilteredManual, "IntArray.countFilteredManual")
|
||||||
results["IntArray.countFilteredSomeManual"] = launch(benchmark::countFilteredSomeManual)
|
launch(benchmark::countFilteredSomeManual, "IntArray.countFilteredSomeManual")
|
||||||
results["IntArray.countFilteredPrimeManual"] = launch(benchmark::countFilteredPrimeManual)
|
launch(benchmark::countFilteredPrimeManual, "IntArray.countFilteredPrimeManual")
|
||||||
results["IntArray.countFiltered"] = launch(benchmark::countFiltered)
|
launch(benchmark::countFiltered, "IntArray.countFiltered")
|
||||||
results["IntArray.countFilteredSome"] = launch(benchmark::countFilteredSome)
|
launch(benchmark::countFilteredSome, "IntArray.countFilteredSome")
|
||||||
results["IntArray.countFilteredPrime"] = launch(benchmark::countFilteredPrime)
|
launch(benchmark::countFilteredPrime, "IntArray.countFilteredPrime")
|
||||||
results["IntArray.countFilteredLocal"] = launch(benchmark::countFilteredLocal)
|
launch(benchmark::countFilteredLocal, "IntArray.countFilteredLocal")
|
||||||
results["IntArray.countFilteredSomeLocal"] = launch(benchmark::countFilteredSomeLocal)
|
launch(benchmark::countFilteredSomeLocal, "IntArray.countFilteredSomeLocal")
|
||||||
results["IntArray.reduce"] = launch(benchmark::reduce)
|
launch(benchmark::reduce, "IntArray.reduce")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -332,11 +339,11 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runIntBaselineBenchmark() {
|
fun runIntBaselineBenchmark() {
|
||||||
val benchmark = IntBaselineBenchmark()
|
val benchmark = IntBaselineBenchmark()
|
||||||
|
|
||||||
results["IntBaseline.consume"] = launch(benchmark::consume)
|
launch(benchmark::consume, "IntBaseline.consume")
|
||||||
results["IntBaseline.allocateList"] = launch(benchmark::allocateList)
|
launch(benchmark::allocateList, "IntBaseline.allocateList")
|
||||||
results["IntBaseline.allocateArray"] = launch(benchmark::allocateArray)
|
launch(benchmark::allocateArray, "IntBaseline.allocateArray")
|
||||||
results["IntBaseline.allocateListAndFill"] = launch(benchmark::allocateListAndFill)
|
launch(benchmark::allocateListAndFill, "IntBaseline.allocateListAndFill")
|
||||||
results["IntBaseline.allocateArrayAndFill"] = launch(benchmark::allocateArrayAndFill)
|
launch(benchmark::allocateArrayAndFill, "IntBaseline.allocateArrayAndFill")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -345,17 +352,17 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = IntListBenchmark()
|
val benchmark = IntListBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["IntList.copy"] = launch(benchmark::copy)
|
launch(benchmark::copy, "IntList.copy")
|
||||||
results["IntList.copyManual"] = launch(benchmark::copyManual)
|
launch(benchmark::copyManual, "IntList.copyManual")
|
||||||
results["IntList.filterAndCount"] = launch(benchmark::filterAndCount)
|
launch(benchmark::filterAndCount, "IntList.filterAndCount")
|
||||||
results["IntList.filterAndMap"] = launch(benchmark::filterAndMap)
|
launch(benchmark::filterAndMap, "IntList.filterAndMap")
|
||||||
results["IntList.filterAndMapManual"] = launch(benchmark::filterAndMapManual)
|
launch(benchmark::filterAndMapManual, "IntList.filterAndMapManual")
|
||||||
results["IntList.filter"] = launch(benchmark::filter)
|
launch(benchmark::filter, "IntList.filter")
|
||||||
results["IntList.filterManual"] = launch(benchmark::filterManual)
|
launch(benchmark::filterManual, "IntList.filterManual")
|
||||||
results["IntList.countFilteredManual"] = launch(benchmark::countFilteredManual)
|
launch(benchmark::countFilteredManual, "IntList.countFilteredManual")
|
||||||
results["IntList.countFiltered"] = launch(benchmark::countFiltered)
|
launch(benchmark::countFiltered, "IntList.countFiltered")
|
||||||
results["IntList.countFilteredLocal"] = launch(benchmark::countFilteredLocal)
|
launch(benchmark::countFilteredLocal, "IntList.countFilteredLocal")
|
||||||
results["IntList.reduce"] = launch(benchmark::reduce)
|
launch(benchmark::reduce, "IntList.reduce")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -364,17 +371,17 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = IntStreamBenchmark()
|
val benchmark = IntStreamBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["IntStream.copy"] = launch(benchmark::copy)
|
launch(benchmark::copy, "IntStream.copy")
|
||||||
results["IntStream.copyManual"] = launch(benchmark::copyManual)
|
launch(benchmark::copyManual, "IntStream.copyManual")
|
||||||
results["IntStream.filterAndCount"] = launch(benchmark::filterAndCount)
|
launch(benchmark::filterAndCount, "IntStream.filterAndCount")
|
||||||
results["IntStream.filterAndMap"] = launch(benchmark::filterAndMap)
|
launch(benchmark::filterAndMap, "IntStream.filterAndMap")
|
||||||
results["IntStream.filterAndMapManual"] = launch(benchmark::filterAndMapManual)
|
launch(benchmark::filterAndMapManual, "IntStream.filterAndMapManual")
|
||||||
results["IntStream.filter"] = launch(benchmark::filter)
|
launch(benchmark::filter, "IntStream.filter")
|
||||||
results["IntStream.filterManual"] = launch(benchmark::filterManual)
|
launch(benchmark::filterManual, "IntStream.filterManual")
|
||||||
results["IntStream.countFilteredManual"] = launch(benchmark::countFilteredManual)
|
launch(benchmark::countFilteredManual, "IntStream.countFilteredManual")
|
||||||
results["IntStream.countFiltered"] = launch(benchmark::countFiltered)
|
launch(benchmark::countFiltered, "IntStream.countFiltered")
|
||||||
results["IntStream.countFilteredLocal"] = launch(benchmark::countFilteredLocal)
|
launch(benchmark::countFilteredLocal, "IntStream.countFilteredLocal")
|
||||||
results["IntStream.reduce"] = launch(benchmark::reduce)
|
launch(benchmark::reduce, "IntStream.reduce")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -383,14 +390,14 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = LambdaBenchmark()
|
val benchmark = LambdaBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["Lambda.noncapturingLambda"] = launch(benchmark::noncapturingLambda)
|
launch(benchmark::noncapturingLambda, "Lambda.noncapturingLambda")
|
||||||
results["Lambda.noncapturingLambdaNoInline"] = launch(benchmark::noncapturingLambdaNoInline)
|
launch(benchmark::noncapturingLambdaNoInline, "Lambda.noncapturingLambdaNoInline")
|
||||||
results["Lambda.capturingLambda"] = launch(benchmark::capturingLambda)
|
launch(benchmark::capturingLambda, "Lambda.capturingLambda")
|
||||||
results["Lambda.capturingLambdaNoInline"] = launch(benchmark::capturingLambdaNoInline)
|
launch(benchmark::capturingLambdaNoInline, "Lambda.capturingLambdaNoInline")
|
||||||
results["Lambda.mutatingLambda"] = launch(benchmark::mutatingLambda)
|
launch(benchmark::mutatingLambda, "Lambda.mutatingLambda")
|
||||||
results["Lambda.mutatingLambdaNoInline"] = launch(benchmark::mutatingLambdaNoInline)
|
launch(benchmark::mutatingLambdaNoInline, "Lambda.mutatingLambdaNoInline")
|
||||||
results["Lambda.methodReference"] = launch(benchmark::methodReference)
|
launch(benchmark::methodReference, "Lambda.methodReference")
|
||||||
results["Lambda.methodReferenceNoInline"] = launch(benchmark::methodReferenceNoInline)
|
launch(benchmark::methodReferenceNoInline, "Lambda.methodReferenceNoInline")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -399,13 +406,13 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = LoopBenchmark()
|
val benchmark = LoopBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["Loop.arrayLoop"] = launch(benchmark::arrayLoop)
|
launch(benchmark::arrayLoop, "Loop.arrayLoop")
|
||||||
results["Loop.arrayIndexLoop"] = launch(benchmark::arrayIndexLoop)
|
launch(benchmark::arrayIndexLoop, "Loop.arrayIndexLoop")
|
||||||
results["Loop.rangeLoop"] = launch(benchmark::rangeLoop)
|
launch(benchmark::rangeLoop, "Loop.rangeLoop")
|
||||||
results["Loop.arrayListLoop"] = launch(benchmark::arrayListLoop)
|
launch(benchmark::arrayListLoop, "Loop.arrayListLoop")
|
||||||
results["Loop.arrayWhileLoop"] = launch(benchmark::arrayWhileLoop)
|
launch(benchmark::arrayWhileLoop, "Loop.arrayWhileLoop")
|
||||||
results["Loop.arrayForeachLoop"] = launch(benchmark::arrayForeachLoop)
|
launch(benchmark::arrayForeachLoop, "Loop.arrayForeachLoop")
|
||||||
results["Loop.arrayListForeachLoop"] = launch(benchmark::arrayListForeachLoop)
|
launch(benchmark::arrayListForeachLoop, "Loop.arrayListForeachLoop")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -413,7 +420,7 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runMatrixMapBenchmark() {
|
fun runMatrixMapBenchmark() {
|
||||||
val benchmark = MatrixMapBenchmark()
|
val benchmark = MatrixMapBenchmark()
|
||||||
|
|
||||||
results["MatrixMap.add"] = launch(benchmark::add)
|
launch(benchmark::add, "MatrixMap.add")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -421,12 +428,12 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runParameterNotNullAssertionBenchmark() {
|
fun runParameterNotNullAssertionBenchmark() {
|
||||||
val benchmark = ParameterNotNullAssertionBenchmark()
|
val benchmark = ParameterNotNullAssertionBenchmark()
|
||||||
|
|
||||||
results["ParameterNotNull.invokeOneArgWithNullCheck"] = launch(benchmark::invokeOneArgWithNullCheck)
|
launch(benchmark::invokeOneArgWithNullCheck, "ParameterNotNull.invokeOneArgWithNullCheck")
|
||||||
results["ParameterNotNull.invokeOneArgWithoutNullCheck"] = launch(benchmark::invokeOneArgWithoutNullCheck)
|
launch(benchmark::invokeOneArgWithoutNullCheck, "ParameterNotNull.invokeOneArgWithoutNullCheck")
|
||||||
results["ParameterNotNull.invokeTwoArgsWithNullCheck"] = launch(benchmark::invokeTwoArgsWithNullCheck)
|
launch(benchmark::invokeTwoArgsWithNullCheck, "ParameterNotNull.invokeTwoArgsWithNullCheck")
|
||||||
results["ParameterNotNull.invokeTwoArgsWithoutNullCheck"] = launch(benchmark::invokeTwoArgsWithoutNullCheck)
|
launch(benchmark::invokeTwoArgsWithoutNullCheck, "ParameterNotNull.invokeTwoArgsWithoutNullCheck")
|
||||||
results["ParameterNotNull.invokeEightArgsWithNullCheck"] = launch(benchmark::invokeEightArgsWithNullCheck)
|
launch(benchmark::invokeEightArgsWithNullCheck, "ParameterNotNull.invokeEightArgsWithNullCheck")
|
||||||
results["ParameterNotNull.invokeEightArgsWithoutNullCheck"] = launch(benchmark::invokeEightArgsWithoutNullCheck)
|
launch(benchmark::invokeEightArgsWithoutNullCheck, "ParameterNotNull.invokeEightArgsWithoutNullCheck")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -434,8 +441,8 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
fun runPrimeListBenchmark() {
|
fun runPrimeListBenchmark() {
|
||||||
val benchmark = PrimeListBenchmark()
|
val benchmark = PrimeListBenchmark()
|
||||||
|
|
||||||
results["PrimeList.calcDirect"] = launch(benchmark::calcDirect)
|
launch(benchmark::calcDirect, "PrimeList.calcDirect")
|
||||||
results["PrimeList.calcEratosthenes"] = launch(benchmark::calcEratosthenes)
|
launch(benchmark::calcEratosthenes, "PrimeList.calcEratosthenes")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -444,11 +451,11 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = StringBenchmark()
|
val benchmark = StringBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["String.stringConcat"] = launch(benchmark::stringConcat)
|
launch(benchmark::stringConcat, "String.stringConcat")
|
||||||
results["String.stringConcatNullable"] = launch(benchmark::stringConcatNullable)
|
launch(benchmark::stringConcatNullable, "String.stringConcatNullable")
|
||||||
results["String.stringBuilderConcat"] = launch(benchmark::stringBuilderConcat)
|
launch(benchmark::stringBuilderConcat, "String.stringBuilderConcat")
|
||||||
results["String.stringBuilderConcatNullable"] = launch(benchmark::stringBuilderConcatNullable)
|
launch(benchmark::stringBuilderConcatNullable, "String.stringBuilderConcatNullable")
|
||||||
results["String.summarizeSplittedCsv"] = launch(benchmark::summarizeSplittedCsv)
|
launch(benchmark::summarizeSplittedCsv, "String.summarizeSplittedCsv")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -460,15 +467,15 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
benchmark.setupEnums()
|
benchmark.setupEnums()
|
||||||
benchmark.setupSealedClassses()
|
benchmark.setupSealedClassses()
|
||||||
|
|
||||||
results["Switch.testSparseIntSwitch"] = launch(benchmark::testSparseIntSwitch)
|
launch(benchmark::testSparseIntSwitch, "Switch.testSparseIntSwitch")
|
||||||
results["Switch.testDenseIntSwitch"] = launch(benchmark::testDenseIntSwitch)
|
launch(benchmark::testDenseIntSwitch, "Switch.testDenseIntSwitch")
|
||||||
results["Switch.testConstSwitch"] = launch(benchmark::testConstSwitch)
|
launch(benchmark::testConstSwitch, "Switch.testConstSwitch")
|
||||||
results["Switch.testObjConstSwitch"] = launch(benchmark::testObjConstSwitch)
|
launch(benchmark::testObjConstSwitch, "Switch.testObjConstSwitch")
|
||||||
results["Switch.testVarSwitch"] = launch(benchmark::testVarSwitch)
|
launch(benchmark::testVarSwitch, "Switch.testVarSwitch")
|
||||||
results["Switch.testStringsSwitch"] = launch(benchmark::testStringsSwitch)
|
launch(benchmark::testStringsSwitch, "Switch.testStringsSwitch")
|
||||||
results["Switch.testEnumsSwitch"] = launch(benchmark::testEnumsSwitch)
|
launch(benchmark::testEnumsSwitch, "Switch.testEnumsSwitch")
|
||||||
results["Switch.testDenseEnumsSwitch"] = launch(benchmark::testDenseEnumsSwitch)
|
launch(benchmark::testDenseEnumsSwitch, "Switch.testDenseEnumsSwitch")
|
||||||
results["Switch.testSealedWhenSwitch"] = launch(benchmark::testSealedWhenSwitch)
|
launch(benchmark::testSealedWhenSwitch, "Switch.testSealedWhenSwitch")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -477,14 +484,14 @@ class Launcher(val numWarmIterations: Int, val numberOfAttempts: Int) {
|
|||||||
val benchmark = WithIndiciesBenchmark()
|
val benchmark = WithIndiciesBenchmark()
|
||||||
benchmark.setup()
|
benchmark.setup()
|
||||||
|
|
||||||
results["WithIndicies.withIndicies"] = launch(benchmark::withIndicies)
|
launch(benchmark::withIndicies, "WithIndicies.withIndicies")
|
||||||
results["WithIndicies.withIndiciesManual"] = launch(benchmark::withIndiciesManual)
|
launch(benchmark::withIndiciesManual, "WithIndicies.withIndiciesManual")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun runOctoTest() {
|
fun runOctoTest() {
|
||||||
results["OctoTest"] = launch(::octoTest)
|
launch(::octoTest, "OctoTest")
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ include ':common'
|
|||||||
include ':backend.native:tests'
|
include ':backend.native:tests'
|
||||||
include ':backend.native:debugger-tests'
|
include ':backend.native:debugger-tests'
|
||||||
include ':utilities'
|
include ':utilities'
|
||||||
include ':performance'
|
//include ':performance' TODO: return when there is one HostManager class version
|
||||||
include ':platformLibs'
|
include ':platformLibs'
|
||||||
|
|
||||||
includeBuild 'shared'
|
includeBuild 'shared'
|
||||||
|
|||||||
@@ -0,0 +1,325 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.report
|
||||||
|
|
||||||
|
import org.jetbrains.report.json.*
|
||||||
|
|
||||||
|
interface JsonSerializable {
|
||||||
|
fun toJson(): String
|
||||||
|
|
||||||
|
// Convert iterable objects arrays, lists to json.
|
||||||
|
fun <T> arrayToJson(data: Iterable<T>): String {
|
||||||
|
return data.joinToString(prefix = "[", postfix = "]") {
|
||||||
|
if (it is JsonSerializable) it.toJson() else it.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entity can be created from json description.
|
||||||
|
interface ConvertedFromJson {
|
||||||
|
fun getRequiredField(data: JsonObject, fieldName: String): JsonElement {
|
||||||
|
return data.getOrNull(fieldName) ?: error("Field '$fieldName' doesn't exist in '$data'. Please, check origin files.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOptionalField(data: JsonObject, fieldName: String): JsonElement? {
|
||||||
|
return data.getOrNull(fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse json array to list.
|
||||||
|
// Takes function to convert elements in array to expected type.
|
||||||
|
fun <T> arrayToList(array: JsonArray, convert: JsonArray.(Int) -> T?): List<T> {
|
||||||
|
var results = mutableListOf<T>()
|
||||||
|
var index = 0
|
||||||
|
var current: T? = array.convert(index)
|
||||||
|
while (current != null) {
|
||||||
|
results.add(current)
|
||||||
|
index++
|
||||||
|
current = array.convert(index)
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods for conversion to expected type with checks of possibility of such conversions.
|
||||||
|
fun elementToDouble(element: JsonElement, name: String): Double =
|
||||||
|
if (element is JsonPrimitive)
|
||||||
|
element.double
|
||||||
|
else
|
||||||
|
error("Field '$name' in '$element' is expected to be a double number. Please, check origin files.")
|
||||||
|
|
||||||
|
fun elementToInt(element: JsonElement, name: String): Int =
|
||||||
|
if (element is JsonPrimitive)
|
||||||
|
element.int
|
||||||
|
else
|
||||||
|
error("Field '$name' in '$element' is expected to be an integer number. Please, check origin files.")
|
||||||
|
|
||||||
|
fun elementToString(element: JsonElement, name:String): String =
|
||||||
|
if (element is JsonLiteral)
|
||||||
|
element.unquoted()
|
||||||
|
else
|
||||||
|
error("Field '$name' in '$element' is expected to be a string. Please, check origin files.")
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EntityFromJsonFactory<T>: ConvertedFromJson {
|
||||||
|
fun create(data: JsonElement): T
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class for benchcmarks report with all information of run.
|
||||||
|
data class BenchmarksReport(val env: Environment, val benchmarks: List<BenchmarkResult>, val compiler: Compiler):
|
||||||
|
JsonSerializable {
|
||||||
|
|
||||||
|
companion object: EntityFromJsonFactory<BenchmarksReport> {
|
||||||
|
override fun create(data: JsonElement): BenchmarksReport {
|
||||||
|
if (data is JsonObject) {
|
||||||
|
val env = Environment.create(getRequiredField(data, "env"))
|
||||||
|
val benchmarksObj = getRequiredField(data, "benchmarks")
|
||||||
|
val compiler = Compiler.create(getRequiredField(data, "kotlin"))
|
||||||
|
val benchmarks = parseBenchmarksArray(benchmarksObj)
|
||||||
|
return BenchmarksReport(env, benchmarks, compiler)
|
||||||
|
} else {
|
||||||
|
error("Top level entity is expected to be an object. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse array with benchmarks to list
|
||||||
|
fun parseBenchmarksArray(data: JsonElement): List<BenchmarkResult> {
|
||||||
|
if (data is JsonArray) {
|
||||||
|
return arrayToList(data.jsonArray, { index ->
|
||||||
|
if (this.getObjectOrNull(index) != null)
|
||||||
|
BenchmarkResult.create(this.getObjectOrNull(index) as JsonObject)
|
||||||
|
else null
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
error("Benchmarks field is expected to be an array. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): String {
|
||||||
|
return """
|
||||||
|
{
|
||||||
|
"env": ${env.toJson()},
|
||||||
|
"kotlin": ${compiler.toJson()},
|
||||||
|
"benchmarks": ${arrayToJson(benchmarks)}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class for kotlin compiler
|
||||||
|
data class Compiler(val backend: Backend, val kotlinVersion: String): JsonSerializable {
|
||||||
|
|
||||||
|
enum class BackendType(val type: String) {
|
||||||
|
JVM("jvm"),
|
||||||
|
NATIVE("native")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object: EntityFromJsonFactory<Compiler> {
|
||||||
|
override fun create(data: JsonElement): Compiler {
|
||||||
|
if (data is JsonObject) {
|
||||||
|
val backend = Backend.create(getRequiredField(data, "backend"))
|
||||||
|
val kotlinVersion = elementToString(getRequiredField(data, "kotlinVersion"), "kotlinVersion")
|
||||||
|
|
||||||
|
return Compiler(backend, kotlinVersion)
|
||||||
|
} else {
|
||||||
|
error("Kotlin entity is expected to be an object. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun backendTypeFromString(s: String): BackendType? = BackendType.values().find { it.type == s }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class for compiler backend
|
||||||
|
data class Backend(val type: BackendType, val version: String, val flags: List<String>): JsonSerializable {
|
||||||
|
companion object: EntityFromJsonFactory<Backend> {
|
||||||
|
override fun create(data: JsonElement): Backend {
|
||||||
|
if (data is JsonObject) {
|
||||||
|
val typeElement = getRequiredField(data, "type")
|
||||||
|
if (typeElement is JsonLiteral) {
|
||||||
|
val type = backendTypeFromString(typeElement.unquoted()) ?: error("Backend type should be 'jvm' or 'native'")
|
||||||
|
val version = elementToString(getRequiredField(data, "version"), "version")
|
||||||
|
val flagsArray = getOptionalField(data, "flags")
|
||||||
|
var flags: List<String> = emptyList()
|
||||||
|
if (flagsArray != null && flagsArray is JsonArray) {
|
||||||
|
flags = arrayToList(flagsArray.jsonArray, { index ->
|
||||||
|
this.getPrimitiveOrNull(index)?.toString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return Backend(type, version, flags)
|
||||||
|
} else {
|
||||||
|
error("Backend type should be string literal.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Backend entity is expected to be an object. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): String {
|
||||||
|
val result = """
|
||||||
|
{
|
||||||
|
"type": "${type.type}",
|
||||||
|
"version": "${version}""""
|
||||||
|
// Don't print flags field if there is no one.
|
||||||
|
if (flags.isEmpty()) {
|
||||||
|
return """$result
|
||||||
|
}"""
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return """
|
||||||
|
$result,
|
||||||
|
"flags": ${arrayToJson(flags)}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): String {
|
||||||
|
return """
|
||||||
|
{
|
||||||
|
"backend": ${backend.toJson()},
|
||||||
|
"kotlinVersion": "${kotlinVersion}"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class for description of environment of benchmarks run
|
||||||
|
data class Environment(val machine: Machine, val jdk: JDKInstance): JsonSerializable {
|
||||||
|
|
||||||
|
companion object: EntityFromJsonFactory<Environment> {
|
||||||
|
override fun create(data: JsonElement): Environment {
|
||||||
|
if (data is JsonObject) {
|
||||||
|
val machine = Machine.create(getRequiredField(data, "machine"))
|
||||||
|
val jdk = JDKInstance.create(getRequiredField(data, "jdk"))
|
||||||
|
|
||||||
|
return Environment(machine, jdk)
|
||||||
|
} else {
|
||||||
|
error("Environment entity is expected to be an object. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class for description of machine used for benchmarks run.
|
||||||
|
data class Machine(val cpu: String, val os: String): JsonSerializable {
|
||||||
|
companion object: EntityFromJsonFactory<Machine> {
|
||||||
|
override fun create(data: JsonElement): Machine {
|
||||||
|
if (data is JsonObject) {
|
||||||
|
val cpu = elementToString(getRequiredField(data, "cpu"), "cpu")
|
||||||
|
val os = elementToString(getRequiredField(data, "os"), "os")
|
||||||
|
|
||||||
|
return Machine(cpu, os)
|
||||||
|
} else {
|
||||||
|
error("Machine entity is expected to be an object. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): String {
|
||||||
|
return """
|
||||||
|
{
|
||||||
|
"cpu": "$cpu",
|
||||||
|
"os": "$os"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class for description of jdk used for benchmarks run.
|
||||||
|
data class JDKInstance(val version: String, val vendor: String): JsonSerializable {
|
||||||
|
companion object: EntityFromJsonFactory<JDKInstance> {
|
||||||
|
override fun create(data: JsonElement): JDKInstance {
|
||||||
|
if (data is JsonObject) {
|
||||||
|
val version = elementToString(getRequiredField(data, "version"), "version")
|
||||||
|
val vendor = elementToString(getRequiredField(data, "vendor"), "vendor")
|
||||||
|
|
||||||
|
return JDKInstance(version, vendor)
|
||||||
|
} else {
|
||||||
|
error("JDK entity is expected to be an object. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): String {
|
||||||
|
return """
|
||||||
|
{
|
||||||
|
"version": "$version",
|
||||||
|
"vendor": "$vendor"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): String {
|
||||||
|
return """
|
||||||
|
{
|
||||||
|
"machine": ${machine.toJson()},
|
||||||
|
"jdk": ${jdk.toJson()}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BenchmarkResult(val name: String, val status: Status,
|
||||||
|
val score: Double, val runtimeInUs: Double,
|
||||||
|
val repeat: Int, val warmup: Int): JsonSerializable {
|
||||||
|
|
||||||
|
companion object: EntityFromJsonFactory<BenchmarkResult> {
|
||||||
|
|
||||||
|
override fun create(data: JsonElement): BenchmarkResult {
|
||||||
|
if (data is JsonObject) {
|
||||||
|
val name = elementToString(getRequiredField(data, "name"), "name")
|
||||||
|
val statusElement = getRequiredField(data, "status")
|
||||||
|
if (statusElement is JsonLiteral) {
|
||||||
|
val status = statusFromString(statusElement.unquoted())
|
||||||
|
?: error("Status should be PASSED or FAILED")
|
||||||
|
val score = elementToDouble(getRequiredField(data, "score"), "score")
|
||||||
|
val runtimeInUs = elementToDouble(getRequiredField(data, "runtimeInUs"), "runtimeInUs")
|
||||||
|
val repeat = elementToInt(getRequiredField(data, "repeat"), "repeat")
|
||||||
|
val warmup = elementToInt(getRequiredField(data, "warmup"), "warmup")
|
||||||
|
|
||||||
|
return BenchmarkResult(name, status, score, runtimeInUs, repeat, warmup)
|
||||||
|
} else {
|
||||||
|
error("Status should be string literal.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Benchmark entity is expected to be an object. Please, check origin files.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun statusFromString(s: String): Status? = Status.values().find { it.value == s }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Status(val value: String) {
|
||||||
|
PASSED("PASSED"),
|
||||||
|
FAILED("FAILED")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toJson(): String {
|
||||||
|
return """
|
||||||
|
{
|
||||||
|
"name": "$name",
|
||||||
|
"status": "${status.value}",
|
||||||
|
"score": ${score},
|
||||||
|
"runtimeInUs": ${runtimeInUs},
|
||||||
|
"repeat": ${repeat},
|
||||||
|
"warmup": ${warmup}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.report.json
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing single JSON element.
|
||||||
|
* Can be [JsonPrimitive], [JsonArray] or [JsonObject].
|
||||||
|
*
|
||||||
|
* [JsonElement.toString] properly prints JSON tree as valid JSON, taking into
|
||||||
|
* account quoted values and primitives
|
||||||
|
*/
|
||||||
|
sealed class JsonElement {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to get current element as [JsonPrimitive]
|
||||||
|
* @throws JsonElementTypeMismatchException is current element is not a [JsonPrimitive]
|
||||||
|
*/
|
||||||
|
open val primitive: JsonPrimitive
|
||||||
|
get() = error("JsonLiteral")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to get current element as [JsonObject]
|
||||||
|
* @throws JsonElementTypeMismatchException is current element is not a [JsonObject]
|
||||||
|
*/
|
||||||
|
open val jsonObject: JsonObject
|
||||||
|
get() = error("JsonObject")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to get current element as [JsonArray]
|
||||||
|
* @throws JsonElementTypeMismatchException is current element is not a [JsonArray]
|
||||||
|
*/
|
||||||
|
open val jsonArray: JsonArray
|
||||||
|
get() = error("JsonArray")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to get current element as [JsonNull]
|
||||||
|
* @throws JsonElementTypeMismatchException is current element is not a [JsonNull]
|
||||||
|
*/
|
||||||
|
open val jsonNull: JsonNull
|
||||||
|
get() = error("JsonPrimitive")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether current element is [JsonNull]
|
||||||
|
*/
|
||||||
|
val isNull: Boolean
|
||||||
|
get() = this === JsonNull
|
||||||
|
|
||||||
|
private fun error(element: String): Nothing =
|
||||||
|
throw JsonElementTypeMismatchException(this::class.toString(), element)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing JSON primitive value. Can be either [JsonLiteral] or [JsonNull].
|
||||||
|
*/
|
||||||
|
sealed class JsonPrimitive : JsonElement() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content of given element without quotes. For [JsonNull] this methods returns `"null"`
|
||||||
|
*/
|
||||||
|
abstract val content: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content of the given element without quotes or `null` if current element is [JsonNull]
|
||||||
|
*/
|
||||||
|
abstract val contentOrNull: String?
|
||||||
|
|
||||||
|
@Suppress("LeakingThis")
|
||||||
|
final override val primitive: JsonPrimitive = this
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as int
|
||||||
|
* @throws NumberFormatException if current element is not a valid representation of number
|
||||||
|
*/
|
||||||
|
val int: Int get() = content.toInt()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as int or `null` if current element is not a valid representation of number
|
||||||
|
**/
|
||||||
|
val intOrNull: Int? get() = content.toIntOrNull()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as long
|
||||||
|
* @throws NumberFormatException if current element is not a valid representation of number
|
||||||
|
*/
|
||||||
|
val long: Long get() = content.toLong()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as long or `null` if current element is not a valid representation of number
|
||||||
|
*/
|
||||||
|
val longOrNull: Long? get() = content.toLongOrNull()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as double
|
||||||
|
* @throws NumberFormatException if current element is not a valid representation of number
|
||||||
|
*/
|
||||||
|
val double: Double get() = content.toDouble()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as double or `null` if current element is not a valid representation of number
|
||||||
|
*/
|
||||||
|
val doubleOrNull: Double? get() = content.toDoubleOrNull()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as float
|
||||||
|
* @throws NumberFormatException if current element is not a valid representation of number
|
||||||
|
*/
|
||||||
|
val float: Float get() = content.toFloat()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as float or `null` if current element is not a valid representation of number
|
||||||
|
*/
|
||||||
|
val floatOrNull: Float? get() = content.toFloatOrNull()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as boolean
|
||||||
|
* @throws IllegalStateException if current element doesn't represent boolean
|
||||||
|
*/
|
||||||
|
val boolean: Boolean get() = content.toBooleanStrict()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns content of current element as boolean or `null` if current element is not a valid representation of boolean
|
||||||
|
*/
|
||||||
|
val booleanOrNull: Boolean? get() = content.toBooleanStrictOrNull()
|
||||||
|
|
||||||
|
override fun toString() = content
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing JSON literals: numbers, booleans and string.
|
||||||
|
* Strings are always quoted.
|
||||||
|
*/
|
||||||
|
data class JsonLiteral internal constructor(
|
||||||
|
private val body: Any,
|
||||||
|
private val isString: Boolean
|
||||||
|
) : JsonPrimitive() {
|
||||||
|
|
||||||
|
override val content = body.toString()
|
||||||
|
override val contentOrNull: String = content
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates number literal
|
||||||
|
*/
|
||||||
|
constructor(number: Number) : this(number, false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates boolean literal
|
||||||
|
*/
|
||||||
|
constructor(boolean: Boolean) : this(boolean, false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates quoted string literal
|
||||||
|
*/
|
||||||
|
constructor(string: String) : this(string, true)
|
||||||
|
|
||||||
|
override fun toString() =
|
||||||
|
if (isString) buildString { printQuoted(content) }
|
||||||
|
else content
|
||||||
|
|
||||||
|
fun unquoted() = content
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing JSON `null` value
|
||||||
|
*/
|
||||||
|
object JsonNull : JsonPrimitive() {
|
||||||
|
override val jsonNull: JsonNull = this
|
||||||
|
override val content: String = "null"
|
||||||
|
override val contentOrNull: String? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing JSON object, consisting of name-value pairs, where value is arbitrary [JsonElement]
|
||||||
|
*/
|
||||||
|
data class JsonObject(val content: Map<String, JsonElement>) : JsonElement(), Map<String, JsonElement> by content {
|
||||||
|
|
||||||
|
override val jsonObject: JsonObject = this
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonElement] associated with given [key]
|
||||||
|
* @throws NoSuchElementException if element is not present
|
||||||
|
*/
|
||||||
|
override fun get(key: String): JsonElement = content[key] ?: throw NoSuchElementException("Element $key is missing")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonElement] associated with given [key] or `null` if element is not present
|
||||||
|
*/
|
||||||
|
fun getOrNull(key: String): JsonElement? = content[key]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonPrimitive] associated with given [key]
|
||||||
|
*
|
||||||
|
* @throws NoSuchElementException if element is not present
|
||||||
|
* @throws JsonElementTypeMismatchException if element is present, but has invalid type
|
||||||
|
*/
|
||||||
|
fun getPrimitive(key: String): JsonPrimitive = get(key) as? JsonPrimitive
|
||||||
|
?: unexpectedJson(key, "JsonPrimitive")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonObject] associated with given [key]
|
||||||
|
*
|
||||||
|
* @throws NoSuchElementException if element is not present
|
||||||
|
* @throws JsonElementTypeMismatchException if element is present, but has invalid type
|
||||||
|
*/
|
||||||
|
fun getObject(key: String): JsonObject = get(key) as? JsonObject
|
||||||
|
?: unexpectedJson(key, "JsonObject")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonArray] associated with given [key]
|
||||||
|
*
|
||||||
|
* @throws NoSuchElementException if element is not present
|
||||||
|
* @throws JsonElementTypeMismatchException if element is present, but has invalid type
|
||||||
|
*/
|
||||||
|
fun getArray(key: String): JsonArray = get(key) as? JsonArray
|
||||||
|
?: unexpectedJson(key, "JsonArray")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonPrimitive] associated with given [key] or `null` if element
|
||||||
|
* is not present or has different type
|
||||||
|
*/
|
||||||
|
fun getPrimitiveOrNull(key: String): JsonPrimitive? = content[key] as? JsonPrimitive
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonObject] associated with given [key] or `null` if element
|
||||||
|
* is not present or has different type
|
||||||
|
*/
|
||||||
|
fun getObjectOrNull(key: String): JsonObject? = content[key] as? JsonObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [JsonArray] associated with given [key] or `null` if element
|
||||||
|
* is not present or has different type
|
||||||
|
*/
|
||||||
|
fun getArrayOrNull(key: String): JsonArray? = content[key] as? JsonArray
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [J] associated with given [key]
|
||||||
|
*
|
||||||
|
* @throws NoSuchElementException if element is not present
|
||||||
|
* @throws JsonElementTypeMismatchException if element is present, but has invalid type
|
||||||
|
*/
|
||||||
|
inline fun <reified J : JsonElement> getAs(key: String): J = get(key) as? J
|
||||||
|
?: unexpectedJson(key, J::class.toString())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [J] associated with given [key] or `null` if element
|
||||||
|
* is not present or has different type
|
||||||
|
*/
|
||||||
|
inline fun <reified J : JsonElement> lookup(key: String): J? = content[key] as? J
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return content.entries.joinToString(
|
||||||
|
prefix = "{",
|
||||||
|
postfix = "}",
|
||||||
|
transform = {(k, v) -> """"$k": $v"""}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class JsonArray(val content: List<JsonElement>) : JsonElement(), List<JsonElement> by content {
|
||||||
|
|
||||||
|
override val jsonArray: JsonArray = this
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [JsonPrimitive]
|
||||||
|
* @throws JsonElementTypeMismatchException if element has invalid type
|
||||||
|
*/
|
||||||
|
fun getPrimitive(index: Int) = content[index] as? JsonPrimitive
|
||||||
|
?: unexpectedJson("at $index", "JsonPrimitive")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [JsonObject]
|
||||||
|
* @throws JsonElementTypeMismatchException if element has invalid type
|
||||||
|
*/
|
||||||
|
fun getObject(index: Int) = content[index] as? JsonObject
|
||||||
|
?: unexpectedJson("at $index", "JsonObject")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [JsonArray]
|
||||||
|
* @throws JsonElementTypeMismatchException if element has invalid type
|
||||||
|
*/
|
||||||
|
fun getArray(index: Int) = content[index] as? JsonArray
|
||||||
|
?: unexpectedJson("at $index", "JsonArray")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [JsonPrimitive] or `null` if element is missing or has different type
|
||||||
|
*/
|
||||||
|
fun getPrimitiveOrNull(index: Int) = content.getOrNull(index) as? JsonPrimitive
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [JsonObject] or `null` if element is missing or has different type
|
||||||
|
*/
|
||||||
|
fun getObjectOrNull(index: Int) = content.getOrNull(index) as? JsonObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [JsonArray] or `null` if element is missing or has different type
|
||||||
|
*/
|
||||||
|
fun getArrayOrNull(index: Int) = content.getOrNull(index) as? JsonArray
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [J]
|
||||||
|
* @throws JsonElementTypeMismatchException if element has invalid type
|
||||||
|
*/
|
||||||
|
inline fun <reified J : JsonElement> getAs(index: Int): J = content[index] as? J
|
||||||
|
?: unexpectedJson("at $index", J::class.toString())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [index]-th element of an array as [J] or `null` if element is missing or has different type
|
||||||
|
*/
|
||||||
|
inline fun <reified J : JsonElement> getAsOrNull(index: Int): J? = content.getOrNull(index) as? J
|
||||||
|
|
||||||
|
override fun toString() = content.joinToString(prefix = "[", postfix = "]")
|
||||||
|
}
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
internal fun unexpectedJson(key: String, expected: String): Nothing =
|
||||||
|
throw JsonElementTypeMismatchException(key, expected)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.report.json
|
||||||
|
|
||||||
|
class JsonInvalidValueInStrictModeException(value: Any, valueDescription: String) : Exception(
|
||||||
|
"$value is not a valid $valueDescription as per JSON spec.\n" +
|
||||||
|
"You can disable strict mode to serialize such values"
|
||||||
|
) {
|
||||||
|
constructor(floatValue: Float) : this(floatValue, "float")
|
||||||
|
constructor(doubleValue: Double) : this(doubleValue, "double")
|
||||||
|
}
|
||||||
|
|
||||||
|
class JsonUnknownKeyException(key: String) : Exception(
|
||||||
|
"Strict JSON encountered unknown key: $key\n" +
|
||||||
|
"You can disable strict mode to skip unknown keys"
|
||||||
|
)
|
||||||
|
|
||||||
|
class JsonParsingException(position: Int, message: String) : Exception("Invalid JSON at $position: $message")
|
||||||
|
|
||||||
|
class JsonElementTypeMismatchException(key: String, expected: String) : Exception("Element $key is not a $expected")
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.report.json
|
||||||
|
|
||||||
|
import org.jetbrains.report.json.EscapeCharMappings.ESC2C
|
||||||
|
// special strings
|
||||||
|
internal const val NULL = "null"
|
||||||
|
|
||||||
|
// special chars
|
||||||
|
internal const val COMMA = ','
|
||||||
|
internal const val COLON = ':'
|
||||||
|
internal const val BEGIN_OBJ = '{'
|
||||||
|
internal const val END_OBJ = '}'
|
||||||
|
internal const val BEGIN_LIST = '['
|
||||||
|
internal const val END_LIST = ']'
|
||||||
|
internal const val STRING = '"'
|
||||||
|
internal const val STRING_ESC = '\\'
|
||||||
|
internal const val INVALID = 0.toChar()
|
||||||
|
internal const val UNICODE_ESC = 'u'
|
||||||
|
// token classes
|
||||||
|
internal const val TC_OTHER: Byte = 0
|
||||||
|
internal const val TC_STRING: Byte = 1
|
||||||
|
internal const val TC_STRING_ESC: Byte = 2
|
||||||
|
internal const val TC_WS: Byte = 3
|
||||||
|
internal const val TC_COMMA: Byte = 4
|
||||||
|
internal const val TC_COLON: Byte = 5
|
||||||
|
internal const val TC_BEGIN_OBJ: Byte = 6
|
||||||
|
internal const val TC_END_OBJ: Byte = 7
|
||||||
|
internal const val TC_BEGIN_LIST: Byte = 8
|
||||||
|
internal const val TC_END_LIST: Byte = 9
|
||||||
|
internal const val TC_NULL: Byte = 10
|
||||||
|
internal const val TC_INVALID: Byte = 11
|
||||||
|
internal const val TC_EOF: Byte = 12
|
||||||
|
// mapping from chars to token classes
|
||||||
|
private const val CTC_MAX = 0x7e
|
||||||
|
// mapping from escape chars real chars
|
||||||
|
private const val C2ESC_MAX = 0x5d
|
||||||
|
private const val ESC2C_MAX = 0x75
|
||||||
|
|
||||||
|
internal val C2TC = ByteArray(CTC_MAX).apply {
|
||||||
|
for (i in 0..0x20)
|
||||||
|
initC2TC(i, TC_INVALID)
|
||||||
|
initC2TC(0x09, TC_WS)
|
||||||
|
initC2TC(0x0a, TC_WS)
|
||||||
|
initC2TC(0x0d, TC_WS)
|
||||||
|
initC2TC(0x20, TC_WS)
|
||||||
|
initC2TC(COMMA, TC_COMMA)
|
||||||
|
initC2TC(COLON, TC_COLON)
|
||||||
|
initC2TC(BEGIN_OBJ, TC_BEGIN_OBJ)
|
||||||
|
initC2TC(END_OBJ, TC_END_OBJ)
|
||||||
|
initC2TC(BEGIN_LIST, TC_BEGIN_LIST)
|
||||||
|
initC2TC(END_LIST, TC_END_LIST)
|
||||||
|
initC2TC(STRING, TC_STRING)
|
||||||
|
initC2TC(STRING_ESC, TC_STRING_ESC)
|
||||||
|
}
|
||||||
|
// object instead of @SharedImmutable because there is mutual initialization in [initC2ESC]
|
||||||
|
internal object EscapeCharMappings {
|
||||||
|
internal val ESC2C = CharArray(ESC2C_MAX)
|
||||||
|
internal val C2ESC = CharArray(C2ESC_MAX).apply {
|
||||||
|
for (i in 0x00..0x1f)
|
||||||
|
initC2ESC(i, UNICODE_ESC)
|
||||||
|
initC2ESC(0x08, 'b')
|
||||||
|
initC2ESC(0x09, 't')
|
||||||
|
initC2ESC(0x0a, 'n')
|
||||||
|
initC2ESC(0x0c, 'f')
|
||||||
|
initC2ESC(0x0d, 'r')
|
||||||
|
initC2ESC('/', '/')
|
||||||
|
initC2ESC(STRING, STRING)
|
||||||
|
initC2ESC(STRING_ESC, STRING_ESC)
|
||||||
|
}
|
||||||
|
private fun CharArray.initC2ESC(c: Int, esc: Char) {
|
||||||
|
this[c] = esc
|
||||||
|
if (esc != UNICODE_ESC) ESC2C[esc.toInt()] = c.toChar()
|
||||||
|
}
|
||||||
|
private fun CharArray.initC2ESC(c: Char, esc: Char) = initC2ESC(c.toInt(), esc)
|
||||||
|
}
|
||||||
|
private fun ByteArray.initC2TC(c: Int, cl: Byte) {
|
||||||
|
this[c] = cl
|
||||||
|
}
|
||||||
|
private fun ByteArray.initC2TC(c: Char, cl: Byte) {
|
||||||
|
initC2TC(c.toInt(), cl)
|
||||||
|
}
|
||||||
|
internal fun charToTokenClass(c: Char) = if (c.toInt() < CTC_MAX) C2TC[c.toInt()] else TC_OTHER
|
||||||
|
internal fun escapeToChar(c: Int): Char = if (c < ESC2C_MAX) ESC2C[c] else INVALID
|
||||||
|
// JSON low level parser
|
||||||
|
internal class Parser(val source: String) {
|
||||||
|
var curPos: Int = 0 // position in source
|
||||||
|
private set
|
||||||
|
// updated by nextToken
|
||||||
|
var tokenPos: Int = 0
|
||||||
|
private set
|
||||||
|
var tc: Byte = TC_EOF
|
||||||
|
private set
|
||||||
|
// update by nextString/nextLiteral
|
||||||
|
private var offset = -1 // when offset >= 0 string is in source, otherwise in buf
|
||||||
|
private var length = 0 // length of string
|
||||||
|
private var buf = CharArray(16) // only used for strings with escapes
|
||||||
|
init {
|
||||||
|
nextToken()
|
||||||
|
}
|
||||||
|
internal inline fun requireTc(expected: Byte, lazyErrorMsg: () -> String) {
|
||||||
|
if (tc != expected)
|
||||||
|
fail(tokenPos, lazyErrorMsg())
|
||||||
|
}
|
||||||
|
val canBeginValue: Boolean
|
||||||
|
get() = when (tc) {
|
||||||
|
TC_BEGIN_LIST, TC_BEGIN_OBJ, TC_OTHER, TC_STRING, TC_NULL -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
fun takeStr(): String {
|
||||||
|
if (tc != TC_OTHER && tc != TC_STRING) fail(tokenPos, "Expected string or non-null literal")
|
||||||
|
val prevStr = if (offset < 0)
|
||||||
|
String(buf, 0, length) else
|
||||||
|
source.substring(offset, offset + length)
|
||||||
|
nextToken()
|
||||||
|
return prevStr
|
||||||
|
}
|
||||||
|
private fun append(ch: Char) {
|
||||||
|
if (length >= buf.size) buf = buf.copyOf(2 * buf.size)
|
||||||
|
buf[length++] = ch
|
||||||
|
}
|
||||||
|
// initializes buf usage upon the first encountered escaped char
|
||||||
|
private fun appendRange(source: String, fromIndex: Int, toIndex: Int) {
|
||||||
|
val addLen = toIndex - fromIndex
|
||||||
|
val oldLen = length
|
||||||
|
val newLen = oldLen + addLen
|
||||||
|
if (newLen > buf.size) buf = buf.copyOf(newLen.coerceAtLeast(2 * buf.size))
|
||||||
|
for (i in 0 until addLen) buf[oldLen + i] = source[fromIndex + i]
|
||||||
|
length += addLen
|
||||||
|
}
|
||||||
|
fun nextToken() {
|
||||||
|
val source = source
|
||||||
|
var curPos = curPos
|
||||||
|
val maxLen = source.length
|
||||||
|
while (true) {
|
||||||
|
if (curPos >= maxLen) {
|
||||||
|
tokenPos = curPos
|
||||||
|
tc = TC_EOF
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val ch = source[curPos]
|
||||||
|
val tc = charToTokenClass(ch)
|
||||||
|
when (tc) {
|
||||||
|
TC_WS -> curPos++ // skip whitespace
|
||||||
|
TC_OTHER -> {
|
||||||
|
nextLiteral(source, curPos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
TC_STRING -> {
|
||||||
|
nextString(source, curPos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
this.tokenPos = curPos
|
||||||
|
this.tc = tc
|
||||||
|
this.curPos = curPos + 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun nextLiteral(source: String, startPos: Int) {
|
||||||
|
tokenPos = startPos
|
||||||
|
offset = startPos
|
||||||
|
var curPos = startPos
|
||||||
|
val maxLen = source.length
|
||||||
|
while (true) {
|
||||||
|
curPos++
|
||||||
|
if (curPos >= maxLen || charToTokenClass(source[curPos]) != TC_OTHER) break
|
||||||
|
}
|
||||||
|
this.curPos = curPos
|
||||||
|
length = curPos - offset
|
||||||
|
tc = if (rangeEquals(source, offset, length, NULL)) TC_NULL else TC_OTHER
|
||||||
|
}
|
||||||
|
private fun nextString(source: String, startPos: Int) {
|
||||||
|
tokenPos = startPos
|
||||||
|
length = 0 // in buffer
|
||||||
|
var curPos = startPos + 1
|
||||||
|
var lastPos = curPos
|
||||||
|
val maxLen = source.length
|
||||||
|
parse@ while (true) {
|
||||||
|
if (curPos >= maxLen) fail(curPos, "Unexpected end in string")
|
||||||
|
if (source[curPos] == STRING) {
|
||||||
|
break@parse
|
||||||
|
} else if (source[curPos] == STRING_ESC) {
|
||||||
|
appendRange(source, lastPos, curPos)
|
||||||
|
val newPos = appendEsc(source, curPos + 1)
|
||||||
|
curPos = newPos
|
||||||
|
lastPos = newPos
|
||||||
|
} else {
|
||||||
|
curPos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastPos == startPos + 1) {
|
||||||
|
// there was no escaped chars
|
||||||
|
this.offset = lastPos
|
||||||
|
this.length = curPos - lastPos
|
||||||
|
} else {
|
||||||
|
// some escaped chars were there
|
||||||
|
appendRange(source, lastPos, curPos)
|
||||||
|
this.offset = -1
|
||||||
|
}
|
||||||
|
this.curPos = curPos + 1
|
||||||
|
tc = TC_STRING
|
||||||
|
}
|
||||||
|
private fun appendEsc(source: String, startPos: Int): Int {
|
||||||
|
var curPos = startPos
|
||||||
|
require(curPos < source.length, curPos) { "Unexpected end after escape char" }
|
||||||
|
val curChar = source[curPos++]
|
||||||
|
if (curChar == UNICODE_ESC) {
|
||||||
|
curPos = appendHex(source, curPos)
|
||||||
|
} else {
|
||||||
|
val c = escapeToChar(curChar.toInt())
|
||||||
|
require(c != INVALID, curPos) { "Invalid escaped char '$curChar'" }
|
||||||
|
append(c)
|
||||||
|
}
|
||||||
|
return curPos
|
||||||
|
}
|
||||||
|
private fun appendHex(source: String, startPos: Int): Int {
|
||||||
|
var curPos = startPos
|
||||||
|
append(
|
||||||
|
((fromHexChar(source, curPos++) shl 12) +
|
||||||
|
(fromHexChar(source, curPos++) shl 8) +
|
||||||
|
(fromHexChar(source, curPos++) shl 4) +
|
||||||
|
fromHexChar(source, curPos++)).toChar()
|
||||||
|
)
|
||||||
|
return curPos
|
||||||
|
}
|
||||||
|
fun skipElement() {
|
||||||
|
if (tc != TC_BEGIN_OBJ && tc != TC_BEGIN_LIST) {
|
||||||
|
nextToken()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val tokenStack = mutableListOf<Byte>()
|
||||||
|
do {
|
||||||
|
when (tc) {
|
||||||
|
TC_BEGIN_LIST, TC_BEGIN_OBJ -> tokenStack.add(tc)
|
||||||
|
TC_END_LIST -> {
|
||||||
|
if (tokenStack.last() != TC_BEGIN_LIST) throw JsonParsingException(curPos, "found ] instead of }")
|
||||||
|
tokenStack.removeAt(tokenStack.size - 1)
|
||||||
|
}
|
||||||
|
TC_END_OBJ -> {
|
||||||
|
if (tokenStack.last() != TC_BEGIN_OBJ) throw JsonParsingException(curPos, "found } instead of ]")
|
||||||
|
tokenStack.removeAt(tokenStack.size - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextToken()
|
||||||
|
} while (tokenStack.isNotEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Utility functions
|
||||||
|
private fun fromHexChar(source: String, curPos: Int): Int {
|
||||||
|
require(curPos < source.length, curPos) { "Unexpected end in unicode escape" }
|
||||||
|
val curChar = source[curPos]
|
||||||
|
return when (curChar) {
|
||||||
|
in '0'..'9' -> curChar.toInt() - '0'.toInt()
|
||||||
|
in 'a'..'f' -> curChar.toInt() - 'a'.toInt() + 10
|
||||||
|
in 'A'..'F' -> curChar.toInt() - 'A'.toInt() + 10
|
||||||
|
else -> fail(curPos, "Invalid toHexChar char '$curChar' in unicode escape")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun rangeEquals(source: String, start: Int, length: Int, str: String): Boolean {
|
||||||
|
val n = str.length
|
||||||
|
if (length != n) return false
|
||||||
|
for (i in 0 until n) if (source[start + i] != str[i]) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
internal inline fun require(condition: Boolean, pos: Int, msg: () -> String) {
|
||||||
|
if (!condition)
|
||||||
|
fail(pos, msg())
|
||||||
|
}
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
internal inline fun fail(pos: Int, msg: String): Nothing {
|
||||||
|
throw JsonParsingException(pos, msg)
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// A bit changed part of kotlinx.serialization plugin
|
||||||
|
package org.jetbrains.report.json
|
||||||
|
|
||||||
|
class JsonTreeParser internal constructor(private val p: Parser) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun parse(input: String): JsonElement = JsonTreeParser(input).readFully()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(input: String) : this(Parser(input))
|
||||||
|
|
||||||
|
private fun readObject(): JsonElement {
|
||||||
|
p.requireTc(TC_BEGIN_OBJ) { "Expected start of object" }
|
||||||
|
p.nextToken()
|
||||||
|
val result: MutableMap<String, JsonElement> = hashMapOf()
|
||||||
|
while (true) {
|
||||||
|
if (p.tc == TC_COMMA) p.nextToken()
|
||||||
|
if (!p.canBeginValue) break
|
||||||
|
val key = p.takeStr()
|
||||||
|
p.requireTc(TC_COLON) { "Expected ':'" }
|
||||||
|
p.nextToken()
|
||||||
|
val elem = read()
|
||||||
|
result[key] = elem
|
||||||
|
}
|
||||||
|
p.requireTc(TC_END_OBJ) { "Expected end of object" }
|
||||||
|
p.nextToken()
|
||||||
|
return JsonObject(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readValue(isString: Boolean): JsonElement {
|
||||||
|
val str = p.takeStr()
|
||||||
|
return JsonLiteral(str, isString)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readArray(): JsonElement {
|
||||||
|
p.requireTc(TC_BEGIN_LIST) { "Expected start of array" }
|
||||||
|
p.nextToken()
|
||||||
|
val result: MutableList<JsonElement> = arrayListOf()
|
||||||
|
while (true) {
|
||||||
|
if (p.tc == TC_COMMA) p.nextToken()
|
||||||
|
if (!p.canBeginValue) break
|
||||||
|
val elem = read()
|
||||||
|
result.add(elem)
|
||||||
|
}
|
||||||
|
p.requireTc(TC_END_LIST) { "Expected end of array" }
|
||||||
|
p.nextToken()
|
||||||
|
return JsonArray(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun read(): JsonElement {
|
||||||
|
if (!p.canBeginValue) fail(p.curPos, "Can't begin reading value from here")
|
||||||
|
val tc = p.tc
|
||||||
|
return when (tc) {
|
||||||
|
TC_NULL -> JsonNull.also { p.nextToken() }
|
||||||
|
TC_STRING -> readValue(isString = true)
|
||||||
|
TC_OTHER -> readValue(isString = false)
|
||||||
|
TC_BEGIN_OBJ -> readObject()
|
||||||
|
TC_BEGIN_LIST -> readArray()
|
||||||
|
else -> fail(p.curPos, "Can't begin reading element")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readFully(): JsonElement {
|
||||||
|
val r = read()
|
||||||
|
p.requireTc(TC_EOF) { "Input wasn't consumed fully" }
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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 org.jetbrains.report.json
|
||||||
|
|
||||||
|
private fun toHexChar(i: Int) : Char {
|
||||||
|
val d = i and 0xf
|
||||||
|
return if (d < 10) (d + '0'.toInt()).toChar()
|
||||||
|
else (d - 10 + 'a'.toInt()).toChar()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ESCAPE_CHARS: Array<String?> = arrayOfNulls<String>(128).apply {
|
||||||
|
for (c in 0..0x1f) {
|
||||||
|
val c1 = toHexChar(c shr 12)
|
||||||
|
val c2 = toHexChar(c shr 8)
|
||||||
|
val c3 = toHexChar(c shr 4)
|
||||||
|
val c4 = toHexChar(c)
|
||||||
|
this[c] = "\\u$c1$c2$c3$c4"
|
||||||
|
}
|
||||||
|
this['"'.toInt()] = "\\\""
|
||||||
|
this['\\'.toInt()] = "\\\\"
|
||||||
|
this['\t'.toInt()] = "\\t"
|
||||||
|
this['\b'.toInt()] = "\\b"
|
||||||
|
this['\n'.toInt()] = "\\n"
|
||||||
|
this['\r'.toInt()] = "\\r"
|
||||||
|
this[0x0c] = "\\f"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun StringBuilder.printQuoted(value: String) {
|
||||||
|
append(STRING)
|
||||||
|
var lastPos = 0
|
||||||
|
val length = value.length
|
||||||
|
for (i in 0 until length) {
|
||||||
|
val c = value[i].toInt()
|
||||||
|
// Do not replace this constant with C2ESC_MAX (which is smaller than ESCAPE_CHARS size),
|
||||||
|
// otherwise JIT won't eliminate range check and won't vectorize this loop
|
||||||
|
if (c >= ESCAPE_CHARS.size) continue // no need to escape
|
||||||
|
val esc = ESCAPE_CHARS[c] ?: continue
|
||||||
|
append(value, lastPos, i) // flush prev
|
||||||
|
append(esc)
|
||||||
|
lastPos = i + 1
|
||||||
|
}
|
||||||
|
append(value, lastPos, length)
|
||||||
|
append(STRING)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if the contents of this string is equal to the word "true", ignoring case, `false` if content equals "false",
|
||||||
|
* and throws [IllegalStateException] otherwise.
|
||||||
|
*/
|
||||||
|
fun String.toBooleanStrict(): Boolean = toBooleanStrictOrNull() ?: throw IllegalStateException("$this does not represent a Boolean")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if the contents of this string is equal to the word "true", ignoring case, `false` if content equals "false",
|
||||||
|
* and returns `null` otherwise.
|
||||||
|
*/
|
||||||
|
fun String.toBooleanStrictOrNull(): Boolean? = when {
|
||||||
|
this.equals("true", ignoreCase = true) -> true
|
||||||
|
this.equals("false", ignoreCase = true) -> false
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user