Skip to content

Commit

Permalink
chore: Use baseline profile to improve app performance
Browse files Browse the repository at this point in the history
  • Loading branch information
yassineAbou committed Jul 12, 2023
1 parent 18fec8f commit 8eea3d8
Show file tree
Hide file tree
Showing 12 changed files with 6,254 additions and 2 deletions.
37 changes: 37 additions & 0 deletions .idea/androidTestResultsUserPreferences.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6,013 changes: 6,013 additions & 0 deletions app/baseline-prof.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions app/benchmark-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-dontobfuscate
9 changes: 9 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,12 @@ dependencies {
implementation("com.google.dagger:hilt-android:2.46.1")
kapt("com.google.dagger:hilt-compiler:2.46.1")
}
android {
buildTypes {
create("benchmark") {
signingConfig = signingConfigs.getByName("debug")
matchingFallbacks += listOf("release")
isDebuggable = false
}
}
}
8 changes: 6 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
xmlns:tools="http://schemas.android.com/tools">

<application
android:name="com.yassineabou.calculator.CalculatorApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="false"
tools:replace="android:supportsRtl"
android:theme="@style/Theme.Calculator0"
android:name="com.yassineabou.calculator.CalculatorApplication">
tools:replace="android:supportsRtl">
<profileable
android:shell="true"
tools:targetApi="29" />

<activity
android:name="com.yassineabou.calculator.ui.MainActivity"
Expand All @@ -21,6 +24,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
Expand Down
1 change: 1 addition & 0 deletions benchmark/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
68 changes: 68 additions & 0 deletions benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import com.android.build.api.dsl.ManagedVirtualDevice

plugins {
id("com.android.test")
id("org.jetbrains.kotlin.android")
}

@Suppress("UnstableApiUsage")
android {
namespace = "com.yassineabou.benchmark"
compileSdk = 33

compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlinOptions {
jvmTarget = "17"
}

defaultConfig {
minSdk = 24
targetSdk = 33

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

testOptions {
managedDevices {
devices {
create<ManagedVirtualDevice>("pixel2Api31") {
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.
create("benchmark") {
isDebuggable = true
signingConfig = getByName("debug").signingConfig
matchingFallbacks += listOf("release")
proguardFiles("benchmark-rules.pro")
}
}

targetProjectPath = ":app"
experimentalProperties["android.experimental.self-instrumenting"] = true
}

dependencies {
implementation("androidx.test.ext:junit:1.1.5")
implementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("androidx.test.uiautomator:uiautomator:2.2.0")
implementation("androidx.benchmark:benchmark-macro-junit4:1.1.1")
}

androidComponents {
beforeVariants(selector().all()) {
it.enable = it.buildType == "benchmark"
}
}
7 changes: 7 additions & 0 deletions benchmark/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<queries>
<package android:name="com.yassineabou.calculator" />
</queries>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.yassineabou.benchmark

import androidx.benchmark.macro.ExperimentalBaselineProfilesApi
import androidx.benchmark.macro.junit4.BaselineProfileRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalBaselineProfilesApi::class)
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {

@get:Rule
val baselineRule = BaselineProfileRule()

@Test
fun generateBaselineProfile() = baselineRule.collectBaselineProfile(
packageName = "com.yassineabou.calculator",
) {
pressHome()
startActivityAndWait()

clickOnId("scientificMode")
clickOnId("normalMode")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.yassineabou.benchmark

import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.FrameTimingMetric
import androidx.benchmark.macro.MacrobenchmarkScope
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import junit.framework.TestCase.fail
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

/**
* This is an example startup benchmark.
*
* It navigates to the device's home screen, and launches the default activity.
*
* Before running this benchmark:
* 1) switch your app's active build variant in the Studio (affects Studio runs only)
* 2) add `<profileable android:shell="true" />` to your app's manifest, within the `<application>` tag
*
* Run this benchmark from Studio to see startup measurements, and captured system traces
* for investigating your app's performance.
*/
@RunWith(AndroidJUnit4::class)
class ExampleStartupBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()

@Test
fun startupCompilationNone() = startup(CompilationMode.None())

@Test
fun startupCompilationPartial() = startup(CompilationMode.Partial())

@Test
fun changeOrientationCompilationNone() = changeOrientation(CompilationMode.None())

@Test
fun changeOrientationCompilationPartial() = changeOrientation(CompilationMode.Partial())

private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated(
packageName = "com.yassineabou.calculator",
metrics = listOf(StartupTimingMetric()),
iterations = 5,
startupMode = StartupMode.COLD,
compilationMode = compilationMode,
) {
pressHome()
startActivityAndWait()
}

private fun changeOrientation(compilationMode: CompilationMode) = benchmarkRule.measureRepeated(
packageName = "com.yassineabou.calculator",
metrics = listOf(FrameTimingMetric()),
iterations = 5,
startupMode = StartupMode.COLD,
compilationMode = compilationMode,
) {
pressHome()
startActivityAndWait()

clickOnId("scientificMode")
clickOnId("normalMode")
}
}

fun MacrobenchmarkScope.clickOnId(resourceId: String) {
val selector = By.res(packageName, resourceId)
if (!device.wait(Until.hasObject(selector), 2_500)) {
fail("Did not find object with id $resourceId")
}

device
.findObject(selector)
.click()
// Chill to ensure we capture the end of the click span in the trace.
Thread.sleep(100)
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ dependencyResolutionManagement {
}
rootProject.name = "Calculator"
include(":app")
include(":benchmark")

0 comments on commit 8eea3d8

Please sign in to comment.