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 macrobenchmarks #5100

Merged
merged 2 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 13 additions & 3 deletions benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@
This is a standalone Android Studio project to benchmark performance. While the root `apollo-kotlin` project can be
opened with IntelliJ, this one requires Android Studio.

It's not a composite build so it's easy to swap the Apollo version and to workaround interop issues between AGP and multiplatform builds.
It's not a composite build to workaround interop issues between AGP and multiplatform builds.
Use `publishAllPublicationsToPluginTestRepository` from `apollo-kotlin` to use the artifacts from the current version.

## Running the tests

You can run the tests from Android Studio by clicking the "run" icon in the gutter next to `class Benchmark`. This will
print the results in the `Run` window of Android Studio
You can run the tests from Android Studio by clicking the "run" icon in the gutter. This will
print the results in the `Run` window of Android Studio.

For the command line, use:

```
# macrobenchmarks
./gradlew -p benchmark :macrobenchmark:connectedBenchmarkAndroidTest

# microbenchmarks
./gradlew -p benchmark :microbenchmark:benchmarkReport
```

## Inspiration

Expand Down
7 changes: 1 addition & 6 deletions benchmark/app/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
A small empty apk to make Firebase Test Labs happy because it requires an 'app' APK:
A small app to monitor start performance and also to pass as an (unused) app apk to Firebase test labs for microbenchmarks.

```
gcloud --project apollo-kotlin firebase test android run --type=instrumentation
--device model=Pixel3,locale=en,orientation=portrait --test=benchmark/build/outputs/apk/androidTest/release/benchmark-release-androidTest.apk
--app benchmark/app/build/outputs/apk/release/app-release-unsigned.apk
```
82 changes: 75 additions & 7 deletions benchmark/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
apply(plugin = "com.android.application")
apply(plugin = "org.jetbrains.kotlin.android")
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile

configure<com.android.build.gradle.AppExtension> {
namespace = "com.apollographql.apollo3.emptyapp"
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.apollographql.apollo3")
}

android {
namespace = "app_under_test"

compileSdkVersion(libs.versions.android.sdkversion.compile.get().toInt())
compileSdk = libs.versions.android.sdkversion.compilebenchmark.get().toInt()

defaultConfig {
minSdk = libs.versions.android.sdkversion.min.get().toInt()
minSdk = libs.versions.android.sdkversion.compose.min.get().toInt()
targetSdk = libs.versions.android.sdkversion.target.get().toInt()

val debugSigningConfig = signingConfigs.getByName("debug").apply {
// This is all public. This app is only an empty shell to make Firebase happy because it requires an 'app' APK.
keyAlias = "key"
keyPassword = "apollo"
storeFile = file("keystore")
Expand All @@ -21,7 +26,70 @@ configure<com.android.build.gradle.AppExtension> {
buildTypes {
getByName("release") {
signingConfig = debugSigningConfig
isMinifyEnabled = true
}
create("benchmark") {
initWith(getByName("release"))
signingConfig = debugSigningConfig
isMinifyEnabled = true
isDebuggable = false
applicationIdSuffix = ".benchmark"
proguardFiles("rules.pro")
}
}
}

@Suppress("UnstableApiUsage")
buildFeatures {
compose = true
}

composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
}
}

dependencies {
implementation("com.apollographql.apollo3:apollo-runtime")
implementation("com.apollographql.apollo3:apollo-normalized-cache")
implementation(libs.compose.runtime)
implementation(libs.compose.ui)
implementation(libs.androidx.profileinstaller)
implementation(libs.androidx.activity)
}

tasks.withType<KotlinJvmCompile>().configureEach {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_1_8)
}
}

val generateQueries: Provider<Task> = tasks.register("generateQueries") {
inputs.file("src/main/graphql/api/operations.graphql")
.withPropertyName("inputGraphQLFile")
.withPathSensitivity(PathSensitivity.RELATIVE)
outputs.dir(buildDir.resolve("generated/graphql/api"))
.withPropertyName("outputDir")

doLast {
val inputDocument = inputs.files.singleFile.readText()
val outputDir = outputs.files.singleFile
outputDir.deleteRecursively()
outputDir.mkdirs()

repeat(10) {
outputDir.resolve("operation$it.graphql").writeText(
inputDocument.replace("#SuffixPlaceholder", it.toString())
)
}
}
}
apollo {
service("api") {
packageName.set("com.apollographql.sample")
//generateCompiledField.set(false)
addTypename.set("always")
srcDir(generateQueries)
schemaFile.set(file("src/main/graphql/api/schema.graphqls"))
}
}
10 changes: 10 additions & 0 deletions benchmark/app/rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Obsfuscation must be disabled for the build variant that generates Baseline Profile, otherwise
# wrong symbols would be generated. The generated Baseline Profile will be properly applied when generated
# without obfuscation and your app is being obfuscated.
-dontobfuscate

# Annotations referenced by androidx.benchmark and androidx.test
-dontwarn androidx.core.os.BuildCompat$PrereleaseSdkCheck
-dontwarn androidx.core.os.BuildCompat
-dontwarn com.google.errorprone.annotations.CanIgnoreReturnValue
-dontwarn com.google.errorprone.annotations.MustBeClosed
20 changes: 19 additions & 1 deletion benchmark/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="INTERNET" />
<!-- Storage permissions required to run the macrobenchmark on my Pixel 3, not sure why -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application >
<profileable android:shell="true"
tools:targetApi="q" />

<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
42 changes: 42 additions & 0 deletions benchmark/app/src/main/graphql/api/operations.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
query GetResponse#SuffixPlaceholder
{
users
{
_id
index
guid
is_active
balance
picture
age
eye_color
name {
first
last
}
company
email
phone
address
about
registered
latitude
longitude
tags
range
friends {
id
name
}
images {
id
format
url
description
}
greeting
favorite_fruit
}
status
is_real_json
}
48 changes: 48 additions & 0 deletions benchmark/app/src/main/graphql/api/schema.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
type Query {
users(param: String): [User!]!
status: String!
is_real_json: Boolean!
}

type User {
_id: String!,
index: Int!,
guid: String!,
is_active: Boolean!,
balance: String!,
picture: String!,
age: Int!,
name: Name!,
company: String!,
email: String!,
address: String!,
about: String!,
registered: String!,
latitude: Float!,
longitude: Float!,
tags: [String!]!,
range: [Int!]!,
friends: [Friend!]!,
images: [Image!]!,
greeting: String!,
favorite_fruit: String!,
eye_color: String!,
phone: String!,
}

type Name {
first: String!,
last: String!,
}

type Friend {
id: Int!,
name: String!,
}

type Image {
id: String!,
format: String!,
url: String!,
description: String!,
}
Loading
Loading