Skip to content

Commit f62053f

Browse files
committed
Switch to using macrobenchmark for engine db benchmarks
1 parent 553a902 commit f62053f

File tree

19 files changed

+165
-44
lines changed

19 files changed

+165
-44
lines changed

build.gradle.kts

+2-5
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,8 @@ allprojects {
2727
}
2828

2929
subprojects {
30-
// We have some empty folders like the :contrib root folder, which Gradle recognizes as projects.
31-
// Don't configure plugins for those folders.
32-
if (project.buildFile.exists()) {
33-
configureLicensee()
34-
}
30+
applyLicenseeConfig()
31+
3532
tasks.withType(Test::class.java).configureEach {
3633
maxParallelForks = 1
3734
if (project.providers.environmentVariable("GITHUB_ACTIONS").isPresent) {

buildSrc/src/main/kotlin/LicenseeConfig.kt

+16-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,22 @@ import org.gradle.api.Project
1818
import org.gradle.kotlin.dsl.apply
1919
import org.gradle.kotlin.dsl.configure
2020

21-
fun Project.configureLicensee() {
21+
fun Project.applyLicenseeConfig() {
22+
// Skip project "demo:benchmark" since it's a "com.android.test" project which is not compatible with Licensee
23+
if (project.path == ":demo:macrobenchmark") {
24+
return
25+
}
26+
27+
// We have some empty folders like the :contrib root folder, which Gradle recognizes as projects.
28+
// Don't configure plugins for those folders.
29+
if (!project.buildFile.exists()) {
30+
return
31+
}
32+
33+
configureLicensee()
34+
}
35+
36+
private fun Project.configureLicensee() {
2237
apply(plugin = "app.cash.licensee")
2338
configure<app.cash.licensee.LicenseeExtension> {
2439
allow("Apache-2.0")

buildSrc/src/main/kotlin/Plugins.kt

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ object Plugins {
2929
const val navSafeArgs = "androidx.navigation.safeargs.kotlin"
3030
const val ruler = "com.spotify.ruler"
3131
const val spotless = "com.diffplug.spotless"
32+
const val androidTest = "com.android.test"
3233
}
3334

3435
// classpath plugins

buildSrc/src/main/kotlin/Sdk.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
object Sdk {
1818
const val COMPILE_SDK = 36
19-
const val TARGET_SDK = 31
19+
const val TARGET_SDK = 36
2020

2121
// Engine and SDC must support API 24.
2222
// Remove desugaring when upgrading it to 26.

demo/.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
/build
1+
/build
2+
/src/benchmark/assets/bulk_data
3+
/synthea

demo/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## Benchmarking
2+
3+
# How to run the benchmark with Synthea for different population sizes
4+
1. Change into the project's root directory
5+
2. Run script to generate population data `sh engine/benchmark/generate_synthea.sh [<population-size>]`
6+
```bash
7+
# For population of 100 patients
8+
sh engine/benchmark/generate_synthea.sh 100
9+
```
10+
3. Run benchmarks
11+
```bash
12+
./gradlew :engine:benchmark:connectedReleaseAndroidTest
13+
```

demo/build.gradle.kts

+8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ android {
2222
isMinifyEnabled = true
2323
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
2424
}
25+
create("benchmark") {
26+
initWith(buildTypes.getByName("release"))
27+
applicationIdSuffix = ".benchmark"
28+
signingConfig = signingConfigs.getByName("debug")
29+
matchingFallbacks += listOf("release")
30+
isDebuggable = false
31+
}
2532
}
2633
buildFeatures {
2734
buildConfig = true
@@ -64,6 +71,7 @@ dependencies {
6471
exclude(group = "com.google.android.fhir", module = "engine")
6572
}
6673
implementation(project(":engine"))
74+
"benchmarkImplementation"(libs.androidx.profileinstaller)
6775

6876
testImplementation(libs.junit)
6977
}

engine/benchmark/generate_synthea.sh renamed to demo/generate_synthea.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pushd "$SYNTHEA_DIR" || exit
1616
popd || exit
1717

1818
# Move to benchmark assets dir
19-
mkdir -p "$GIT_ROOT_DIR"/engine/benchmark/src/androidTest/assets/bulk_data
20-
cp "$SYNTHEA_DIR"/output/fhir/Patient*.ndjson "$GIT_ROOT_DIR"/engine/benchmark/src/androidTest/assets/bulk_data
19+
mkdir -p "$GIT_ROOT_DIR"/demo/src/benchmark/assets/bulk_data
20+
cp "$SYNTHEA_DIR"/output/fhir/Patient*.ndjson "$GIT_ROOT_DIR"/demo/src/benchmark/assets/bulk_data
2121

2222
rm -rf "$SYNTHEA_DIR"/output

demo/macrobenchmark/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

demo/macrobenchmark/build.gradle.kts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
plugins {
2+
id(Plugins.BuildPlugins.androidTest)
3+
id(Plugins.BuildPlugins.kotlinAndroid)
4+
}
5+
6+
android {
7+
namespace = "com.google.android.fhir.demo.macrobenchmark"
8+
compileSdk = Sdk.COMPILE_SDK
9+
10+
defaultConfig {
11+
minSdk = Sdk.MIN_SDK
12+
targetSdk = Sdk.TARGET_SDK
13+
testInstrumentationRunner = Dependencies.androidJunitRunner
14+
}
15+
16+
buildTypes {
17+
// This benchmark buildType is used for benchmarking, and should function like your
18+
// release build (for example, with minification on). It"s signed with a debug key
19+
// for easy local/CI testing.
20+
create("benchmark") {
21+
isDebuggable = true
22+
signingConfig = getByName("debug").signingConfig
23+
matchingFallbacks += listOf("release")
24+
}
25+
}
26+
27+
targetProjectPath = ":demo"
28+
@Suppress("UnstableApiUsage")
29+
experimentalProperties["android.experimental.self-instrumenting"] = true
30+
31+
kotlin { jvmToolchain(11) }
32+
}
33+
34+
dependencies {
35+
implementation(libs.androidx.test.ext.junit)
36+
implementation(libs.androidx.test.espresso.core)
37+
implementation(libs.androidx.uiautomator)
38+
implementation(libs.androidx.benchmark.macro.junit4)
39+
}
40+
41+
androidComponents { beforeVariants(selector().all()) { it.enable = it.buildType == "benchmark" } }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<manifest />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.android.fhir.demo.macrobenchmark
18+
19+
import androidx.benchmark.macro.StartupMode
20+
import androidx.benchmark.macro.StartupTimingMetric
21+
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
22+
import androidx.test.ext.junit.runners.AndroidJUnit4
23+
import org.junit.Rule
24+
import org.junit.Test
25+
import org.junit.runner.RunWith
26+
27+
/**
28+
* This is an example startup benchmark.
29+
*
30+
* It navigates to the device's home screen, and launches the default activity.
31+
*
32+
* Before running this benchmark:
33+
* 1) switch your app's active build variant in the Studio (affects Studio runs only)
34+
* 2) add `<profileable android:shell="true" />` to your app's manifest, within the `<application>`
35+
* tag
36+
*
37+
* Run this benchmark from Studio to see startup measurements, and captured system traces for
38+
* investigating your app's performance.
39+
*/
40+
@RunWith(AndroidJUnit4::class)
41+
class ExampleStartupBenchmark {
42+
@get:Rule val benchmarkRule = MacrobenchmarkRule()
43+
44+
@Test
45+
fun startup() =
46+
benchmarkRule.measureRepeated(
47+
packageName = "com.google.android.fhir.demo.benchmark",
48+
metrics = listOf(StartupTimingMetric()),
49+
iterations = 3,
50+
startupMode = StartupMode.COLD,
51+
) {
52+
pressHome()
53+
startActivityAndWait()
54+
}
55+
}

demo/src/benchmark/assets/.keep

Whitespace-only changes.

demo/src/main/AndroidManifest.xml

+9-17
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
11
<?xml version="1.0" encoding="utf-8" ?>
2-
<!--
3-
Copyright 2020 Google LLC
2+
<manifest
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
>
46

5-
Licensed under the Apache License, Version 2.0 (the "License");
6-
you may not use this file except in compliance with the License.
7-
You may obtain a copy of the License at
8-
9-
http://www.apache.org/licenses/LICENSE-2.0
10-
11-
Unless required by applicable law or agreed to in writing, software
12-
distributed under the License is distributed on an "AS IS" BASIS,
13-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14-
See the License for the specific language governing permissions and
15-
limitations under the License.
16-
-->
17-
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
7+
<uses-permission android:name="android.permission.INTERNET" />
188

199
<application
2010
android:name="com.google.android.fhir.demo.FhirApplication"
@@ -26,11 +16,13 @@
2616
android:supportsRtl="true"
2717
android:theme="@style/AppTheme"
2818
>
19+
<profileable android:shell="true" tools:targetApi="29" />
20+
2921
<activity
3022
android:name="com.google.android.fhir.demo.MainActivity"
23+
android:exported="true"
3124
android:label="@string/app_name"
3225
android:windowSoftInputMode="adjustResize"
33-
android:exported="true"
3426
>
3527
<intent-filter>
3628
<action android:name="android.intent.action.MAIN" />
@@ -39,5 +31,5 @@
3931
</intent-filter>
4032
</activity>
4133
</application>
42-
<uses-permission android:name="android.permission.INTERNET" />
34+
4335
</manifest>

engine/benchmark/.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
11
/build
2-
/synthea
3-
/src/androidTest/assets/bulk_data

engine/benchmark/README.md

-12
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,3 @@ Alternatively, from the command line, run the connectedCheck to run all of the t
3232
```
3333

3434
In this case, results will be saved to the `outputs/androidTest-results/connected/<device>/test-result.pb`. To visualize on Android Studio, click Run / Import Tests From File and find the `.pb` file
35-
36-
# How to run the benchmark with Synthea for different population sizes
37-
1. Change into the project's root directory
38-
2. Run script to generate population data `sh engine/benchmark/generate_synthea.sh [<population-size>]`
39-
```bash
40-
# For population of 100 patients
41-
sh engine/benchmark/generate_synthea.sh 100
42-
```
43-
3. Run benchmarks
44-
```bash
45-
./gradlew :engine:benchmark:connectedReleaseAndroidTest
46-
```

engine/benchmark/build.gradle.kts

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ android {
1111
minSdk = Sdk.MIN_SDK
1212
testInstrumentationRunner = Dependencies.androidBenchmarkRunner
1313
// Enable measuring on an emulator, or devices with low battery
14-
// testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "EMULATOR,LOW-BATTERY"
14+
// testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] =
15+
// "EMULATOR,LOW-BATTERY"
1516
}
1617

1718
testBuildType = "release"

gradle/libs.versions.toml

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ androidx-activity = "1.7.2"
88
androidx-appcompat = "1.6.1"
99
androidx-arch-core = "2.2.0"
1010
androidx-benchmark = "1.3.4"
11+
androidx-benchmark-macro = "1.3.4"
1112
androidx-constraintlayout = "2.1.4"
1213
androidx-core = "1.10.1"
1314
androidx-datastore = "1.0.0"
1415
androidx-espresso = "3.5.1"
1516
androidx-fragment = "1.6.0"
1617
androidx-lifecycle = "2.6.1"
1718
androidx-navigation = "2.6.0"
19+
androidx-profilerinstaller = "1.4.1"
1820
androidx-recyclerview = "1.3.2"
1921
androidx-room = "2.5.2"
2022
androidx-sqlite = "2.3.1"
@@ -29,9 +31,10 @@ kotlin-stdlib = "1.9.22"
2931
kotlin-test = "1.9.22"
3032
kotlinx-coroutines = "1.8.1"
3133
logback-android = "3.0.0"
34+
material = "1.9.0"
3235
opencds-cqf-fhir = "3.8.0"
3336
truth = "1.1.5"
34-
material = "1.9.0"
37+
uiautomator = "2.3.0"
3538

3639
[libraries]
3740
android-fhir-common = { module = "com.google.android.fhir:common", version.ref = "android-fhir-common" }
@@ -41,6 +44,7 @@ androidx-activity = { module = "androidx.activity:activity", version.ref = "andr
4144
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
4245
androidx-arch-core-testing = { module = "androidx.arch.core:core-testing", version.ref = "androidx-arch-core" }
4346
androidx-benchmark-junit4 = { module = "androidx.benchmark:benchmark-junit4", version.ref = "androidx-benchmark" }
47+
androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidx-benchmark-macro" }
4448
androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintlayout" }
4549
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
4650
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" }
@@ -51,6 +55,7 @@ androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime",
5155
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
5256
androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "androidx-navigation" }
5357
androidx-navigation-ui = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "androidx-navigation" }
58+
androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "androidx-profilerinstaller" }
5459
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerview" }
5560
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" }
5661
androidx-room-room = { module = "androidx.room:room-ktx", version.ref = "androidx-room" }
@@ -64,6 +69,7 @@ androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "a
6469
androidx-test-ext-junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "androidx-test-ext-junit" }
6570
androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test-rules" }
6671
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" }
72+
androidx-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "uiautomator" }
6773
androidx-work-runtime = { module = "androidx.work:work-runtime-ktx", version.ref = "androidx-work" }
6874
androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "androidx-work" }
6975
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
@@ -75,11 +81,11 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c
7581
kotlinx-coroutines-playservices = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines" }
7682
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
7783
logback-android = { module = "com.github.tony19:logback-android", version.ref = "logback-android" }
84+
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
7885
opencds-cqf-fhir-cr = { module = "org.opencds.cqf.fhir:cqf-fhir-cr", version.ref = "opencds-cqf-fhir" }
7986
opencds-cqf-fhir-jackson = { module = "org.opencds.cqf.fhir:cqf-fhir-jackson", version.ref = "opencds-cqf-fhir" }
8087
opencds-cqf-fhir-utility = { module = "org.opencds.cqf.fhir:cqf-fhir-utility", version.ref = "opencds-cqf-fhir" }
8188
truth = { module = "com.google.truth:truth", version.ref = "truth" }
82-
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
8389

8490
[bundles]
8591

settings.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,5 @@ include(":workflow:benchmark")
6868
include(":engine:benchmark")
6969

7070
include(":workflow_demo")
71+
72+
include(":demo:macrobenchmark")

0 commit comments

Comments
 (0)