@@ -2,6 +2,7 @@ package kotlinx.benchmark.gradle
22
33import kotlinx.benchmark.gradle.internal.KotlinxBenchmarkPluginInternalApi
44import org.gradle.api.*
5+ import org.gradle.api.tasks.TaskProvider
56import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
67import java.io.InputStream
78import java.util.*
@@ -14,18 +15,18 @@ fun Project.processAndroidCompilation(target: KotlinJvmAndroidCompilation) {
1415 println (" processAndroidCompilation: ${target.name} " )
1516 val compilation = target.target.compilations.names.let (::println)
1617
17- tasks.register(" processAndroid${target.name.capitalize(Locale .getDefault())} Compilation" , DefaultTask ::class .java) {
18+ val generateSourcesTask = tasks.register(" processAndroid${target.name.capitalize(Locale .getDefault())} Compilation" , DefaultTask ::class .java) {
1819 it.group = " benchmark"
1920 it.description = " Processes the Android compilation '${target.name} ' for benchmarks"
2021 it.dependsOn(" bundle${target.name.capitalize(Locale .getDefault())} Aar" )
2122 it.doLast {
2223 unpackAndProcessAar(target) { classDescriptors ->
2324 generateBenchmarkSourceFiles(classDescriptors)
2425 }
25- detectAndroidDevice()
26- createAndroidBenchmarkExecTask()
2726 }
2827 }
28+
29+ createAndroidBenchmarkExecTask(target, generateSourcesTask)
2930}
3031
3132fun Project.detectAndroidDevice () {
@@ -47,43 +48,97 @@ fun Project.detectAndroidDevice() {
4748
4849
4950// Use shell command to execute separate project gradle task
50- fun Project.createAndroidBenchmarkExecTask () {
51- // TODO: Project path needs to execute benchmark task
52- val executeBenchmarkPath = " E:/Android/AndroidProjects/kotlin-qualification-task"
53- // Using ./gradlew on Windows shows error:
54- // CreateProcess error=193, %1 is not a valid Win32 application
55- val osName = System .getProperty(" os.name" ).toLowerCase(Locale .ROOT )
56- val gradlewPath = " $executeBenchmarkPath /gradlew" + if (osName.contains(" win" )) " .bat" else " "
57- val args = listOf (" -p" , executeBenchmarkPath, " connectedAndroidTest" )
51+ fun Project.createAndroidBenchmarkExecTask (target : KotlinJvmAndroidCompilation , generateSourcesTask : TaskProvider <* >) {
52+ tasks.register(" android${target.name.capitalize(Locale .getDefault())} Benchmark" , DefaultTask ::class .java) {
53+ it.group = " benchmark"
54+ it.description = " Processes the Android compilation '${target.name} ' for benchmarks"
55+ it.dependsOn(generateSourcesTask)
56+ it.doLast {
57+ detectAndroidDevice()
5858
59- try {
60- println (" Running command: $gradlewPath ${args.joinToString(" " )} " )
59+ // TODO: Project path needs to execute benchmark task
60+ val executeBenchmarkPath = " E:/Android/AndroidProjects/kotlin-qualification-task"
61+ // Using ./gradlew on Windows shows error:
62+ // CreateProcess error=193, %1 is not a valid Win32 application
63+ val osName = System .getProperty(" os.name" ).toLowerCase(Locale .ROOT )
64+ val gradlewPath = " $executeBenchmarkPath /gradlew" + if (osName.contains(" win" )) " .bat" else " "
65+ val args = listOf (" -p" , executeBenchmarkPath, " connectedAndroidTest" )
66+
67+ try {
68+ println (" Running command: $gradlewPath ${args.joinToString(" " )} " )
69+
70+ val process = ProcessBuilder (gradlewPath, * args.toTypedArray())
71+ .redirectOutput(ProcessBuilder .Redirect .PIPE )
72+ .redirectError(ProcessBuilder .Redirect .PIPE )
73+ .start()
74+
75+ val outputGobbler = StreamGobbler (process.inputStream) { println (it) }
76+ val errorGobbler = StreamGobbler (process.errorStream) { System .err.println (it) }
77+
78+ outputGobbler.start()
79+ errorGobbler.start()
80+
81+ clearLogcat()
82+ val exitCode = process.waitFor(10 , TimeUnit .MINUTES )
83+ captureLogcatOutput()
84+ if (! exitCode || process.exitValue() != 0 ) {
85+ println (" Android benchmark task failed with exit code ${process.exitValue()} " )
86+ } else {
87+ println (" Benchmark for Android target finished." )
88+ }
89+ } catch (e: Exception ) {
90+ e.printStackTrace()
91+ throw GradleException (" Failed to execute benchmark task" , e)
92+ }
93+ }
94+ }
95+ }
6196
62- val process = ProcessBuilder (gradlewPath, * args.toTypedArray())
63- .redirectOutput(ProcessBuilder .Redirect .PIPE )
64- .redirectError(ProcessBuilder .Redirect .PIPE )
97+ private fun captureLogcatOutput () {
98+ try {
99+ val logcatProcess = ProcessBuilder (" adb" , " logcat" , " -v" , " time" )
100+ .redirectErrorStream(true )
65101 .start()
66102
67- val outputGobbler = StreamGobbler (process.inputStream) { println (it) }
68- val errorGobbler = StreamGobbler (process.errorStream) { System .err.println (it) }
103+ val logcatGobbler = StreamGobbler (logcatProcess.inputStream) { line ->
104+ when {
105+ line.contains(" Iteration" ) -> println (line.substring(line.indexOf(" Iteration" )))
106+ line.contains(" run finished" ) -> println (line.substring(line.indexOf(" run finished" )))
107+ }
108+ }
69109
70- outputGobbler.start()
71- errorGobbler.start()
110+ logcatGobbler.start()
72111
73- val exitCode = process.waitFor(10 , TimeUnit .MINUTES )
74- if (! exitCode || process.exitValue() != 0 ) {
75- println (" Android benchmark task failed with exit code ${process.exitValue()} " )
76- } else {
77- println (" Benchmark for Android target finished." )
112+ if (! logcatProcess.waitFor(10 , TimeUnit .SECONDS )) {
113+ logcatProcess.destroy()
78114 }
115+
116+ logcatGobbler.join()
117+ } catch (e: Exception ) {
118+ e.printStackTrace()
119+ throw GradleException (" Failed to capture logcat output" , e)
120+ }
121+ }
122+
123+ private fun clearLogcat () {
124+ try {
125+ ProcessBuilder (" adb" , " logcat" , " -c" )
126+ .redirectErrorStream(true )
127+ .start()
128+ .waitFor(5 , TimeUnit .SECONDS )
79129 } catch (e: Exception ) {
80130 e.printStackTrace()
81- throw GradleException (" Failed to execute benchmark task " , e)
131+ throw GradleException (" Failed to clear logcat " , e)
82132 }
83133}
84134
85- class StreamGobbler (private val inputStream : InputStream , private val consumer : (String ) -> Unit ) : Thread() {
135+ class StreamGobbler (
136+ private val inputStream : InputStream ,
137+ private val consumer : (String ) -> Unit
138+ ) : Thread() {
86139 override fun run () {
87- inputStream.bufferedReader().lines().forEach(consumer)
140+ inputStream.bufferedReader().useLines { lines ->
141+ lines.forEach { consumer(it) }
142+ }
88143 }
89144}
0 commit comments