1
1
package kotlinx.benchmark.gradle
2
2
3
- import kotlinx.benchmark.gradle.internal.KotlinxBenchmarkPluginInternalApi
4
3
import org.gradle.api.*
5
- import org.gradle.api.tasks.TaskProvider
6
4
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
7
5
import java.io.InputStream
8
6
import java.util.*
9
7
import java.util.concurrent.TimeUnit
10
8
9
+ private const val GENERATED_ANDROID_PROJECT_NAME = " GeneratedAndroidProject"
11
10
12
- @KotlinxBenchmarkPluginInternalApi
13
- fun Project.processAndroidCompilation (target : KotlinJvmAndroidCompilation ) {
14
- project.logger.info(" Configuring benchmarks for '${target.name} ' using Kotlin/Android" )
15
- println (" processAndroidCompilation: ${target.name} " )
16
- val compilation = target.target.compilations.names.let (::println)
11
+ internal fun Project.processAndroidCompilation (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ) {
12
+ project.logger.info(" Configuring benchmarks for '${compilation.name} ' using $target " )
17
13
18
- val generateSourcesTask = tasks.register(" processAndroid${target.name.capitalize(Locale .getDefault())} Compilation" , DefaultTask ::class .java) {
19
- it.group = " benchmark"
20
- it.description = " Processes the Android compilation '${target.name} ' for benchmarks"
21
- it.dependsOn(" bundle${target.name.capitalize(Locale .getDefault())} Aar" )
22
- it.doLast {
23
- unpackAndProcessAar(target) { classDescriptors ->
24
- generateBenchmarkSourceFiles(classDescriptors)
14
+ createUnpackAarTask(target, compilation)
15
+ createSetupAndroidProjectTask(target, compilation)
16
+ createAndroidBenchmarkGenerateSourceTask(target, compilation)
17
+ createAndroidBenchmarkExecTask(target, compilation)
18
+ }
19
+
20
+ private fun Project.androidBenchmarkBuildDir (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ) =
21
+ benchmarkBuildDir(target).resolve(compilation.name)
22
+
23
+ private fun Project.generatedAndroidProjectDir (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ) =
24
+ androidBenchmarkBuildDir(target, compilation).resolve(GENERATED_ANDROID_PROJECT_NAME )
25
+
26
+ private fun Project.createSetupAndroidProjectTask (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ) {
27
+ task<DefaultTask >(" setup${compilation.name.capitalize()} AndroidProject" ) {
28
+ group = " benchmark"
29
+ description = " Sets up an empty android project to generate benchmarks into"
30
+
31
+ doFirst {
32
+ sync {
33
+ it.apply {
34
+ val pluginJarPath = BenchmarksPlugin ::class .java.protectionDomain.codeSource.location.path
35
+ from(project.zipTree(pluginJarPath))
36
+ into(androidBenchmarkBuildDir(target, compilation))
37
+ include(" $GENERATED_ANDROID_PROJECT_NAME /**" )
38
+ }
39
+ }
40
+ }
41
+ doLast {
42
+ val generatedAndroidProjectDir = generatedAndroidProjectDir(target, compilation)
43
+ logger.info(" Setting up an empty Android project at $generatedAndroidProjectDir " )
44
+
45
+ generatedAndroidProjectDir.resolve(" microbenchmark/build.gradle.kts" ).let {
46
+ val unpackedDir = getUnpackAarDir(compilation)
47
+ val newText = it.readText().replace(
48
+ " <<BENCHMARK_CLASSES_JAR_PATH>>" ,
49
+ unpackedDir.resolve(" classes.jar" ).absolutePath
50
+ )
51
+ it.writeText(newText)
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ private fun Project.createUnpackAarTask (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ) {
58
+ // TODO: capitalize(Locale.ROOT) everywhere in the project. For toLower/UpperCase() as well.
59
+ task<DefaultTask >(" unpack${compilation.name.capitalize()} Aar" ) {
60
+ group = " benchmark"
61
+ description = " Unpacks the AAR file produced by ${target.name} compilation '${compilation.name} '"
62
+ dependsOn(" bundle${compilation.name.capitalize()} Aar" )
63
+ doLast {
64
+ logger.info(" Unpacking AAR file produced by ${target.name} compilation '${compilation.name} '" )
65
+
66
+ val aarFile = getAarFile(compilation)
67
+
68
+ if (! aarFile.exists()) {
69
+ throw IllegalStateException (" AAR file not found: ${aarFile.absolutePath} " )
25
70
}
71
+
72
+ // TODO: Register the unpacked dir as an output of this task
73
+ // TODO: Delete the directory if exists before unpacking
74
+ unpackAarFile(aarFile, compilation)
26
75
}
27
76
}
77
+ }
78
+
79
+ private fun generateSourcesTaskName (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ): String {
80
+ return " ${target.name}${compilation.name.capitalize()}${BenchmarksPlugin .BENCHMARK_GENERATE_SUFFIX } "
81
+ }
82
+
83
+ private fun Project.createAndroidBenchmarkGenerateSourceTask (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ) {
84
+ task<DefaultTask >(generateSourcesTaskName(target, compilation)) {
85
+ group = " benchmark"
86
+ description = " Generates Android source files for ${target.name} compilation '${compilation.name} '"
87
+ dependsOn(" unpack${compilation.name.capitalize()} Aar" )
88
+ dependsOn(" setup${compilation.name.capitalize()} AndroidProject" )
28
89
29
- createAndroidBenchmarkExecTask(target, generateSourcesTask)
90
+ doLast {
91
+
92
+ val unpackedDir = getUnpackAarDir(compilation)
93
+ processClassesJar(unpackedDir, compilation) { classDescriptors ->
94
+ val targetDir = generatedAndroidProjectDir(target, compilation)
95
+ .resolve(" microbenchmark/src/androidTest/kotlin" )
96
+
97
+ check(targetDir.exists())
98
+
99
+ generateBenchmarkSourceFiles(targetDir, classDescriptors)
100
+ }
101
+ }
102
+ }
30
103
}
31
104
32
- fun Project. detectAndroidDevice () {
105
+ private fun detectAndroidDevice () {
33
106
println (" Detect running Android devices..." )
34
107
val devices = ProcessBuilder (" adb" , " devices" )
35
108
.start()
@@ -48,16 +121,16 @@ fun Project.detectAndroidDevice() {
48
121
49
122
50
123
// Use shell command to execute separate project gradle task
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 {
124
+ private fun Project.createAndroidBenchmarkExecTask (target : AndroidBenchmarkTarget , compilation : KotlinJvmAndroidCompilation ) {
125
+ task< DefaultTask > (" android${compilation .name.capitalize() } Benchmark" ) {
126
+ group = " benchmark"
127
+ description = " Executes benchmarks for ${target.name} compilation '${compilation .name} '"
128
+ dependsOn(generateSourcesTaskName(target, compilation) )
129
+ doLast {
57
130
detectAndroidDevice()
58
131
59
132
// TODO: Project path needs to execute benchmark task
60
- val executeBenchmarkPath = " E:/Android/AndroidProjects/kotlin-qualification-task "
133
+ val executeBenchmarkPath = generatedAndroidProjectDir(target, compilation).path
61
134
// Using ./gradlew on Windows shows error:
62
135
// CreateProcess error=193, %1 is not a valid Win32 application
63
136
val osName = System .getProperty(" os.name" ).toLowerCase(Locale .ROOT )
@@ -137,10 +210,7 @@ private fun clearLogcat() {
137
210
}
138
211
}
139
212
140
- class StreamGobbler (
141
- private val inputStream : InputStream ,
142
- private val consumer : (String ) -> Unit
143
- ) : Thread() {
213
+ private class StreamGobbler (private val inputStream : InputStream , private val consumer : (String ) -> Unit ) : Thread() {
144
214
override fun run () {
145
215
inputStream.bufferedReader().useLines { lines ->
146
216
lines.forEach { consumer(it) }
0 commit comments