Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup Baseline profiles #379

Merged
merged 14 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/baseline-profile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Weekly Baseline Profile Generation

on:
schedule:
- cron: '30 0 * * 0,3,5' #Every Sunday, Wednesday, and Friday at 12:30AM

jobs:
baseline_profiles:
name: "Generate Baseline Profiles"
runs-on: ubuntu-latest

permissions:
contents: write

timeout-minutes: 60

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 21

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
cache-disabled: true

- name: Setup Android SDK
uses: android-actions/setup-android@v3

- name: Accept licenses
run: yes | sdkmanager --licenses || true

- name: Build app and benchmark
run: ./gradlew assembleNonMinifiedRelease

- name: Clear Gradle Managed Devices
run: ./gradlew cleanManagedDevices

- name: Generate Baseline Profile
run: ./gradlew :android:app:generateBaselineProfile
-Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=baselineprofile
-Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
--no-configuration-cache

## ToDo: Commit baseline profile changes to main.
38 changes: 9 additions & 29 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,15 @@ jobs:
echo "TRAKT_CLIENT_SECRET=$TRAKT_CLIENT_SECRET" >> ./local.properties
echo "TRAKT_REDIRECT_URI=$TRAKT_REDIRECT_URI" >> ./local.properties

- name: Build with Gradle
run: ./gradlew assemble
- name: Build Android App
run: |
./gradlew check \
:android:app:assemble \
:android:app:bundle \
-x assembleNonMinifiedRelease \
-x bundleNonMinifiedRelease \
-Pandroidx.baselineprofile.skipgeneration=true \
--no-configuration-cache

android-lint:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -374,30 +381,3 @@ jobs:
# name: test-results
# path: fastlane/test_output
#
create-release:
needs: [build-android, android-lint, android-screenshot-test, common-test, spotless, dependency-health, jvm-test]
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: ${{ env.JDK_VERSION }}
distribution: ${{ env.DISTRIBUTION }}

- name: Create release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
draft: true
files: android/app/build/outputs/apk/dev/debug/app-dev-debug.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload build outputs (APKs)
uses: actions/upload-artifact@v4
with:
name: build-outputs
path: android/app/build/outputs
1 change: 1 addition & 0 deletions android/app/benchmark-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-dontobfuscate
9 changes: 8 additions & 1 deletion android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
plugins {
alias(libs.plugins.tvmaniac.application)
alias(libs.plugins.ksp)
}

