Skip to content

Commit f93625f

Browse files
committed
Add baseline profile.
1 parent fc23c42 commit f93625f

File tree

11 files changed

+222
-27
lines changed

11 files changed

+222
-27
lines changed

baselineprofile/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

baselineprofile/build.gradle.kts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
plugins {
2+
id("com.android.test")
3+
id("org.jetbrains.kotlin.android")
4+
id("androidx.baselineprofile")
5+
}
6+
7+
android {
8+
namespace = "com.swordfish.lemuroid.baselineprofile"
9+
compileSdk = 34
10+
11+
compileOptions {
12+
sourceCompatibility = JavaVersion.VERSION_17
13+
targetCompatibility = JavaVersion.VERSION_17
14+
}
15+
16+
kotlinOptions {
17+
jvmTarget = "17"
18+
}
19+
20+
defaultConfig {
21+
minSdk = 28
22+
targetSdk = 34
23+
24+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
25+
}
26+
27+
targetProjectPath = ":lemuroid-app"
28+
29+
flavorDimensions += listOf("opensource", "cores")
30+
productFlavors {
31+
create("free") { dimension = "opensource" }
32+
create("play") { dimension = "opensource" }
33+
create("bundle") { dimension = "cores" }
34+
create("dynamic") { dimension = "cores" }
35+
}
36+
37+
}
38+
39+
// This is the configuration block for the Baseline Profile plugin.
40+
// You can specify to run the generators on a managed devices or connected devices.
41+
baselineProfile {
42+
useConnectedDevices = true
43+
}
44+
45+
dependencies {
46+
implementation("androidx.test.ext:junit:1.1.5")
47+
implementation("androidx.test.espresso:espresso-core:3.5.1")
48+
implementation("androidx.test.uiautomator:uiautomator:2.2.0")
49+
implementation("androidx.benchmark:benchmark-macro-junit4:1.2.3")
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<manifest />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.swordfish.lemuroid.baselineprofile
2+
3+
import androidx.benchmark.macro.junit4.BaselineProfileRule
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
import androidx.test.filters.LargeTest
6+
7+
import org.junit.Rule
8+
import org.junit.Test
9+
import org.junit.runner.RunWith
10+
11+
/**
12+
* This test class generates a basic startup baseline profile for the target package.
13+
*
14+
* We recommend you start with this but add important user flows to the profile to improve their performance.
15+
* Refer to the [baseline profile documentation](https://d.android.com/topic/performance/baselineprofiles)
16+
* for more information.
17+
*
18+
* You can run the generator with the "Generate Baseline Profile" run configuration in Android Studio or
19+
* the equivalent `generateBaselineProfile` gradle task:
20+
* ```
21+
* ./gradlew :lemuroid-app:generateReleaseBaselineProfile
22+
* ```
23+
* The run configuration runs the Gradle task and applies filtering to run only the generators.
24+
*
25+
* Check [documentation](https://d.android.com/topic/performance/benchmarking/macrobenchmark-instrumentation-args)
26+
* for more information about available instrumentation arguments.
27+
*
28+
* After you run the generator, you can verify the improvements running the [StartupBenchmarks] benchmark.
29+
*
30+
* When using this class to generate a baseline profile, only API 33+ or rooted API 28+ are supported.
31+
*
32+
* The minimum required version of androidx.benchmark to generate a baseline profile is 1.2.0.
33+
**/
34+
@RunWith(AndroidJUnit4::class)
35+
@LargeTest
36+
class BaselineProfileGenerator {
37+
38+
@get:Rule
39+
val rule = BaselineProfileRule()
40+
41+
@Test
42+
fun generate() {
43+
// This example works only with the variant with application id `com.swordfish.lemuroid`."
44+
rule.collect(
45+
packageName = "com.swordfish.lemuroid",
46+
47+
// See: https://d.android.com/topic/performance/baselineprofiles/dex-layout-optimizations
48+
includeInStartupProfile = true
49+
) {
50+
// This block defines the app's critical user journey. Here we are interested in
51+
// optimizing for app startup. But you can also navigate and scroll through your most important UI.
52+
53+
// Start default activity for your app
54+
pressHome()
55+
startActivityAndWait()
56+
57+
// TODO Write more interactions to optimize advanced journeys of your app.
58+
// For example:
59+
// 1. Wait until the content is asynchronously loaded
60+
// 2. Scroll the feed content
61+
// 3. Navigate to detail screen
62+
63+
// Check UiAutomator documentation for more information how to interact with the app.
64+
// https://d.android.com/training/testing/other-components/ui-automator
65+
}
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.swordfish.lemuroid.baselineprofile
2+
3+
import androidx.benchmark.macro.BaselineProfileMode
4+
import androidx.benchmark.macro.CompilationMode
5+
import androidx.benchmark.macro.StartupMode
6+
import androidx.benchmark.macro.StartupTimingMetric
7+
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
8+
import androidx.test.ext.junit.runners.AndroidJUnit4
9+
import androidx.test.filters.LargeTest
10+
11+
import org.junit.Rule
12+
import org.junit.Test
13+
import org.junit.runner.RunWith
14+
15+
/**
16+
* This test class benchmarks the speed of app startup.
17+
* Run this benchmark to verify how effective a Baseline Profile is.
18+
* It does this by comparing [CompilationMode.None], which represents the app with no Baseline
19+
* Profiles optimizations, and [CompilationMode.Partial], which uses Baseline Profiles.
20+
*
21+
* Run this benchmark to see startup measurements and captured system traces for verifying
22+
* the effectiveness of your Baseline Profiles. You can run it directly from Android
23+
* Studio as an instrumentation test, or run all benchmarks for a variant, for example benchmarkRelease,
24+
* with this Gradle task:
25+
* ```
26+
* ./gradlew :baselineprofile:connectedBenchmarkReleaseAndroidTest
27+
* ```
28+
*
29+
* You should run the benchmarks on a physical device, not an Android emulator, because the
30+
* emulator doesn't represent real world performance and shares system resources with its host.
31+
*
32+
* For more information, see the [Macrobenchmark documentation](https://d.android.com/macrobenchmark#create-macrobenchmark)
33+
* and the [instrumentation arguments documentation](https://d.android.com/topic/performance/benchmarking/macrobenchmark-instrumentation-args).
34+
**/
35+
@RunWith(AndroidJUnit4::class)
36+
@LargeTest
37+
class StartupBenchmarks {
38+
39+
@get:Rule
40+
val rule = MacrobenchmarkRule()
41+
42+
@Test
43+
fun startupCompilationNone() =
44+
benchmark(CompilationMode.None())
45+
46+
@Test
47+
fun startupCompilationBaselineProfiles() =
48+
benchmark(CompilationMode.Partial(BaselineProfileMode.Require))
49+
50+
private fun benchmark(compilationMode: CompilationMode) {
51+
// This example works only with the variant with application id `com.swordfish.lemuroid`."
52+
rule.measureRepeated(
53+
packageName = "com.swordfish.lemuroid",
54+
metrics = listOf(StartupTimingMetric()),
55+
compilationMode = compilationMode,
56+
startupMode = StartupMode.COLD,
57+
iterations = 10,
58+
setupBlock = {
59+
pressHome()
60+
},
61+
measureBlock = {
62+
startActivityAndWait()
63+
64+
// TODO Add interactions to wait for when your app is fully drawn.
65+
// The app is fully drawn when Activity.reportFullyDrawn is called.
66+
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
67+
// from the AndroidX Activity library.
68+
69+
// Check the UiAutomator documentation for more information on how to
70+
// interact with the app.
71+
// https://d.android.com/training/testing/other-components/ui-automator
72+
}
73+
)
74+
}
75+
}

build.gradle.kts

+8-19
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
11
import com.android.build.gradle.BaseExtension
2-
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
32

43
buildscript {
54
repositories {
65
google()
76
jcenter()
7+
mavenCentral()
88
}
99
dependencies {
1010
classpath(deps.plugins.android)
1111
classpath(deps.plugins.navigationSafeArgs)
12+
classpath(deps.plugins.kotlinGradlePlugin)
1213
}
1314
}
1415

15-
plugins {
16+
plugins {
1617
id("org.jetbrains.kotlin.jvm") version deps.versions.kotlin
1718
id("com.github.ben-manes.versions") version "0.39.0"
1819
id("org.jetbrains.kotlin.plugin.serialization") version "1.4.0"
1920
id("org.jlleitschuh.gradle.ktlint") version "12.1.0"
21+
id("com.android.test") version "8.4.0" apply false
22+
id("org.jetbrains.kotlin.android") version deps.versions.kotlin apply false
23+
id("androidx.baselineprofile") version "1.2.3" apply false
24+
id("com.android.application") version "8.4.0" apply false
2025
}
2126

2227
allprojects {
2328
repositories {
2429
google()
30+
mavenCentral()
2531
jcenter()
2632
mavenLocal()
27-
mavenCentral()
2833
maven { setUrl("https://jitpack.io") }
2934
}
3035

@@ -85,20 +90,4 @@ tasks {
8590
"clean"(Delete::class) {
8691
delete(buildDir)
8792
}
88-
89-
"dependencyUpdates"(DependencyUpdatesTask::class) {
90-
resolutionStrategy {
91-
componentSelection {
92-
all {
93-
val rejected =
94-
listOf("alpha", "beta", "rc", "cr", "m")
95-
.map { qualifier -> Regex("(?i).*[.-]$qualifier[.\\d-]*") }
96-
.any { it.matches(candidate.version) }
97-
if (rejected) {
98-
reject("Release candidate")
99-
}
100-
}
101-
}
102-
}
103-
}
10493
}

buildSrc/src/main/java/deps.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ object deps {
100100
const val drawablePainter = "com.google.accompanist:accompanist-drawablepainter:${versions.accompanist}"
101101
}
102102
}
103+
const val profileInstaller = "androidx.profileinstaller:profileinstaller:1.3.1"
103104
}
104105
object arch {
105106
object work {
@@ -163,7 +164,8 @@ object deps {
163164
}
164165

165166
object plugins {
166-
const val android = "com.android.tools.build:gradle:8.2.2"
167+
const val android = "com.android.tools.build:gradle:8.4.0"
167168
const val navigationSafeArgs = "androidx.navigation:navigation-safe-args-gradle-plugin:${versions.navigation}"
169+
const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
168170
}
169171
}

gradle.properties

+1-4
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@ org.gradle.parallel=true
33
org.gradle.daemon=true
44
org.gradle.jvmargs=-Xmx2560m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
55
org.gradle.caching=true
6-
76
# https://github.com/gradle/kotlin-dsl/issues/311
87
org.gradle.configureondemand=false
9-
108
# Kotlin
119
kotlin.incremental.usePreciseJavaTracking=true
12-
1310
# Android
1411
android.builder.sdkDownload=true
1512
android.enableD8.desugaring=true
16-
1713
# AndroidX
1814
android.useAndroidX=true
1915
android.enableJetifier=true
16+
org.gradle.configuration-cache=true
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Thu Mar 21 23:45:39 CET 2024
1+
#Thu May 09 21:09:06 CEST 2024
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
4-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
55
zipStoreBase=GRADLE_USER_HOME
66
zipStorePath=wrapper/dists

lemuroid-app/build.gradle.kts

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ plugins {
44
id("kotlin-kapt")
55
id("androidx.navigation.safeargs.kotlin")
66
id("kotlinx-serialization")
7+
id("androidx.baselineprofile")
78
}
89

910
android {
@@ -128,6 +129,9 @@ dependencies {
128129
implementation(project(":lemuroid-metadata-libretro-db"))
129130
implementation(project(":lemuroid-touchinput"))
130131

132+
"baselineProfile"(project(":baselineprofile"))
133+
implementation(deps.libs.androidx.profileInstaller)
134+
131135
"bundleImplementation"(project(":bundled-cores"))
132136

133137
"freeImplementation"(project(":lemuroid-app-ext-free"))

settings.gradle.kts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
@file:Suppress("ktlint")
22

3+
pluginManagement {
4+
repositories {
5+
gradlePluginPortal()
6+
google()
7+
mavenCentral()
8+
}
9+
}
10+
311
include(
412
":retrograde-util",
513
":retrograde-app-shared",
@@ -8,7 +16,8 @@ include(
816
":lemuroid-metadata-libretro-db",
917
":lemuroid-app-ext-free",
1018
":lemuroid-app-ext-play",
11-
":bundled-cores"
19+
":bundled-cores",
20+
":baselineprofile"
1221
)
1322

1423
project(":bundled-cores").projectDir = File("lemuroid-cores/bundled-cores")

0 commit comments

Comments
 (0)