@@ -2,6 +2,7 @@ package kotlinx.benchmark.gradle
2
2
3
3
import kotlinx.benchmark.gradle.internal.KotlinxBenchmarkPluginInternalApi
4
4
import org.gradle.api.*
5
+ import org.gradle.api.tasks.TaskProvider
5
6
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
6
7
import java.io.InputStream
7
8
import java.util.*
@@ -14,18 +15,18 @@ fun Project.processAndroidCompilation(target: KotlinJvmAndroidCompilation) {
14
15
println (" processAndroidCompilation: ${target.name} " )
15
16
val compilation = target.target.compilations.names.let (::println)
16
17
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) {
18
19
it.group = " benchmark"
19
20
it.description = " Processes the Android compilation '${target.name} ' for benchmarks"
20
21
it.dependsOn(" bundle${target.name.capitalize(Locale .getDefault())} Aar" )
21
22
it.doLast {
22
23
unpackAndProcessAar(target) { classDescriptors ->
23
24
generateBenchmarkSourceFiles(classDescriptors)
24
25
}
25
- detectAndroidDevice()
26
- createAndroidBenchmarkExecTask()
27
26
}
28
27
}
28
+
29
+ createAndroidBenchmarkExecTask(target, generateSourcesTask)
29
30
}
30
31
31
32
fun Project.detectAndroidDevice () {
@@ -47,43 +48,97 @@ fun Project.detectAndroidDevice() {
47
48
48
49
49
50
// 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()
58
58
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
+ }
61
96
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 )
65
101
.start()
66
102
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
+ }
69
109
70
- outputGobbler.start()
71
- errorGobbler.start()
110
+ logcatGobbler.start()
72
111
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()
78
114
}
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 )
79
129
} catch (e: Exception ) {
80
130
e.printStackTrace()
81
- throw GradleException (" Failed to execute benchmark task " , e)
131
+ throw GradleException (" Failed to clear logcat " , e)
82
132
}
83
133
}
84
134
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() {
86
139
override fun run () {
87
- inputStream.bufferedReader().lines().forEach(consumer)
140
+ inputStream.bufferedReader().useLines { lines ->
141
+ lines.forEach { consumer(it) }
142
+ }
88
143
}
89
144
}
0 commit comments