Refactor baseline profiles generation and regenerate (#3434)
This commit is contained in:
+10
-2
@@ -13,6 +13,7 @@ plugins {
|
|||||||
alias(mihonx.plugins.spotless)
|
alias(mihonx.plugins.spotless)
|
||||||
|
|
||||||
alias(libs.plugins.aboutLibraries)
|
alias(libs.plugins.aboutLibraries)
|
||||||
|
alias(libs.plugins.androidx.baselineProfile)
|
||||||
alias(libs.plugins.kotlin.serialization)
|
alias(libs.plugins.kotlin.serialization)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +83,8 @@ android {
|
|||||||
|
|
||||||
signingConfig = debug.signingConfig
|
signingConfig = debug.signingConfig
|
||||||
|
|
||||||
|
isProfileable = true
|
||||||
|
|
||||||
proguardFiles("proguard-android-optimize.txt", "proguard-rules.pro")
|
proguardFiles("proguard-android-optimize.txt", "proguard-rules.pro")
|
||||||
|
|
||||||
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = true)}\"")
|
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime(useLatestCommitTime = true)}\"")
|
||||||
@@ -110,8 +113,6 @@ android {
|
|||||||
create("benchmark") {
|
create("benchmark") {
|
||||||
initWith(release)
|
initWith(release)
|
||||||
|
|
||||||
isDebuggable = false
|
|
||||||
isProfileable = true
|
|
||||||
versionNameSuffix = "-benchmark"
|
versionNameSuffix = "-benchmark"
|
||||||
applicationIdSuffix = ".benchmark"
|
applicationIdSuffix = ".benchmark"
|
||||||
|
|
||||||
@@ -197,7 +198,14 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baselineProfile {
|
||||||
|
baselineProfileOutputDir = "baselineProfiles"
|
||||||
|
mergeIntoMain = true
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
baselineProfile(projects.baselineProfile)
|
||||||
|
|
||||||
implementation(projects.i18n)
|
implementation(projects.i18n)
|
||||||
implementation(projects.core.archive)
|
implementation(projects.core.archive)
|
||||||
implementation(projects.core.common)
|
implementation(projects.core.common)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -92,6 +92,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
|||||||
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
|
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
|
||||||
import eu.kanade.tachiyomi.ui.more.OnboardingScreen
|
import eu.kanade.tachiyomi.ui.more.OnboardingScreen
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
|
import eu.kanade.tachiyomi.util.system.isBenchmarkBuildType
|
||||||
import eu.kanade.tachiyomi.util.system.isNavigationBarNeedsScrim
|
import eu.kanade.tachiyomi.util.system.isNavigationBarNeedsScrim
|
||||||
import eu.kanade.tachiyomi.util.system.updaterEnabled
|
import eu.kanade.tachiyomi.util.system.updaterEnabled
|
||||||
import eu.kanade.tachiyomi.util.view.setComposeContent
|
import eu.kanade.tachiyomi.util.view.setComposeContent
|
||||||
@@ -256,11 +257,13 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
HandleOnNewIntent(context = context, navigator = navigator)
|
HandleOnNewIntent(context = context, navigator = navigator)
|
||||||
|
|
||||||
|
if (!isBenchmarkBuildType) {
|
||||||
CheckForUpdates()
|
CheckForUpdates()
|
||||||
ShowOnboarding()
|
ShowOnboarding()
|
||||||
ShowDonationCampaign()
|
ShowDonationCampaign()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
splashScreen?.setKeepOnScreenCondition {
|
splashScreen?.setKeepOnScreenCondition {
|
||||||
|
|||||||
@@ -21,3 +21,6 @@ val isReleaseBuildType: Boolean
|
|||||||
|
|
||||||
val isFossBuildType: Boolean
|
val isFossBuildType: Boolean
|
||||||
inline get() = BuildConfig.BUILD_TYPE == "foss"
|
inline get() = BuildConfig.BUILD_TYPE == "foss"
|
||||||
|
|
||||||
|
val isBenchmarkBuildType: Boolean
|
||||||
|
inline get() = BuildConfig.BUILD_TYPE.contains("nonMinified") || BuildConfig.BUILD_TYPE.contains("benchmark")
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import com.android.build.api.dsl.ManagedVirtualDevice
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias(mihonx.plugins.android.test)
|
||||||
|
alias(libs.plugins.androidx.baselineProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "mihon.baselineprofile"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
|
||||||
|
targetProjectPath = ":app"
|
||||||
|
|
||||||
|
// This code creates the gradle managed device used to generate baseline profiles.
|
||||||
|
// To use GMD please invoke generation through the command line:
|
||||||
|
// ./gradlew :app:generateBaselineProfile
|
||||||
|
testOptions.managedDevices.allDevices {
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
create<ManagedVirtualDevice>("pixel6Api34") {
|
||||||
|
device = "Pixel 6"
|
||||||
|
apiLevel = 34
|
||||||
|
systemImageSource = "google"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the configuration block for the Baseline Profile plugin.
|
||||||
|
// You can specify to run the generators on a managed devices or connected devices.
|
||||||
|
baselineProfile {
|
||||||
|
managedDevices += "pixel6Api34"
|
||||||
|
useConnectedDevices = false
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(libs.androidx.benchmark.macroJunit4)
|
||||||
|
implementation(libs.androidx.test.junit)
|
||||||
|
implementation(libs.androidx.test.espresso.core)
|
||||||
|
implementation(libs.androidx.test.uiautomator)
|
||||||
|
}
|
||||||
|
|
||||||
|
androidComponents {
|
||||||
|
onVariants { variant ->
|
||||||
|
val artifactsLoader = variant.artifacts.getBuiltArtifactsLoader()
|
||||||
|
val applicationId = variant.testedApks.map { artifactsLoader.load(it)?.applicationId }
|
||||||
|
variant.instrumentationRunnerArguments.put("targetAppId", applicationId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<manifest />
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package mihon.baselineprofile
|
||||||
|
|
||||||
|
import androidx.benchmark.macro.junit4.BaselineProfileRule
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.LargeTest
|
||||||
|
import androidx.test.uiautomator.By
|
||||||
|
import androidx.test.uiautomator.BySelector
|
||||||
|
import androidx.test.uiautomator.UiDevice
|
||||||
|
import androidx.test.uiautomator.Until
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@LargeTest
|
||||||
|
class BaselineProfileGenerator {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val rule = BaselineProfileRule()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun generate() {
|
||||||
|
rule.collect(TARGET_PACKAGE_NAME) {
|
||||||
|
pressHome()
|
||||||
|
startActivityAndWait()
|
||||||
|
|
||||||
|
device.waitAndClick(By.text("Updates"))
|
||||||
|
device.waitForIdle()
|
||||||
|
|
||||||
|
device.waitAndClick(By.text("History"))
|
||||||
|
device.waitForIdle()
|
||||||
|
|
||||||
|
device.waitAndClick(By.text("Browse"))
|
||||||
|
device.waitForIdle()
|
||||||
|
device.waitAndClick(By.text("Extensions"))
|
||||||
|
device.waitForIdle()
|
||||||
|
|
||||||
|
device.waitAndClick(By.text("More"))
|
||||||
|
device.waitForIdle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UiDevice.waitAndClick(by: BySelector) {
|
||||||
|
wait(Until.findObject(by), 60_000).click()
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package mihon.baselineprofile
|
||||||
|
|
||||||
|
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 androidx.test.filters.LargeTest
|
||||||
|
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run this benchmark from Studio to see startup measurements, and captured system traces
|
||||||
|
* for investigating your app's performance from a cold state.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||||
|
class ColdStartupBenchmark : AbstractStartupBenchmark(StartupMode.COLD)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run this benchmark from Studio to see startup measurements, and captured system traces
|
||||||
|
* for investigating your app's performance from a warm state.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||||
|
class WarmStartupBenchmark : AbstractStartupBenchmark(StartupMode.WARM)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run this benchmark from Studio to see startup measurements, and captured system traces
|
||||||
|
* for investigating your app's performance from a hot state.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4ClassRunner::class)
|
||||||
|
class HotStartupBenchmark : AbstractStartupBenchmark(StartupMode.HOT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test class benchmarks the speed of app startup.
|
||||||
|
* Run this benchmark to verify how effective a Baseline Profile is.
|
||||||
|
* It does this by comparing [CompilationMode.None], which represents the app with no Baseline
|
||||||
|
* Profiles optimizations, and [CompilationMode.Partial], which uses Baseline Profiles.
|
||||||
|
*
|
||||||
|
* Run this benchmark to see startup measurements and captured system traces for verifying
|
||||||
|
* the effectiveness of your Baseline Profiles. You can run it directly from Android
|
||||||
|
* Studio as an instrumentation test, or run all benchmarks for a variant, for example benchmarkRelease,
|
||||||
|
* with this Gradle task:
|
||||||
|
* ```
|
||||||
|
* ./gradlew :baselineprofile:connectedBenchmarkReleaseAndroidTest
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* You should run the benchmarks on a physical device, not an Android emulator, because the
|
||||||
|
* emulator doesn't represent real world performance and shares system resources with its host.
|
||||||
|
*
|
||||||
|
* For more information, see the [Macrobenchmark documentation](https://d.android.com/macrobenchmark#create-macrobenchmark)
|
||||||
|
* and the [instrumentation arguments documentation](https://d.android.com/topic/performance/benchmarking/macrobenchmark-instrumentation-args).
|
||||||
|
**/
|
||||||
|
abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) {
|
||||||
|
@get:Rule
|
||||||
|
val rule = MacrobenchmarkRule()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startupCompilationNone() =
|
||||||
|
benchmark(CompilationMode.None())
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startupCompilationBaselineProfilesDisabled() =
|
||||||
|
benchmark(CompilationMode.Partial(BaselineProfileMode.Disable))
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startupCompilationBaselineProfiles() =
|
||||||
|
benchmark(CompilationMode.Partial(BaselineProfileMode.Require))
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startupCompilationFull() = benchmark(CompilationMode.Full())
|
||||||
|
|
||||||
|
private fun benchmark(compilationMode: CompilationMode) {
|
||||||
|
// The application id for the running build variant is read from the instrumentation arguments.
|
||||||
|
rule.measureRepeated(
|
||||||
|
packageName = TARGET_PACKAGE_NAME,
|
||||||
|
metrics = listOf(StartupTimingMetric()),
|
||||||
|
compilationMode = compilationMode,
|
||||||
|
startupMode = startupMode,
|
||||||
|
iterations = 10,
|
||||||
|
setupBlock = {
|
||||||
|
pressHome()
|
||||||
|
},
|
||||||
|
measureBlock = {
|
||||||
|
startActivityAndWait()
|
||||||
|
|
||||||
|
// TODO Add interactions to wait for when your app is fully drawn.
|
||||||
|
// The app is fully drawn when Activity.reportFullyDrawn is called.
|
||||||
|
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
|
||||||
|
// from the AndroidX Activity library.
|
||||||
|
|
||||||
|
// Check the UiAutomator documentation for more information on how to
|
||||||
|
// interact with the app.
|
||||||
|
// https://d.android.com/training/testing/other-components/ui-automator
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package mihon.baselineprofile
|
||||||
|
|
||||||
|
import androidx.benchmark.macro.junit4.BaselineProfileRule
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.LargeTest
|
||||||
|
import androidx.test.uiautomator.By
|
||||||
|
import androidx.test.uiautomator.BySelector
|
||||||
|
import androidx.test.uiautomator.UiDevice
|
||||||
|
import androidx.test.uiautomator.Until
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@LargeTest
|
||||||
|
class StartupProfileGenerator {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val rule = BaselineProfileRule()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun generate() {
|
||||||
|
rule.collect(
|
||||||
|
packageName = TARGET_PACKAGE_NAME,
|
||||||
|
includeInStartupProfile = true
|
||||||
|
) {
|
||||||
|
pressHome()
|
||||||
|
startActivityAndWait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UiDevice.waitAndClick(by: BySelector) {
|
||||||
|
wait(Until.findObject(by), 60_000).click()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package mihon.baselineprofile
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
|
||||||
|
internal val TARGET_PACKAGE_NAME: String
|
||||||
|
inline get() = InstrumentationRegistry.getArguments().getString("targetAppId")
|
||||||
|
?: throw Exception("targetAppId not passed as instrumentation runner arg")
|
||||||
@@ -10,6 +10,7 @@ plugins {
|
|||||||
alias(libs.plugins.android.kmp.library) apply false
|
alias(libs.plugins.android.kmp.library) apply false
|
||||||
alias(libs.plugins.android.library) apply false
|
alias(libs.plugins.android.library) apply false
|
||||||
alias(libs.plugins.android.test) apply false
|
alias(libs.plugins.android.test) apply false
|
||||||
|
alias(libs.plugins.androidx.baselineProfile) apply false
|
||||||
alias(libs.plugins.firebase.crashlytics) apply false
|
alias(libs.plugins.firebase.crashlytics) apply false
|
||||||
alias(libs.plugins.google.services) apply false
|
alias(libs.plugins.google.services) apply false
|
||||||
alias(libs.plugins.kotlin.compose.compiler) apply false
|
alias(libs.plugins.kotlin.compose.compiler) apply false
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ android-gradle = "9.2.1"
|
|||||||
androidx-activity-compose = "1.13.0"
|
androidx-activity-compose = "1.13.0"
|
||||||
androidx-annotation = "1.10.0"
|
androidx-annotation = "1.10.0"
|
||||||
androidx-appCompat = "1.7.1"
|
androidx-appCompat = "1.7.1"
|
||||||
|
androidx-baselineProfile = "1.5.0-alpha06"
|
||||||
androidx-benchmark = "1.4.1"
|
androidx-benchmark = "1.4.1"
|
||||||
androidx-biometric = "1.2.0-alpha05"
|
androidx-biometric = "1.2.0-alpha05"
|
||||||
androidx-compose-bom = "2026.06.00"
|
androidx-compose-bom = "2026.06.00"
|
||||||
@@ -106,7 +107,7 @@ androidx-profileInstaller = { module = "androidx.profileinstaller:profileinstall
|
|||||||
androidx-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerView" }
|
androidx-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerView" }
|
||||||
androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "androidx-sqlite" }
|
androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "androidx-sqlite" }
|
||||||
androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" }
|
androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" }
|
||||||
androidx-test-junit = { module = "androidx.test.ext:junit-ktx", version.ref = "androidx-test-junit" }
|
androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-junit" }
|
||||||
androidx-test-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "androidx-test-uiautomator" }
|
androidx-test-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "androidx-test-uiautomator" }
|
||||||
androidx-viewPager = { module = "androidx.viewpager:viewpager", version.ref = "androidx-viewPager" }
|
androidx-viewPager = { module = "androidx.viewpager:viewpager", version.ref = "androidx-viewPager" }
|
||||||
androidx-work = { module = "androidx.work:work-runtime", version.ref = "androidx-work" }
|
androidx-work = { module = "androidx.work:work-runtime", version.ref = "androidx-work" }
|
||||||
@@ -185,9 +186,10 @@ xmlutil-serialization = { module = "io.github.pdvrieze.xmlutil:serialization", v
|
|||||||
[plugins]
|
[plugins]
|
||||||
aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutLibraries" }
|
aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutLibraries" }
|
||||||
android-application = { id = "com.android.application", version.ref = "android-gradle" }
|
android-application = { id = "com.android.application", version.ref = "android-gradle" }
|
||||||
android-test = { id = "com.android.test", version.ref = "android-gradle" }
|
|
||||||
android-kmp-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "android-gradle" }
|
android-kmp-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "android-gradle" }
|
||||||
android-library = { id = "com.android.library", version.ref = "android-gradle" }
|
android-library = { id = "com.android.library", version.ref = "android-gradle" }
|
||||||
|
android-test = { id = "com.android.test", version.ref = "android-gradle" }
|
||||||
|
androidx-baselineProfile = { id = "androidx.baselineprofile", version.ref = "androidx-baselineProfile" }
|
||||||
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebase-crashlytics" }
|
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebase-crashlytics" }
|
||||||
google-services = { id = "com.google.gms.google-services", version.ref = "google-services" }
|
google-services = { id = "com.google.gms.google-services", version.ref = "google-services" }
|
||||||
kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin-gradle" }
|
kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin-gradle" }
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
# Baseline profiles
|
|
||||||
|
|
||||||
The baseline profile for this app is located at [`app/src/main/baseline-prof.txt`](../app/src/main/baseline-prof.txt).
|
|
||||||
It contains rules that enable AOT compilation of the critical user path taken during app launch.
|
|
||||||
For more information on baseline profiles, read [this document](https://developer.android.com/studio/profile/baselineprofiles).
|
|
||||||
|
|
||||||
> Note: The baseline profile needs to be re-generated for release builds that touch code which changes app startup.
|
|
||||||
|
|
||||||
To generate the baseline profile, select the `devBenchmark` build variant and run the
|
|
||||||
`BaselineProfileGenerator` benchmark test on an AOSP Android Emulator.
|
|
||||||
Then copy the resulting baseline profile from the emulator to [`app/src/main/baseline-prof.txt`](../app/src/main/baseline-prof.txt).
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
plugins {
|
|
||||||
alias(mihonx.plugins.android.test)
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "tachiyomi.macrobenchmark"
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
testInstrumentationRunnerArguments["androidx.benchmark.enabledRules"] = "BaselineProfile"
|
|
||||||
}
|
|
||||||
|
|
||||||
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.add("release")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
targetProjectPath = ":app"
|
|
||||||
experimentalProperties["android.experimental.self-instrumenting"] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(libs.androidx.test.junit)
|
|
||||||
implementation(libs.androidx.test.espresso.core)
|
|
||||||
implementation(libs.androidx.test.uiautomator)
|
|
||||||
implementation(libs.androidx.benchmark.macroJunit4)
|
|
||||||
}
|
|
||||||
|
|
||||||
androidComponents {
|
|
||||||
beforeVariants(selector().all()) {
|
|
||||||
it.enable = it.buildType == "benchmark"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest />
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package tachiyomi.macrobenchmark
|
|
||||||
|
|
||||||
import androidx.benchmark.macro.junit4.BaselineProfileRule
|
|
||||||
import androidx.test.uiautomator.By
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class BaselineProfileGenerator {
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val baselineProfileRule = BaselineProfileRule()
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun generate() = baselineProfileRule.collect(
|
|
||||||
packageName = "eu.kanade.tachiyomi.benchmark",
|
|
||||||
profileBlock = {
|
|
||||||
pressHome()
|
|
||||||
startActivityAndWait()
|
|
||||||
|
|
||||||
device.findObject(By.text("Updates")).click()
|
|
||||||
|
|
||||||
device.findObject(By.text("History")).click()
|
|
||||||
|
|
||||||
// TODO: automate storage permissions and possibly open manga details screen too?
|
|
||||||
// device.findObject(By.text("Browse")).click()
|
|
||||||
// device.findObject(By.text("Extensions")).click()
|
|
||||||
// device.swipe(150, 150, 50, 150, 1)
|
|
||||||
|
|
||||||
device.findObject(By.text("More")).click()
|
|
||||||
device.findObject(By.text("Settings")).click()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package tachiyomi.macrobenchmark
|
|
||||||
|
|
||||||
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.internal.runner.junit4.AndroidJUnit4ClassRunner
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run this benchmark from Studio to see startup measurements, and captured system traces
|
|
||||||
* for investigating your app's performance from a cold state.
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
|
||||||
class ColdStartupBenchmark : AbstractStartupBenchmark(StartupMode.COLD)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run this benchmark from Studio to see startup measurements, and captured system traces
|
|
||||||
* for investigating your app's performance from a warm state.
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
|
||||||
class WarmStartupBenchmark : AbstractStartupBenchmark(StartupMode.WARM)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run this benchmark from Studio to see startup measurements, and captured system traces
|
|
||||||
* for investigating your app's performance from a hot state.
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4ClassRunner::class)
|
|
||||||
class HotStartupBenchmark : AbstractStartupBenchmark(StartupMode.HOT)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for benchmarks with different startup modes.
|
|
||||||
* Enables app startups from various states of baseline profile or [CompilationMode]s.
|
|
||||||
*/
|
|
||||||
abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) {
|
|
||||||
@get:Rule
|
|
||||||
val benchmarkRule = MacrobenchmarkRule()
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun startupNoCompilation() = startup(CompilationMode.None())
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun startupBaselineProfileDisabled() = startup(
|
|
||||||
CompilationMode.Partial(
|
|
||||||
baselineProfileMode = BaselineProfileMode.Disable,
|
|
||||||
warmupIterations = 1,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun startupBaselineProfile() = startup(
|
|
||||||
CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require),
|
|
||||||
)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun startupFullCompilation() = startup(CompilationMode.Full())
|
|
||||||
|
|
||||||
private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated(
|
|
||||||
packageName = "eu.kanade.tachiyomi.benchmark",
|
|
||||||
metrics = listOf(StartupTimingMetric()),
|
|
||||||
compilationMode = compilationMode,
|
|
||||||
iterations = 10,
|
|
||||||
startupMode = startupMode,
|
|
||||||
setupBlock = {
|
|
||||||
pressHome()
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
startActivityAndWait()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -30,13 +30,13 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
|||||||
|
|
||||||
rootProject.name = "Mihon"
|
rootProject.name = "Mihon"
|
||||||
include(":app")
|
include(":app")
|
||||||
|
include(":baseline-profile")
|
||||||
include(":core-metadata")
|
include(":core-metadata")
|
||||||
include(":core:archive")
|
include(":core:archive")
|
||||||
include(":core:common")
|
include(":core:common")
|
||||||
include(":data")
|
include(":data")
|
||||||
include(":domain")
|
include(":domain")
|
||||||
include(":i18n")
|
include(":i18n")
|
||||||
include(":macrobenchmark")
|
|
||||||
include(":presentation-core")
|
include(":presentation-core")
|
||||||
include(":presentation-widget")
|
include(":presentation-widget")
|
||||||
include(":source-api")
|
include(":source-api")
|
||||||
|
|||||||
Reference in New Issue
Block a user