Skip to content

Commit 4092879

Browse files
Abduqodiri Qurbonzodakx412764776
authored andcommitted
Generate benchmark sources into the template android project
1 parent 8b68846 commit 4092879

File tree

4 files changed

+111
-73
lines changed

4 files changed

+111
-73
lines changed

plugin/main/src/kotlinx/benchmark/gradle/AndroidMultiplatformTasks.kt

Lines changed: 97 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,108 @@
11
package kotlinx.benchmark.gradle
22

3-
import kotlinx.benchmark.gradle.internal.KotlinxBenchmarkPluginInternalApi
43
import org.gradle.api.*
5-
import org.gradle.api.tasks.TaskProvider
64
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
75
import java.io.InputStream
86
import java.util.*
97
import java.util.concurrent.TimeUnit
108

9+
private const val GENERATED_ANDROID_PROJECT_NAME = "GeneratedAndroidProject"
1110

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")
1713

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}")
2570
}
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)
2675
}
2776
}
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")
2889

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+
}
30103
}
31104

32-
fun Project.detectAndroidDevice() {
105+
private fun detectAndroidDevice() {
33106
println("Detect running Android devices...")
34107
val devices = ProcessBuilder("adb", "devices")
35108
.start()
@@ -48,16 +121,16 @@ fun Project.detectAndroidDevice() {
48121

49122

50123
// 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 {
57130
detectAndroidDevice()
58131

59132
// TODO: Project path needs to execute benchmark task
60-
val executeBenchmarkPath = "E:/Android/AndroidProjects/kotlin-qualification-task"
133+
val executeBenchmarkPath = generatedAndroidProjectDir(target, compilation).path
61134
// Using ./gradlew on Windows shows error:
62135
// CreateProcess error=193, %1 is not a valid Win32 application
63136
val osName = System.getProperty("os.name").toLowerCase(Locale.ROOT)
@@ -137,10 +210,7 @@ private fun clearLogcat() {
137210
}
138211
}
139212

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() {
144214
override fun run() {
145215
inputStream.bufferedReader().useLines { lines ->
146216
lines.forEach { consumer(it) }

plugin/main/src/kotlinx/benchmark/gradle/AndroidSourceGenerator.kt

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,16 @@
11
package kotlinx.benchmark.gradle
22

33
import com.squareup.kotlinpoet.*
4-
import kotlinx.benchmark.gradle.internal.KotlinxBenchmarkPluginInternalApi
5-
import org.gradle.api.*
64
import java.io.File
75
import java.util.*
86

9-
@KotlinxBenchmarkPluginInternalApi
10-
fun Project.generateBenchmarkSourceFiles(
7+
internal fun generateBenchmarkSourceFiles(
8+
targetDir: File,
119
classDescriptors: List<ClassAnnotationsDescriptor>,
1210
) {
13-
14-
// TODO: Path needs to generate files
15-
val targetPath = "/Users/abduqodiri.qurbonzoda_1/AndroidStudioProjects/kotlin-qualification-task/microbenchmark"
16-
val androidTestDir = File(targetPath).resolve("src/androidTest/kotlin")
17-
if (!androidTestDir.exists()) {
18-
androidTestDir.mkdirs()
19-
}
20-
21-
val buildGradleFile = File(targetPath).resolve("build.gradle.kts")
22-
val dependencyPaths = listOf(
23-
"${project.projectDir}/build/outputs/unpacked-aar/release/classes.jar".replace("\\", "/") to null,
24-
"androidx.benchmark:benchmark-junit4" to "1.2.4",
25-
"androidx.test.ext:junit-ktx" to "1.2.1",
26-
"junit:junit" to "4.13.2"
27-
)
28-
29-
updateAndroidDependencies(buildGradleFile, dependencyPaths)
30-
3111
classDescriptors.forEach { descriptor ->
3212
if (descriptor.visibility == Visibility.PUBLIC && !descriptor.isAbstract) {
33-
generateDescriptorFile(descriptor, androidTestDir)
13+
generateDescriptorFile(descriptor, targetDir)
3414
}
3515
}
3616
}

plugin/main/src/kotlinx/benchmark/gradle/AndroidTasks.kt

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,21 @@
11
package kotlinx.benchmark.gradle
22

3-
import kotlinx.benchmark.gradle.internal.KotlinxBenchmarkPluginInternalApi
43
import org.gradle.api.*
54
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
65
import java.io.File
76
import java.util.jar.JarFile
87

9-
@KotlinxBenchmarkPluginInternalApi
10-
fun Project.unpackAndProcessAar(
11-
target: KotlinJvmAndroidCompilation,
12-
onProcessed: (List<ClassAnnotationsDescriptor>) -> Unit
13-
) {
14-
println("Unpacking AAR file for ${target.name}")
15-
val aarFile = getAarFile(target)
16-
if (aarFile.exists()) {
17-
val unpackedDir = unpackAarFile(aarFile, target)
18-
processClassesJar(unpackedDir, target, onProcessed)
19-
} else {
20-
println("AAR file not found")
21-
}
8+
internal fun Project.getAarFile(compilation: KotlinJvmAndroidCompilation): File {
9+
return File("${project.projectDir}/build/outputs/aar/${project.name}-${compilation.name}.aar")
2210
}
2311

24-
private fun Project.getAarFile(target: KotlinJvmAndroidCompilation): File {
25-
return File("${project.projectDir}/build/outputs/aar/${project.name}-${target.name}.aar")
12+
internal fun Project.getUnpackAarDir(compilation: KotlinJvmAndroidCompilation): File {
13+
return File("${project.projectDir}/build/outputs/unpacked-aar/${compilation.name}")
2614
}
2715

28-
private fun Project.unpackAarFile(aarFile: File, target: KotlinJvmAndroidCompilation): File {
29-
val unpackedDir = File("${project.projectDir}/build/outputs/unpacked-aar/${target.name}")
30-
project.copy {
16+
internal fun Project.unpackAarFile(aarFile: File, compilation: KotlinJvmAndroidCompilation): File {
17+
val unpackedDir = getUnpackAarDir(compilation)
18+
project.sync {
3119
it.from(project.zipTree(aarFile))
3220
it.into(unpackedDir)
3321
}
@@ -43,13 +31,13 @@ private fun Project.unpackAarFile(aarFile: File, target: KotlinJvmAndroidCompila
4331
return unpackedDir
4432
}
4533

46-
private fun Project.processClassesJar(
34+
internal fun processClassesJar(
4735
unpackedDir: File,
48-
target: KotlinJvmAndroidCompilation,
36+
compilation: KotlinJvmAndroidCompilation,
4937
onProcessed: (List<ClassAnnotationsDescriptor>) -> Unit) {
5038
val classesJar = File(unpackedDir, "classes.jar")
5139
if (classesJar.exists()) {
52-
println("Processing classes.jar for ${target.name}")
40+
println("Processing classes.jar for ${compilation.name}")
5341
val jar = JarFile(classesJar)
5442
val annotationProcessor = AnnotationProcessor()
5543
annotationProcessor.processJarFile(jar)

plugin/main/src/kotlinx/benchmark/gradle/BenchmarksPlugin.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ constructor(
124124
config.target.compilations.all { compilation ->
125125
// This block is called for each compilation when they are materialized
126126
println("handling compilation: $compilation")
127-
processAndroidCompilation(compilation)
127+
processAndroidCompilation(config, compilation)
128128
}
129129
}
130130
}

0 commit comments

Comments
 (0)