diff --git a/app/build.gradle.kts b/app/build.gradle.kts index eb61be1c799..3fe03d4ad2c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -302,7 +302,6 @@ dependencies { implementation(libs.aboutLibraries.core) implementation(libs.aboutLibraries.compose.core) - implementation(libs.aboutLibraries.compose.m3) implementation(libs.compose.qr.code) implementation(libs.enterprise.feedback) diff --git a/benchmark/README.md b/benchmark/README.md index b5e772dcd1c..557d24c4d38 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -1,22 +1,47 @@ ## App Benchmarks -This is the benchmark project for the Android App. To run the benchmarks, the following prerequisites must be met: +This module now uses `com.android.test` and targets `:app` directly. Gradle builds the tested app APK and the benchmark test APK together, installs both on the connected device, and runs the selected benchmark. You do not need to manually assemble and install the app APK first. -- A real Android device is used for testing (emulators are not supported). -- There is a beta benchmark build of the app installed on the device. -- If using the test with login, make sure the max amount of devices registered to the account is not exceeded. +## Prerequisites -### Building the benchmark APK -To build the benchmark APK, use the following command: +- Use a real Android device. Do not use an emulator for macrobenchmarks. +- Connect exactly one Android device. +- If running a login benchmark, make sure the benchmark account can still register a device. +- The current setup is aimed at the `prod` flavor with the `benchmark` build type. + +## Run a benchmark + +Run the startup benchmark without login: + +```shell +./gradlew :benchmark:connectedProdBenchmarkBenchmarkAndroidTest \ + -Pandroid.testInstrumentationRunnerArguments.class=com.wire.benchmark.StartupBenchmark#startUpWithoutBaselineProfiler \ + -Pandroid.testInstrumentationRunnerArguments.TARGET_PACKAGE="com.wire" +``` + +Run the startup benchmark with login: ```shell -./gradlew clean assembleBetaBenchmark +./gradlew :benchmark:connectedProdBenchmarkBenchmarkAndroidTest \ + -Pandroid.testInstrumentationRunnerArguments.class=com.wire.benchmark.StartupBenchmarkWithLogin#startUpWithoutBaselineProfiler \ + -Pandroid.testInstrumentationRunnerArguments.TARGET_PACKAGE="com.wire" \ + -Pandroid.testInstrumentationRunnerArguments.EMAIL="$EMAIL" \ + -Pandroid.testInstrumentationRunnerArguments.PASSWORD="$PASSWORD" ``` -### Running the benchmarks -To run the benchmarks, use the following command: +Run the baseline profile generator: + ```shell -./gradlew :benchmark:connectedDebugAndroidTest +./gradlew :benchmark:connectedProdBenchmarkBenchmarkAndroidTest \ + -Pandroid.testInstrumentationRunnerArguments.class=com.wire.benchmark.BaselineGenerator \ + -Pandroid.testInstrumentationRunnerArguments.TARGET_PACKAGE="com.wire" \ + -Pandroid.testInstrumentationRunnerArguments.EMAIL="$EMAIL" \ + -Pandroid.testInstrumentationRunnerArguments.PASSWORD="$PASSWORD" ``` -Alternatively, you can run the benchmarks directly from Android Studio by selecting the `benchmark` module and running the `connectedDebugAndroidTest` configuration. +## Notes + +- The benchmark module reads `TARGET_PACKAGE`, `EMAIL`, and `PASSWORD` from instrumentation runner arguments. +- The app APK is produced from `:app` automatically through `targetProjectPath = ":app"`. +- Benchmark output is written under `benchmark/build/outputs/connected_android_test_additional_output/`. +- The committed pre-profile reference snapshot lives under `benchmark/baselines/`. diff --git a/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter000_2026-05-12-17-15-22.perfetto-trace b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter000_2026-05-12-17-15-22.perfetto-trace new file mode 100644 index 00000000000..33d04720551 Binary files /dev/null and b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter000_2026-05-12-17-15-22.perfetto-trace differ diff --git a/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter001_2026-05-12-17-15-42.perfetto-trace b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter001_2026-05-12-17-15-42.perfetto-trace new file mode 100644 index 00000000000..750c4af36af Binary files /dev/null and b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter001_2026-05-12-17-15-42.perfetto-trace differ diff --git a/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter002_2026-05-12-17-16-03.perfetto-trace b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter002_2026-05-12-17-16-03.perfetto-trace new file mode 100644 index 00000000000..9904f99bc78 Binary files /dev/null and b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter002_2026-05-12-17-16-03.perfetto-trace differ diff --git a/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter003_2026-05-12-17-16-22.perfetto-trace b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter003_2026-05-12-17-16-22.perfetto-trace new file mode 100644 index 00000000000..b55afc1446f Binary files /dev/null and b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter003_2026-05-12-17-16-22.perfetto-trace differ diff --git a/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter004_2026-05-12-17-16-43.perfetto-trace b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter004_2026-05-12-17-16-43.perfetto-trace new file mode 100644 index 00000000000..b83f03b9919 Binary files /dev/null and b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter004_2026-05-12-17-16-43.perfetto-trace differ diff --git a/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/additionaltestoutput.benchmark.message_com.wire.benchmark.StartupBenchmarkWithLogin.startUpWithoutBaselineProfiler.txt b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/additionaltestoutput.benchmark.message_com.wire.benchmark.StartupBenchmarkWithLogin.startUpWithoutBaselineProfiler.txt new file mode 100644 index 00000000000..7d38d4ca360 --- /dev/null +++ b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/additionaltestoutput.benchmark.message_com.wire.benchmark.StartupBenchmarkWithLogin.startUpWithoutBaselineProfiler.txt @@ -0,0 +1,6 @@ +StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler +frameCount [min 9.0](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter004_2026-05-12-17-16-43.perfetto-trace), [median 15.0](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter002_2026-05-12-17-16-03.perfetto-trace), [max 17.0](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter000_2026-05-12-17-15-22.perfetto-trace) +timeToInitialDisplayMs [min 1,723.1](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter001_2026-05-12-17-15-42.perfetto-trace), [median 2,599.7](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter002_2026-05-12-17-16-03.perfetto-trace), [max 2,952.0](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter003_2026-05-12-17-16-22.perfetto-trace) +frameDurationCpuMs P50 20.8, P90 162.3, P95 319.4, P99 531.3 +frameOverrunMs P50 17.5, P90 395.3, P95 446.9, P99 983.0 +Traces: Iteration [0](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter000_2026-05-12-17-15-22.perfetto-trace) [1](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter001_2026-05-12-17-15-42.perfetto-trace) [2](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter002_2026-05-12-17-16-03.perfetto-trace) [3](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter003_2026-05-12-17-16-22.perfetto-trace) [4](file://StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter004_2026-05-12-17-16-43.perfetto-trace) diff --git a/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/com.wire.benchmark.test-benchmarkData.json b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/com.wire.benchmark.test-benchmarkData.json new file mode 100644 index 00000000000..bacb3c84d00 --- /dev/null +++ b/benchmark/baselines/2026-05-12-pre-profile/debugAndroidTest/connected/device/com.wire.benchmark.test-benchmarkData.json @@ -0,0 +1,264 @@ +{ + "context": { + "build": { + "brand": "samsung", + "device": "beyond1", + "fingerprint": "samsung/beyond1lteeea/beyond1:12/SP1A.210812.016/G973FXXSGHWC2:user/release-keys", + "id": "SP1A.210812.016", + "model": "SM-G973F", + "type": "user", + "version": { + "codename": "REL", + "sdk": 31 + } + }, + "cpuCoreCount": 8, + "cpuLocked": false, + "cpuMaxFreqHz": 2730000000, + "memTotalBytes": 7780278272, + "sustainedPerformanceModeEnabled": false, + "artMainlineVersion": -1, + "osCodenameAbbreviated": "S", + "compilationMode": "run-from-apk" + }, + "benchmarks": [ + { + "name": "startUpWithoutBaselineProfiler", + "params": {}, + "className": "com.wire.benchmark.StartupBenchmarkWithLogin", + "totalRunTimeNs": 115069511341, + "metrics": { + "frameCount": { + "minimum": 9.0, + "maximum": 17.0, + "median": 15.0, + "runs": [ + 17.0, + 15.0, + 15.0, + 13.0, + 9.0 + ] + }, + "timeToInitialDisplayMs": { + "minimum": 1723.123999, + "maximum": 2951.96419, + "median": 2599.657806, + "runs": [ + 2500.532268, + 1723.123999, + 2647.364883, + 2951.96419, + 2599.657806 + ] + } + }, + "sampledMetrics": { + "frameDurationCpuMs": { + "P50": 20.813884, + "P90": 162.27387720000007, + "P95": 319.4071384, + "P99": 531.255910439996, + "runs": [ + [ + 325.692769, + 68.380077, + 54.908615, + 15.018462, + 11.697115, + 7.781462, + 7.829269, + 132.79523, + 29.866423, + 7.719462, + 5.551346, + 9.040462, + 9.100384, + 6.647154, + 7.282462, + 7.249269, + 7.858154 + ], + [ + 319.750846, + 15.858769, + 8.890115, + 11.328924, + 9.437308, + 9.278539, + 10.240615, + 6.429269, + 9.088039, + 10.856538, + 8.113154, + 931.652961, + 176.019846, + 20.749231, + 15.590192 + ], + [ + 318.891577, + 65.248269, + 89.330538, + 14.030192, + 12.652461, + 158.837385, + 37.513039, + 13.484423, + 16.567615, + 25.585154, + 24.468154, + 24.952269, + 23.125193, + 24.475154, + 24.199346 + ], + [ + 312.659154, + 53.641385, + 49.1325, + 8.453308, + 8.755538, + 100.812577, + 27.346615, + 20.813884, + 22.833692, + 14.436769, + 21.239885, + 25.688616, + 23.515847 + ], + [ + 342.833769, + 90.992346, + 18.095654, + 48.197577, + 44.546385, + 31.585846, + 14.741307, + 45.167308, + 12.529961 + ] + ] + }, + "frameOverrunMs": { + "P50": 17.499871, + "P90": 395.2889302000001, + "P95": 446.9477457999998, + "P99": 982.9506878399989, + "runs": [ + [ + 915.668533, + 381.348445, + 75.854817, + 47.450116, + 1.384337, + 0.587482, + 0.436439, + 117.357932, + 106.680959, + 17.769072, + 2.453411, + 0.782926, + 0.656099, + 0.704277, + 0.752101, + 0.599516, + 0.62544 + ], + [ + 388.7575, + 311.144949, + 9.783801, + -4.239268, + -5.022047, + -5.461053, + -4.905269, + -8.621463, + -5.789697, + -4.571522, + -6.740523, + 931.727492, + 1091.799979, + 186.398294, + -0.707661 + ], + [ + 461.140845, + 354.794748, + 96.44043, + 68.131771, + -1.590777, + 144.400401, + 133.158378, + 33.844493, + 17.216292, + 17.15948, + 17.233297, + 17.398024, + 17.305488, + 18.869413, + 17.499871 + ], + [ + 425.658097, + 342.122287, + 60.08663, + 34.26431, + 0.468035, + 86.187997, + 76.439461, + 34.020423, + 17.300776, + 17.373953, + 17.18826, + 17.357145, + 17.379381 + ], + [ + 424.496833, + 421.414651, + 105.428551, + 49.438119, + 63.145233, + 16.527307, + 17.109163, + 39.768467, + 39.35054 + ] + ] + } + }, + "warmupIterations": 0, + "repeatIterations": 5, + "thermalThrottleSleepSeconds": 0, + "profilerOutputs": [ + { + "type": "PerfettoTrace", + "label": "Trace Iteration 0", + "filename": "StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter000_2026-05-12-17-15-22.perfetto-trace" + }, + { + "type": "PerfettoTrace", + "label": "Trace Iteration 1", + "filename": "StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter001_2026-05-12-17-15-42.perfetto-trace" + }, + { + "type": "PerfettoTrace", + "label": "Trace Iteration 2", + "filename": "StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter002_2026-05-12-17-16-03.perfetto-trace" + }, + { + "type": "PerfettoTrace", + "label": "Trace Iteration 3", + "filename": "StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter003_2026-05-12-17-16-22.perfetto-trace" + }, + { + "type": "PerfettoTrace", + "label": "Trace Iteration 4", + "filename": "StartupBenchmarkWithLogin_startUpWithoutBaselineProfiler_iter004_2026-05-12-17-16-43.perfetto-trace" + } + ] + } + ] +} \ No newline at end of file diff --git a/benchmark/baselines/README.md b/benchmark/baselines/README.md new file mode 100644 index 00000000000..09436c52e16 --- /dev/null +++ b/benchmark/baselines/README.md @@ -0,0 +1,35 @@ +# Baseline measurements + +The `-pre-profile/` directory is the fixed reference baseline, captured once during initial setup. +It measures the full user-facing flow (startup + login → conversation list visible) WITHOUT any baseline profile applied. + +The checked-in directory layout is intentionally device-agnostic. Use a stable leaf such as +`debugAndroidTest/connected/device/` rather than the physical handset name reported by Gradle +(for example `SM-G973F - 12`). The benchmark JSON already contains the real device metadata under +`context.build`, so renaming the folder does not lose comparability data. + +## Contents + +Each directory contains: +- `com.wire.benchmark.test-benchmarkData.json` — metrics including `timeToInitialDisplayMs.median` (cold-start latency) +- Perfetto trace files (`.perfetto-trace`) — flame graphs for profiling +- Test output logs — summary data + +## Comparison + +All refresh PRs compare their post-profile measurements against this single pre-profile baseline. +The percentage improvement is reported in the PR comment (e.g., "12% faster on cold start"). + +Example baseline metric: +```json +{ + "metrics": { + "timeToInitialDisplayMs": { + "median": 850.5, + "p95": 920.3 + } + } +} +``` + +Post-profile measurements are ephemeral (not versioned) — they are used only to calculate the improvement percentage in each refresh PR. diff --git a/benchmark/build.gradle.kts b/benchmark/build.gradle.kts index 86ea17ab96f..3fcca95709d 100644 --- a/benchmark/build.gradle.kts +++ b/benchmark/build.gradle.kts @@ -15,14 +15,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ +import flavor.FlavorDimensions +import flavor.ProductFlavors + plugins { - id(libs.plugins.android.library.get().pluginId) + id("com.android.test") + alias(libs.plugins.androidx.baselineprofile) } android { + namespace = "com.wire.benchmark" + compileSdk = 36 + defaultConfig { - minSdk = 23 - compileSdk = 36 + minSdk = 28 + targetSdk = 36 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -31,17 +38,35 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - namespace = "com.wire.benchmark" - defaultConfig.missingDimensionStrategy("contentType", "beta") + flavorDimensions += FlavorDimensions.DEFAULT + productFlavors { + ProductFlavors.all.forEach { flavor -> + create(flavor.buildName) { + dimension = flavor.dimensions + } + } + } + + targetProjectPath = ":app" + experimentalProperties["android.experimental.self-instrumenting"] = true + + buildTypes { + create("benchmark") { + isDebuggable = true + signingConfig = signingConfigs.getByName("debug") + matchingFallbacks += listOf("release", "compatrelease") + } + } +} + +baselineProfile { + useConnectedDevices = true } dependencies { - implementation(libs.androidx.core) - implementation(libs.androidx.appcompat) - implementation(libs.androidx.compose.runtime) - - testImplementation(libs.junit4) - androidTestImplementation(libs.androidx.test.extJunit) - androidTestImplementation(libs.androidx.espresso.core) - androidTestImplementation(libs.androidx.benchmark.macro.junit4) + implementation(libs.androidx.test.extJunit) + implementation(libs.androidx.espresso.core) + implementation(libs.androidx.test.uiAutomator) + implementation(libs.androidx.benchmark.macro.junit4) + implementation(libs.junit4) } diff --git a/benchmark/src/main/AndroidManifest.xml b/benchmark/src/main/AndroidManifest.xml deleted file mode 100644 index c17075661b2..00000000000 --- a/benchmark/src/main/AndroidManifest.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/benchmark/src/androidTest/java/com/wire/benchmark/BaselineGenerator.kt b/benchmark/src/main/java/com/wire/benchmark/BaselineGenerator.kt similarity index 57% rename from benchmark/src/androidTest/java/com/wire/benchmark/BaselineGenerator.kt rename to benchmark/src/main/java/com/wire/benchmark/BaselineGenerator.kt index 2a38a864362..9b5e4160ae5 100644 --- a/benchmark/src/androidTest/java/com/wire/benchmark/BaselineGenerator.kt +++ b/benchmark/src/main/java/com/wire/benchmark/BaselineGenerator.kt @@ -17,11 +17,9 @@ */ package com.wire.benchmark -import androidx.benchmark.macro.MacrobenchmarkScope import androidx.benchmark.macro.junit4.BaselineProfileRule import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.uiautomator.By -import androidx.test.uiautomator.Until +import androidx.test.platform.app.InstrumentationRegistry import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -32,34 +30,18 @@ class BaselineGenerator { @get:Rule val baselineProfileRule = BaselineProfileRule() + private val args get() = InstrumentationRegistry.getArguments() + private val targetPackage get() = args.getString("TARGET_PACKAGE", "com.wire") + private val email get() = args.getString("EMAIL").orEmpty() + private val password get() = args.getString("PASSWORD").orEmpty() + @Test fun startup() = baselineProfileRule.collect( - packageName = PACKAGE_NAME + packageName = targetPackage, + includeInStartupProfile = true, ) { pressHome() startActivityAndWait() - login() - } - - private fun MacrobenchmarkScope.login() { - device.findObject(By.res("loginButton"))?.let { - it.click() - } - device.findObject(By.res("userIdentifierInput"))?.let { - it.text = EMAIL - } - device.findObject(By.res("PasswordInput"))?.let { - it.text = PASSWORD - } - device.findObject(By.res("loginButton"))?.let { - it.click() - } - device.wait(Until.hasObject(By.text("Conversations")), 30_000) - } - - companion object { - private const val PACKAGE_NAME = "com.wire.android.internal" - private const val EMAIL = "" - private const val PASSWORD = "" + if (email.isNotEmpty() && password.isNotEmpty()) login(email, password) } } diff --git a/benchmark/src/main/java/com/wire/benchmark/LoginExt.kt b/benchmark/src/main/java/com/wire/benchmark/LoginExt.kt new file mode 100644 index 00000000000..567b6067d7d --- /dev/null +++ b/benchmark/src/main/java/com/wire/benchmark/LoginExt.kt @@ -0,0 +1,44 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.benchmark + +import androidx.benchmark.macro.MacrobenchmarkScope +import androidx.test.uiautomator.By +import androidx.test.uiautomator.Until +import kotlin.time.Duration.Companion.seconds + +/** + * Login to the app using the provided email and password. This function assumes that the app is on the login screen. + */ +fun MacrobenchmarkScope.login(email: String, password: String) { + device.findObject(By.res("userIdentifierInput"))?.text = email + device.findObject(By.res("loginButton"))?.click() + device.findObject(By.res("PasswordInput"))?.text = password + device.findObject(By.res("LoginNextButton"))?.click() + waitForAnalyticsIfPresentAndAgree() + device.wait(Until.hasObject(By.text("Conversations")), 30.seconds.inWholeMilliseconds) +} + +/** + * Wait for the analytics dialog to appear and click "Agree" if it is present. + * This function assumes that the app is on the screen where the analytics dialog may appear. + */ +fun MacrobenchmarkScope.waitForAnalyticsIfPresentAndAgree() { + device.wait(Until.hasObject(By.text("Agree")), 10.seconds.inWholeMilliseconds) + device.findObject(By.text("Agree"))?.click() +} diff --git a/benchmark/src/androidTest/java/com/wire/benchmark/StartupBenchmark.kt b/benchmark/src/main/java/com/wire/benchmark/StartupBenchmark.kt similarity index 88% rename from benchmark/src/androidTest/java/com/wire/benchmark/StartupBenchmark.kt rename to benchmark/src/main/java/com/wire/benchmark/StartupBenchmark.kt index 59904d14bdb..76067b1a473 100644 --- a/benchmark/src/androidTest/java/com/wire/benchmark/StartupBenchmark.kt +++ b/benchmark/src/main/java/com/wire/benchmark/StartupBenchmark.kt @@ -23,6 +23,7 @@ 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.platform.app.InstrumentationRegistry import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -33,6 +34,9 @@ class StartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() + private val args get() = InstrumentationRegistry.getArguments() + private val targetPackage get() = args.getString("TARGET_PACKAGE", "com.wire") + @Test fun startUpWithBaselineProfiler() { startup(CompilationMode.Partial(BaselineProfileMode.Require)) @@ -44,7 +48,7 @@ class StartupBenchmark { } private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( - packageName = PACKAGE_NAME, + packageName = targetPackage, metrics = listOf(StartupTimingMetric()), iterations = ITERATIONS, startupMode = StartupMode.COLD, @@ -55,7 +59,6 @@ class StartupBenchmark { } companion object { - private const val PACKAGE_NAME = "com.wire.android.internal" private const val ITERATIONS = 10 } } diff --git a/benchmark/src/androidTest/java/com/wire/benchmark/StartupBenchmarkWithLogin.kt b/benchmark/src/main/java/com/wire/benchmark/StartupBenchmarkWithLogin.kt similarity index 71% rename from benchmark/src/androidTest/java/com/wire/benchmark/StartupBenchmarkWithLogin.kt rename to benchmark/src/main/java/com/wire/benchmark/StartupBenchmarkWithLogin.kt index 6b6adaef3e6..77af1f438be 100644 --- a/benchmark/src/androidTest/java/com/wire/benchmark/StartupBenchmarkWithLogin.kt +++ b/benchmark/src/main/java/com/wire/benchmark/StartupBenchmarkWithLogin.kt @@ -25,16 +25,13 @@ 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 androidx.test.platform.app.InstrumentationRegistry import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith /** * This benchmark will measure the app startup when we have a valid session. - * please replace the email and password with a valid one. - * NEVER EVER PUSH your credentials into git. */ @RunWith(AndroidJUnit4::class) class StartupBenchmarkWithLogin { @@ -42,13 +39,18 @@ class StartupBenchmarkWithLogin { @get:Rule val benchmarkRule = MacrobenchmarkRule() + private val args get() = InstrumentationRegistry.getArguments() + private val targetPackage get() = args.getString("TARGET_PACKAGE", "com.wire") + private val email get() = args.getString("EMAIL").orEmpty() + private val password get() = args.getString("PASSWORD").orEmpty() + @Test fun startUpWithoutBaselineProfiler() { startup( CompilationMode.None() ) { startActivityAndWait() - login() + if (email.isNotEmpty() && password.isNotEmpty()) login(email, password) } } @@ -58,31 +60,15 @@ class StartupBenchmarkWithLogin { CompilationMode.Partial(BaselineProfileMode.Require) ) { startActivityAndWait() - login() - } - } - - private fun MacrobenchmarkScope.login() { - device.findObject(By.res("userIdentifierInput"))?.let { - it.text = EMAIL - } - device.findObject(By.res("loginButton"))?.let { - it.click() - } - device.findObject(By.res("PasswordInput"))?.let { - it.text = PASSWORD - } - device.findObject(By.res("LoginNextButton"))?.let { - it.click() + if (email.isNotEmpty() && password.isNotEmpty()) login(email, password) } - device.wait(Until.hasObject(By.text("Conversations")), 30_000) } private fun startup( compilationMode: CompilationMode, setupBlock: MacrobenchmarkScope.() -> Unit = {}, ) = benchmarkRule.measureRepeated( - packageName = PACKAGE_NAME, + packageName = targetPackage, metrics = listOf(StartupTimingMetric(), FrameTimingMetric()), iterations = ITERATIONS, startupMode = StartupMode.COLD, @@ -94,9 +80,6 @@ class StartupBenchmarkWithLogin { } companion object { - private const val PACKAGE_NAME = "com.wire.android.internal" private const val ITERATIONS = 5 - private const val EMAIL = "" - private const val PASSWORD = "" } } diff --git a/buildSrc/src/main/kotlin/scripts/variants.gradle.kts b/buildSrc/src/main/kotlin/scripts/variants.gradle.kts index 14aa2a6d76c..482035ed1e3 100644 --- a/buildSrc/src/main/kotlin/scripts/variants.gradle.kts +++ b/buildSrc/src/main/kotlin/scripts/variants.gradle.kts @@ -128,6 +128,7 @@ android { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") isDebuggable = false + isProfileable = true matchingFallbacks.add("release") signingConfig = signingConfigs.getByName("debug") } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ea998d7475..37782a50c00 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -96,7 +96,8 @@ leakCanary = "2.14" ksp = "2.3.4" # Benchmark -benchmark-macro-junit4 = "1.3.3" +benchmark-macro-junit4 = "1.4.1" +benchmark-baselineprofile-plugin = "1.5.0-alpha05" profileinstaller = "1.4.1" # Testing @@ -136,6 +137,7 @@ screenshot = { id = "com.android.compose.screenshot", version.ref = "screenshot" compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } cyclonedx = { id = "org.cyclonedx.bom", version.ref = "cyclonedx" } jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "jetbrains-compose" } +androidx-baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark-baselineprofile-plugin" } # Home-made convention plugins defined in build-logic wire-android-application = { id = "com.wire.android.application" } @@ -291,9 +293,9 @@ countly-sdk = { module = "ly.count.android:sdk", version.ref = "countly" } compose-qr-code = { module = "com.lightspark:compose-qr-code", version.ref = "compose-qr" } # Dev tools -aboutLibraries-core = { module = "com.mikepenz:aboutlibraries-core", version.ref = "aboutLibraries" } -aboutLibraries-compose-core = { module = "com.mikepenz:aboutlibraries-compose-core", version.ref = "aboutLibraries" } -aboutLibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutLibraries" } +aboutLibraries-core = { module = "com.mikepenz:aboutlibraries-core-android", version.ref = "aboutLibraries" } +aboutLibraries-compose-core = { module = "com.mikepenz:aboutlibraries-compose-core-android", version.ref = "aboutLibraries" } +aboutLibraries-compose-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3-android", version.ref = "aboutLibraries" } leakCanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakCanary" } # Testing