From d8c1e85025789aff2b3c9ef91aa9a75b58b7d6e8 Mon Sep 17 00:00:00 2001 From: LepilkinaElena Date: Tue, 19 Mar 2019 17:25:48 +0300 Subject: [PATCH] Added register task and some fixes for TeamCity (#2785) --- performance/build.gradle | 14 ++ .../buildSrc/src/main/kotlin/BuildRegister.kt | 137 ++++++++++++++++++ .../src/main/kotlin/RegressionsReporter.kt | 27 +--- performance/buildSrc/src/main/kotlin/Utils.kt | 26 ++++ .../ui/src/main/kotlin/main.kt | 7 +- 5 files changed, 190 insertions(+), 21 deletions(-) create mode 100644 performance/buildSrc/src/main/kotlin/BuildRegister.kt create mode 100644 performance/buildSrc/src/main/kotlin/Utils.kt diff --git a/performance/build.gradle b/performance/build.gradle index 9a792ab15c9..ec012d3a086 100644 --- a/performance/build.gradle +++ b/performance/build.gradle @@ -56,6 +56,7 @@ task slackReport(type: RegressionsReporter) { defaultBranch = project.findProperty('kotlin.native.default.branch') ?: "master" def target = System.getProperty("os.name") summaryFile = "${targetsResults}/${target}.txt" + bundleBuild = project.findProperty('kotlin.bundleBuild') == null ? false : true } } @@ -80,6 +81,19 @@ private def uploadBenchmarkResultToBintray(String fileName) { } } +task registerBuild(type: BuildRegister) { + // Get bundle size. + bundleSize = null + if (project.findProperty('kotlin.bundleBuild') != null) { + def dist = findProperty('org.jetbrains.kotlin.native.home') ?: 'dist' + dist = (new File(dist)).isAbsolute() ? dist : "${project.getProjectDir()}/$dist" + bundleSize = (new File(dist)).directorySize() + } + currentBenchmarksReportFile = "${buildDir.absolutePath}/${nativeJson}" + analyzer = MPPTools.findFile("${analyzerTool}${MPPTools.getNativeProgramExtension()}", + "${rootBuildDirectory}/${analyzerToolDirectory}") +} + def mergeReports(String fileName) { def reports = [] subprojects.each { diff --git a/performance/buildSrc/src/main/kotlin/BuildRegister.kt b/performance/buildSrc/src/main/kotlin/BuildRegister.kt new file mode 100644 index 00000000000..82585ffb577 --- /dev/null +++ b/performance/buildSrc/src/main/kotlin/BuildRegister.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2010-2019 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.Action +import org.gradle.api.DefaultTask +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +import com.ullink.slack.simpleslackapi.impl.SlackSessionFactory + +import org.jetbrains.report.json.* + +import java.io.FileInputStream +import java.io.IOException +import java.io.File +import java.io.OutputStreamWriter +import java.io.BufferedReader +import java.io.InputStreamReader +import java.util.concurrent.TimeUnit +import java.net.HttpURLConnection +import java.net.URL +import java.util.Base64 +import java.util.Properties + +/** + * Task to produce regressions report and send it to slack. Requires a report with current benchmarks result + * and path to analyzer tool + * + * @property currentBenchmarksReportFile path to file with becnhmarks result + * @property analyzer path to analyzer tool + * @property bundleSize size of build + */ +open class BuildRegister : DefaultTask() { + @Input + lateinit var currentBenchmarksReportFile: String + @Input + lateinit var analyzer: String + + var bundleSize: Int? = null + + val buildInfoToken: Int = 4 + val compileTimeSamplesNumber: Int = 2 + val buildNumberTokens: Int = 3 + val performanceServer = "https://kotlin-native-perf-summary.labs.jb.gg" + + private fun sendPostRequest(url: String, body: String) : String { + val connection = URL(url).openConnection() as HttpURLConnection + return connection.apply { + setRequestProperty("Content-Type", "application/json; charset=utf-8") + requestMethod = "POST" + doOutput = true + val outputWriter = OutputStreamWriter(outputStream) + outputWriter.write(body) + outputWriter.flush() + }.let { + if (it.responseCode == 200) it.inputStream else it.errorStream + }.let { streamToRead -> + BufferedReader(InputStreamReader(streamToRead)).use { + val response = StringBuffer() + + var inputLine = it.readLine() + while (inputLine != null) { + response.append(inputLine) + inputLine = it.readLine() + } + it.close() + response.toString() + } + } + } + + @TaskAction + fun run() { + // Get TeamCity properties. + val teamcityConfig = System.getenv("TEAMCITY_BUILD_PROPERTIES_FILE") ?: + error("Can't load teamcity config!") + + val buildProperties = Properties() + buildProperties.load(FileInputStream(teamcityConfig)) + val buildId = buildProperties.getProperty("teamcity.build.id") + val bintrayUser = buildProperties.getProperty("bintray.user") + val bintrayApiKey = buildProperties.getProperty("bintray.apikey") + val teamCityUser = buildProperties.getProperty("teamcity.auth.userId") + val teamCityPassword = buildProperties.getProperty("teamcity.auth.password") + val buildNumber = buildProperties.getProperty("build.number") + + // Get summary information. + val output = arrayOf("$analyzer", "summary", "-exec-samples", "all", "-compile", "samples", + "-compile-samples", "HelloWorld,Videoplayer", "-codesize-samples", "all", "$currentBenchmarksReportFile") + .runCommand() + // Postprocess information. + val buildInfoParts = output.split(',') + if (buildInfoParts.size != buildInfoToken) { + error("Problems with getting summary information using $analyzer and $currentBenchmarksReportFile.") + } + + val (failures, executionTime, compileTime, codeSize) = buildInfoParts.map { it.trim() } + // Add legends. + val geometricMean = "Geometric Mean-" + val executionTimeInfo = "$geometricMean$executionTime" + val codeSizeInfo = "$geometricMean$codeSize" + val compileTimeSamples = compileTime.split(';') + if (compileTimeSamples.size != compileTimeSamplesNumber) { + error("Problems with getting compile time samples value. Expected at least $compileTimeSamplesNumber samples, got ${compileTimeSamples.size}") + } + val (helloWorldCompile, videoplayerCompile) = compileTimeSamples + val compileTimeInfo = "HelloWorld-$helloWorldCompile;Videoplayer-$videoplayerCompile" + val target = System.getProperty("os.name").replace("\\s".toRegex(), "") + val buildNumberParts = buildNumber.split("-") + if (buildNumberParts.size != buildNumberTokens) { + error("Wrong format of build number $buildNumber.") + } + val (_, buildType, _) = buildNumberParts + + // Send post request to register build. + val requestBody = buildString { + append("{\"buildId\":\"$buildId\",") + append("\"teamCityUser\":\"$teamCityUser\",") + append("\"teamCityPassword\":\"$teamCityPassword\",") + append("\"bintrayUser\": \"$bintrayUser\", ") + append("\"bintrayPassword\":\"$bintrayApiKey\", ") + append("\"target\": \"$target\",") + append("\"buildType\": \"$buildType\",") + append("\"failuresNumber\": $failures,") + append("\"executionTime\": \"$executionTimeInfo\",") + append("\"compileTime\": \"$compileTimeInfo\",") + append("\"codeSize\": \"$codeSizeInfo\",") + append("\"bundleSize\": ${bundleSize?.let {"\"$bundleSize\""} ?: bundleSize}}") + } + println(sendPostRequest("$performanceServer/register", requestBody)) + } +} \ No newline at end of file diff --git a/performance/buildSrc/src/main/kotlin/RegressionsReporter.kt b/performance/buildSrc/src/main/kotlin/RegressionsReporter.kt index 297ed211f05..4332c0af4a3 100644 --- a/performance/buildSrc/src/main/kotlin/RegressionsReporter.kt +++ b/performance/buildSrc/src/main/kotlin/RegressionsReporter.kt @@ -24,23 +24,6 @@ import java.net.URL import java.util.Base64 import java.util.Properties -// Run command line from string. -fun Array.runCommand(workingDir: File = File("."), - timeoutAmount: Long = 60, - timeoutUnit: TimeUnit = TimeUnit.SECONDS): String { - return try { - ProcessBuilder(*this) - .directory(workingDir) - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .redirectError(ProcessBuilder.Redirect.PIPE) - .start().apply { - waitFor(timeoutAmount, timeoutUnit) - }.inputStream.bufferedReader().readText() - } catch (e: IOException) { - error("Couldn't run command $this") - } -} - data class Commit(val revision: String, val developer: String, val webUrlWithDescription: String) // List of commits. @@ -78,6 +61,7 @@ class CommitsList(data: JsonElement): ConvertedFromJson { * @property htmlReport name of result html report * @property defaultBranch name of default branch * @property summaryFile name of file with short summary + * @property bundleBuild property to show if current build is full or not */ open class RegressionsReporter : DefaultTask() { @@ -114,6 +98,9 @@ open class RegressionsReporter : DefaultTask() { @Input lateinit var summaryFile: String + @Input + var bundleBuild: Boolean = false + private fun tabUrl(buildId: String, buildTypeId: String, tab: String) = "$teamCityUrl/viewLog.html?buildId=$buildId&buildTypeId=$buildTypeId&tab=$tab" @@ -239,8 +226,10 @@ open class RegressionsReporter : DefaultTask() { session.connect() if (branch == defaultBranch) { - val channel = session.findChannelByName(buildProperties.getProperty("konan-channel-name")) - session.sendMessage(channel, message) + if (bundleBuild) { + val channel = session.findChannelByName(buildProperties.getProperty("konan-channel-name")) + session.sendMessage(channel, message) + } } else { changesList.commits.filter { it.developer in slackUsers }. map { it.developer } .toSet().forEach { diff --git a/performance/buildSrc/src/main/kotlin/Utils.kt b/performance/buildSrc/src/main/kotlin/Utils.kt new file mode 100644 index 00000000000..45604c3b73d --- /dev/null +++ b/performance/buildSrc/src/main/kotlin/Utils.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2019 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 java.io.FileInputStream +import java.io.IOException +import java.io.File +import java.util.concurrent.TimeUnit + +// Run command line from string. +fun Array.runCommand(workingDir: File = File("."), + timeoutAmount: Long = 60, + timeoutUnit: TimeUnit = TimeUnit.SECONDS): String { + return try { + ProcessBuilder(*this) + .directory(workingDir) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start().apply { + waitFor(timeoutAmount, timeoutUnit) + }.inputStream.bufferedReader().readText() + } catch (e: IOException) { + error("Couldn't run command $this") + } +} \ No newline at end of file diff --git a/tools/performance-server/ui/src/main/kotlin/main.kt b/tools/performance-server/ui/src/main/kotlin/main.kt index 112a1e573d3..084c0bea4d3 100644 --- a/tools/performance-server/ui/src/main/kotlin/main.kt +++ b/tools/performance-server/ui/src/main/kotlin/main.kt @@ -82,6 +82,9 @@ fun getChartOptions(samples: Array): dynamic { val axisXObject: dynamic = object{} axisXObject["offset"] = 40 chartOptions["axisX"] = axisXObject + val axisYObject: dynamic = object{} + axisYObject["offset"] = 70 + chartOptions["axisY"] = axisYObject val legendObject: dynamic = object{} legendObject["legendNames"] = samples chartOptions["plugins"] = arrayOf(Chartist.plugins.legend(legendObject)) @@ -236,7 +239,7 @@ fun main(args: Array) { val labels = mutableListOf() val executionTime = mutableMapOf>() val compileTime = mutableMapOf>() - val codeSize = mutableMapOf>() + val codeSize = mutableMapOf>() val bundleSize = mutableListOf() builds.forEach { @@ -248,7 +251,7 @@ fun main(args: Array) { } separateValues(it.executionTime, executionTime) { value -> value.toDouble() } separateValues(it.compileTime, compileTime) { value -> value.toDouble() } - separateValues(it.codeSize, codeSize) { value -> value.toInt() } + separateValues(it.codeSize, codeSize) { value -> value.toDouble() } bundleSize.add(it.bundleSize?.toInt()) }