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

Add a starting point for benchmarks #11

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions app-watch-benchmark/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
54 changes: 54 additions & 0 deletions app-watch-benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@file:Suppress("UnstableApiUsage")

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

android {
namespace = "com.louiscad.composeoclockplayground.benchmark"

defaultConfig {
minSdk = 30
compileSdk = 34
targetSdk = 34

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments["androidx.benchmark.profiling.mode"] = "none"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

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.
val benchmark by creating {
isDebuggable = false
signingConfig = signingConfigs.getByName("debug")
matchingFallbacks.add("release")
}
}

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

dependencies {
implementation {
platform(AndroidX.compose.bom)
AndroidX.compose.ui.testJunit4()
AndroidX.test.runner()
AndroidX.test.rules()
AndroidX.test.uiAutomator()
AndroidX.benchmark.macroJunit4()
}
}

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

<uses-feature android:name="android.hardware.type.watch" />

<queries>
<package android:name="com.louiscad.composeoclockplayground" />
</queries>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.louiscad.composeoclockplayground.benchmark

import android.app.UiAutomation
import android.content.ComponentName
import android.view.KeyEvent
import androidx.test.uiautomator.UiDevice

fun UiDevice.startWatchface(watchfaceName: ComponentName) {
// From https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:deploy/deployer/src/main/java/com/android/tools/deployer/model/component/WatchFace.java
val result =
executeShellCommand("am broadcast -a com.google.android.wearable.app.DEBUG_SURFACE --es operation set-watchface --ecn component ${watchfaceName.flattenToString()}")

// TODO error checking
}

fun UiDevice.currentWatchface(): String {
return executeShellCommand("am broadcast -a com.google.android.wearable.app.DEBUG_SURFACE --es operation current-watchface")
}

val DefaultWatchFace = ComponentName(
"com.google.android.wearable.sysui",
"com.google.android.clockwork.sysui.experiences.defaultwatchface.DefaultWatchFace"
)

inline fun UiAutomation.withShellPermission(block: () -> Unit) {
adoptShellPermissionIdentity()

try {
block()
} finally {
dropShellPermissionIdentity()
}
}

fun UiDevice.pressSleep() {
pressKeyCode(KeyEvent.KEYCODE_SLEEP)
}

fun UiDevice.pressWakeup() {
pressKeyCode(KeyEvent.KEYCODE_WAKEUP)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@file:OptIn(ExperimentalMetricApi::class, ExperimentalPerfettoTraceProcessorApi::class)

package com.louiscad.composeoclockplayground.benchmark

import androidx.benchmark.macro.ExperimentalMetricApi
import androidx.benchmark.macro.TraceMetric
import androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi
import androidx.benchmark.perfetto.PerfettoTraceProcessor

object IgnoredMetric : TraceMetric() {
override fun getResult(
captureInfo: CaptureInfo,
traceSession: PerfettoTraceProcessor.Session
): List<Measurement> {
return listOf(Measurement("ignored", 0.0))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.louiscad.composeoclockplayground.benchmark

import android.content.ComponentName

class SampleWatchfaceBenchmark : WatchFaceBenchmark() {
override val watchfaceComponent: ComponentName = ComponentName(
PACKAGE_NAME,
"com.louiscad.composeoclockplayground.SampleWatchFaceService"
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.louiscad.composeoclockplayground.benchmark

import android.app.Instrumentation
import android.app.UiAutomation
import android.content.ComponentName
import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import org.junit.Before
import org.junit.Rule
import org.junit.Test

abstract class WatchFaceBenchmark {
private lateinit var instrumentation: Instrumentation
private lateinit var uiAutomation: UiAutomation
private lateinit var device: UiDevice

abstract val watchfaceComponent: ComponentName

@get:Rule
val benchmarkRule = MacrobenchmarkRule()

@Before
fun setup() {
instrumentation = InstrumentationRegistry.getInstrumentation()
uiAutomation = instrumentation.uiAutomation
device = UiDevice.getInstance(instrumentation)
}

@Before
fun after() {
device.wakeUp()
device.startWatchface(DefaultWatchFace)
}

@Test
fun oneMinuteInteractive() = benchmarkRule.measureRepeated(
packageName = watchfaceComponent.packageName,
metrics = metrics(),
compilationMode = CompilationMode.Partial(),
// TODO bump to multiple
iterations = 1,
startupMode = StartupMode.WARM,
setupBlock = {
device.startWatchface(watchfaceComponent)
repeat(5) {
println("Sleep in setupBlock $it")
Thread.sleep(1000)
}

println("Waking Up")
device.wakeUp()
},
) {
repeat(10) {
device.wakeUp()
println("Sleep in test $it")
Thread.sleep(6000)
}
}

// TODO add interesting watchface metrics
open fun metrics() = listOf(IgnoredMetric)

companion object {
val PACKAGE_NAME = "com.louiscad.composeoclockplayground"
}
}


3 changes: 3 additions & 0 deletions app-watch/proguard-benchmark.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# When generating the baseline profile we want the proper names of
# the methods and classes
-dontobfuscate
8 changes: 8 additions & 0 deletions convention-plugins/src/main/kotlin/android-app.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ android {
"proguard-rules.pro"
)
}
create("benchmark") {
initWith(buildTypes.getByName("release"))
matchingFallbacks += "release"
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-benchmark.pro"
)
}
}
kotlinOptions {
freeCompilerArgs += "-opt-in=splitties.experimental.ExperimentalSplittiesApi"
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ include {
"app-phone"()
"app-watch"()
"shared"()
"app-watch-benchmark"()
}
9 changes: 9 additions & 0 deletions versions.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ version.androidx.activity=1.8.2
## # available=1.9.0-alpha01
## # available=1.9.0-alpha02

version.androidx.benchmark=1.3.0-alpha01

version.androidx.compose=2023.10.01

version.androidx.compose.compiler=1.5.8
Expand Down Expand Up @@ -72,6 +74,11 @@ version.androidx.test.ext.junit=1.1.5
## # available=1.2.0-alpha02
## # available=1.2.0-alpha03

version.androidx.test.rules=1.5.0
## # available=1.6.0-alpha01
## # available=1.6.0-alpha02
## # available=1.6.0-alpha03

version.androidx.test.runner=1.5.2
## # available=1.5.3-alpha01
## # available=1.6.0-alpha01
Expand All @@ -81,6 +88,8 @@ version.androidx.test.runner=1.5.2
## # available=1.6.0-alpha05
## # available=1.6.0-alpha06

version.androidx.test.uiautomator=2.3.0

version.androidx.wear.compose=1.3.0
## # available=1.4.0-alpha01

Expand Down
Loading