Android: Baseline profile generation

This creates a new benchmark module that is responsible for generating baseline profiles and testing them. As part of this commit a baseline-prof.txt file has been included to speed up launch times with the app in its current state. Later, profile generation can be automated and keep up with the app as it changes.
This commit is contained in:
Charles Lombardo 2022-12-09 12:13:34 -05:00
parent 61c10a5644
commit 974003888a
10 changed files with 4085 additions and 1 deletions

View File

@ -33,6 +33,8 @@ android {
versionCode(getBuildVersionCode())
versionName "${getVersion()}"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
@ -69,6 +71,19 @@ android {
versionNameSuffix '-debug'
jniDebuggable true
}
benchmark {
signingConfig signingConfigs.debug
matchingFallbacks = ['release']
debuggable false
applicationIdSuffix ".benchmark"
versionNameSuffix '-benchmark'
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'),
'proguard-rules.pro'
minifyEnabled true
shrinkResources true
}
}
externalNativeBuild {
@ -107,6 +122,7 @@ dependencies {
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation 'androidx.preference:preference:1.2.0'
implementation 'androidx.profileinstaller:profileinstaller:1.2.1'
// Force dependency version to solve build conflict with androidx preferences
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"

View File

@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-feature
android:name="android.hardware.touchscreen"
@ -44,6 +45,9 @@
<meta-data
android:name="android.max_aspect"
android:value="2.1"/>
<profileable
android:shell="true"
tools:targetApi="29" />
<activity
android:name=".ui.main.MainActivity"

File diff suppressed because it is too large Load Diff

1
Source/Android/benchmark/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,73 @@
import com.android.build.api.dsl.ManagedVirtualDevice
plugins {
id 'com.android.test'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.dolphin.benchmark'
compileSdk 33
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
defaultConfig {
minSdk 23
targetSdk 33
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
testOptions {
managedDevices {
devices {
pixel2Api31 (ManagedVirtualDevice) {
device = "Pixel 2"
apiLevel = 31
systemImageSource = "aosp"
}
}
}
}
buildTypes {
// This benchmark buildType is used for benchmarking, and should function like your
// release build (for example, with minification on). It's signed with a debug key
// for easy local/CI testing.
benchmark {
signingConfig signingConfigs.debug
matchingFallbacks = ['release']
debuggable true
applicationIdSuffix ".benchmark"
versionNameSuffix '-benchmark'
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'),
'proguard-rules.pro'
minifyEnabled true
shrinkResources true
}
}
targetProjectPath = ":app"
experimentalProperties["android.experimental.self-instrumenting"] = true
}
dependencies {
implementation 'androidx.test.ext:junit:1.1.4'
implementation 'androidx.test.espresso:espresso-core:3.5.0'
implementation 'androidx.test.uiautomator:uiautomator:2.2.0'
implementation 'androidx.benchmark:benchmark-macro-junit4:1.1.1'
}
androidComponents {
beforeVariants(selector().all()) {
enabled = buildType == "benchmark"
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<package android:name="org.dolphinemu.dolphinemu.debug" />
</queries>
</manifest>

View File

@ -0,0 +1,43 @@
package com.dolphin.benchmark
import androidx.benchmark.macro.ExperimentalBaselineProfilesApi
import androidx.benchmark.macro.junit4.BaselineProfileRule
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import androidx.test.uiautomator.UiSelector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@OptIn(ExperimentalBaselineProfilesApi::class)
@RunWith(AndroidJUnit4ClassRunner::class)
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun generate() = rule.collectBaselineProfile(
packageName = "org.dolphinemu.dolphinemu.benchmark",
profileBlock = {
pressHome()
startActivityAndWait()
// Dismiss analytics dialog due to issue with finding button
device.pressBack()
// Navigate through activities that don't require games
// TODO: Make all activities testable without having games available
// TODO: Use resource strings to support more languages
// Navigate to the Settings Activity
val settings = device.findObject(UiSelector().description("Settings"))
settings.clickAndWaitForNewWindow(30_000)
// Go through settings and to the User Data Activity
val config = device.findObject(UiSelector().textContains("Config"))
config.click()
val userData = device.findObject(UiSelector().textContains("User Data"))
userData.clickAndWaitForNewWindow(30_000)
},
)
}

View File

@ -0,0 +1,40 @@
package com.dolphin.benchmark
import androidx.benchmark.macro.BaselineProfileMode
import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun startupBaselineProfileDisabled() = startup(
CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Disable, warmupIterations = 1)
)
@Test
fun startupBaselineProfile() = startup(
CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require, warmupIterations = 1)
)
private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated(
packageName = "org.dolphinemu.dolphinemu.benchmark",
metrics = listOf(StartupTimingMetric()),
iterations = 10,
compilationMode = compilationMode,
startupMode = StartupMode.COLD,
setupBlock = {
pressHome()
}
) {
startActivityAndWait()
}
}

View File

@ -5,6 +5,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}

View File

@ -1 +1,2 @@
include ':app'
include ':benchmark'