android {
Expand Down Expand Up @@ -80,6 +79,7 @@ dependencies {
implementation(libs.androidx.core.core)
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.profileinstaller)
implementation(libs.appauth)

implementation(libs.decompose.decompose)
Expand All @@ -97,4 +97,11 @@ dependencies {
implementation(libs.androidx.compose.ui.ui)
implementation(libs.coroutines.core)
implementation(libs.ktor.core)

baselineProfile(projects.android.benchmark)
}

baselineProfile {
mergeIntoMain = true
saveInSrc = true
}
26,553 changes: 26,553 additions & 0 deletions android/app/src/main/generated/baselineProfiles/baseline-prof.txt

Large diffs are not rendered by default.

26,553 changes: 26,553 additions & 0 deletions android/app/src/main/generated/baselineProfiles/startup-prof.txt

Large diffs are not rendered by default.

61 changes: 61 additions & 0 deletions android/benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import com.android.build.api.dsl.ManagedVirtualDevice

plugins {
alias(libs.plugins.android.test)
alias(libs.plugins.androidx.baselineprofile)
alias(libs.plugins.tvmaniac.kotlin.android)
}

android {
namespace = "com.thomaskioko.tvmaniac.benchmark"
compileSdk = 35

defaultConfig {
minSdk = 28
targetSdk = 35

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

@Suppress("UnstableApiUsage")
testOptions {
managedDevices {
devices {
create<ManagedVirtualDevice>("pixel6Api34") {
device = "Pixel 6"
apiLevel = 34
systemImageSource = "aosp"
}
}
}
}

targetProjectPath = ":android:app"
}

@Suppress("UnstableApiUsage")
baselineProfile {
managedDevices += "pixel6Api34"
useConnectedDevices = false

// Set this to true for debugging
enableEmulatorDisplay = false
}

dependencies {
implementation(libs.androidx.junit)
implementation(libs.androidx.espresso.core)
implementation(libs.androidx.uiautomator)
implementation(libs.androidx.benchmark.macro.junit4)
}

@Suppress("UnstableApiUsage")
androidComponents {
onVariants { v ->
val artifactsLoader = v.artifacts.getBuiltArtifactsLoader()
v.instrumentationRunnerArguments.put(
"targetAppId",
v.testedApks.map { artifactsLoader.load(it)?.applicationId },
)
}
}
1 change: 1 addition & 0 deletions android/benchmark/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest />
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.thomaskioko.tvmaniac.benchmark

const val TARGET_PACKAGE = "com.thomaskioko.tvmaniac"
const val DEFAULT_ITERATIONS = 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.thomaskioko.tvmaniac.benchmark.baselineprofile

import androidx.benchmark.macro.junit4.BaselineProfileRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.thomaskioko.tvmaniac.benchmark.TARGET_PACKAGE
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()

@Test
fun generateBaselineProfile() = rule.collect(
packageName = TARGET_PACKAGE,
includeInStartupProfile = true,
profileBlock = {
startActivityAndWait()
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.thomaskioko.tvmaniac.benchmark.benchmark

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 com.thomaskioko.tvmaniac.benchmark.DEFAULT_ITERATIONS
import com.thomaskioko.tvmaniac.benchmark.TARGET_PACKAGE
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 startupCompilationModePartial() = startup(CompilationMode.Partial())

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

private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated(
packageName = TARGET_PACKAGE,
metrics = listOf(StartupTimingMetric()),
iterations = DEFAULT_ITERATIONS,
compilationMode = compilationMode,
startupMode = StartupMode.COLD,
) {
pressHome()
startActivityAndWait()

//TODO:: Add core app interactions
}
}
6 changes: 6 additions & 0 deletions build-plugins/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,17 @@ gradlePlugin {
id = "plugin.tvmaniac.android.library"
implementationClass = "com.thomaskioko.tvmaniac.plugins.AndroidLibraryPlugin"
}

register("androidComposeLibrary") {
id = "plugin.tvmaniac.compose.library"
implementationClass = "com.thomaskioko.tvmaniac.plugins.ComposeLibraryPlugin"
}

register("kotlinAndroid") {
id = "plugin.tvmaniac.kotlin.android"
implementationClass = "com.thomaskioko.tvmaniac.plugins.KotlinAndroidConventionPlugin"
}

register("spotless") {
id = "plugin.tvmaniac.spotless"
implementationClass = "com.thomaskioko.tvmaniac.plugins.SpotlessPlugin"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.thomaskioko.tvmaniac.plugins

import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.ManagedVirtualDevice
import com.thomaskioko.tvmaniac.extensions.Versions
import com.thomaskioko.tvmaniac.extensions.configureAndroid
import com.thomaskioko.tvmaniac.extensions.configureAndroidCompose
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.get

class ApplicationPlugin : Plugin<Project> {
Expand All @@ -17,6 +19,8 @@ class ApplicationPlugin : Plugin<Project> {
apply("com.android.application")
apply("org.jetbrains.kotlin.android")
apply("com.autonomousapps.dependency-analysis")
apply("androidx.baselineprofile")
apply("com.google.devtools.ksp")
}

extensions.configure<ApplicationExtension> {
Expand All @@ -25,6 +29,8 @@ class ApplicationPlugin : Plugin<Project> {
versionCode = 1
versionName = "1.0"
targetSdk = Versions.TARGET_SDK

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

buildFeatures.buildConfig = true
Expand All @@ -46,6 +52,17 @@ class ApplicationPlugin : Plugin<Project> {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}

@Suppress("UnstableApiUsage")
testOptions {
managedDevices {
devices.create<ManagedVirtualDevice>("pixel6Api34") {
device = "Pixel 6"
apiLevel = 34
systemImageSource = "aosp"
}
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.thomaskioko.tvmaniac.plugins

import com.thomaskioko.tvmaniac.extensions.configureKotlinJvm
import org.gradle.api.Plugin
import org.gradle.api.Project

class KotlinAndroidConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.jetbrains.kotlin.android")
}

configureKotlinJvm()
}
}
}
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ plugins {
alias(libs.plugins.tvmaniac.git.hooks)
alias(libs.plugins.tvmaniac.spotless)
alias(libs.plugins.tvmaniac.root)
alias(libs.plugins.android.test) apply false
alias(libs.plugins.androidx.baselineprofile) apply false
}
Loading
Loading