Publish current app and server
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id("com.android.test")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("androidx.baselineprofile")
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -8,12 +9,16 @@ android {
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
// Baseline profile generation needs API 28+. The app itself still ships to 23 —
|
||||
// this floor applies only to the machine generating the profile, not to the TVs
|
||||
// that consume it.
|
||||
minSdk = 28
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
testInstrumentationRunnerArguments["androidx.benchmark.enabledRules"] = "Macrobenchmark"
|
||||
// The target is the current debug build for Phase 1 only. Results are labelled
|
||||
// debug-influenced; a release benchmark variant will be added before Phase 2.
|
||||
testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE"
|
||||
// No DEBUGGABLE suppression any more: the baselineprofile plugin adds
|
||||
// nonMinifiedRelease / benchmarkRelease variants to :app and mirrors them here,
|
||||
// so these are real release numbers rather than the debug-influenced ones the
|
||||
// Phase 1 setup produced.
|
||||
testInstrumentationRunnerArguments["androidx.benchmark.enabledRules"] = "Macrobenchmark,BaselineProfile"
|
||||
}
|
||||
targetProjectPath = ":app"
|
||||
experimentalProperties["android.experimental.self-instrumenting"] = true
|
||||
@@ -31,6 +36,12 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
baselineProfile {
|
||||
// A television is the only device that produces a representative profile for this
|
||||
// app, so generation always runs against whatever is connected over adb.
|
||||
useConnectedDevices = true
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
||||
@@ -38,7 +49,8 @@ kotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.benchmark:benchmark-macro-junit4:1.2.4")
|
||||
implementation("androidx.benchmark:benchmark-macro-junit4:1.3.4")
|
||||
implementation("androidx.test.ext:junit:1.2.1")
|
||||
implementation("androidx.test:runner:1.6.2")
|
||||
implementation("androidx.test.uiautomator:uiautomator:2.3.0")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.ponzischeme89.memby.benchmark
|
||||
|
||||
import android.view.KeyEvent
|
||||
import androidx.benchmark.macro.MacrobenchmarkScope
|
||||
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
|
||||
|
||||
/**
|
||||
* Records the classes and methods the launcher touches between process start and the
|
||||
* first few D-pad moves, so ART can compile them ahead of time instead of interpreting
|
||||
* them on a TV box that has nothing to spare.
|
||||
*
|
||||
* Run against a real television:
|
||||
*
|
||||
* .\gradlew.bat :app:generateReleaseBaselineProfile
|
||||
*
|
||||
* The output lands in app/src/release/generated/baselineProfiles and is checked in, so
|
||||
* an ordinary `assembleRelease` needs no device. Regenerate it after a change that moves
|
||||
* the startup path — a stale profile is not harmful, just progressively less useful.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class BaselineProfileGenerator {
|
||||
@get:Rule val rule = BaselineProfileRule()
|
||||
|
||||
@Test
|
||||
fun startupAndBrowse() = rule.collect(
|
||||
packageName = "com.ponzischeme89.memby",
|
||||
// The signed-in launcher renders from HomeCache before the network answers, so a
|
||||
// cold start reaches real rows without waiting on the gateway. Include enough
|
||||
// D-pad movement to pull in the row/card composables and Coil's decode path,
|
||||
// which is where the first-scroll jank lives.
|
||||
includeInStartupProfile = true,
|
||||
) {
|
||||
pressHome()
|
||||
startActivityAndWait()
|
||||
browseHome()
|
||||
}
|
||||
|
||||
private fun MacrobenchmarkScope.browseHome() {
|
||||
repeat(4) { device.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) }
|
||||
device.waitForIdle()
|
||||
device.pressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN)
|
||||
repeat(3) { device.pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT) }
|
||||
device.waitForIdle()
|
||||
device.pressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN)
|
||||
device.waitForIdle()
|
||||
}
|
||||
}
|
||||
@@ -15,24 +15,35 @@ import org.junit.runner.RunWith
|
||||
class HomeBenchmark {
|
||||
@get:Rule val benchmarkRule = MacrobenchmarkRule()
|
||||
|
||||
/**
|
||||
* The baseline for comparison: no ahead-of-time compilation at all. Keep this around
|
||||
* — the only way to know whether [coldStartToHomeWithProfile] is earning its keep is
|
||||
* to see the two numbers side by side.
|
||||
*/
|
||||
@Test
|
||||
fun coldStartToHome() = benchmarkRule.measureRepeated(
|
||||
packageName = "com.ponzischeme89.memby",
|
||||
fun coldStartToHomeNoCompilation() = measureColdStart(CompilationMode.None())
|
||||
|
||||
/** What a viewer installing a release APK actually gets. */
|
||||
@Test
|
||||
fun coldStartToHomeWithProfile() = measureColdStart(CompilationMode.Partial())
|
||||
|
||||
private fun measureColdStart(mode: CompilationMode) = benchmarkRule.measureRepeated(
|
||||
packageName = PACKAGE_NAME,
|
||||
metrics = listOf(StartupTimingMetric()),
|
||||
compilationMode = CompilationMode.None(),
|
||||
compilationMode = mode,
|
||||
startupMode = StartupMode.COLD,
|
||||
iterations = 3,
|
||||
iterations = 5,
|
||||
setupBlock = { pressHome() },
|
||||
measureBlock = { startActivityAndWait() },
|
||||
)
|
||||
|
||||
@Test
|
||||
fun homeDpadAndRows() = benchmarkRule.measureRepeated(
|
||||
packageName = "com.ponzischeme89.memby",
|
||||
packageName = PACKAGE_NAME,
|
||||
metrics = listOf(FrameTimingMetric()),
|
||||
compilationMode = CompilationMode.None(),
|
||||
compilationMode = CompilationMode.Partial(),
|
||||
startupMode = StartupMode.WARM,
|
||||
iterations = 3,
|
||||
iterations = 5,
|
||||
setupBlock = { startActivityAndWait() },
|
||||
measureBlock = { exerciseHome() },
|
||||
)
|
||||
@@ -44,4 +55,8 @@ class HomeBenchmark {
|
||||
device.pressKeyCode(android.view.KeyEvent.KEYCODE_DPAD_RIGHT)
|
||||
device.waitForIdle()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PACKAGE_NAME = "com.ponzischeme89.memby"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user