Skip to content

Commit 7068505

Browse files
wip got benchmark traces working
1 parent 15ecc74 commit 7068505

File tree

18 files changed

+407
-34
lines changed

18 files changed

+407
-34
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
22+
23+
-dontobfuscate
24+
25+
-ignorewarnings
26+
27+
-keepattributes *Annotation*
28+
29+
-dontnote junit.framework.**
30+
-dontnote junit.runner.**
31+
32+
-dontwarn androidx.test.**
33+
-dontwarn org.junit.**
34+
-dontwarn org.hamcrest.**
35+
-dontwarn com.squareup.javawriter.JavaWriter
36+
37+
-keepclasseswithmembers @org.junit.runner.RunWith public class *

benchmarks/compose-workflow/build.gradle.kts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,64 @@
1+
import com.rickbusarow.kgx.libsCatalog
2+
import com.rickbusarow.kgx.version
3+
import com.squareup.workflow1.buildsrc.internal.javaTarget
4+
import com.squareup.workflow1.buildsrc.internal.javaTargetVersion
5+
16
plugins {
2-
id("com.android.application")
7+
id("com.android.library")
38
id("kotlin-android")
4-
id("android-defaults")
9+
// id("android-defaults")
10+
alias(libs.plugins.androidx.benchmark)
511
alias(libs.plugins.compose.compiler)
612
}
713

814
// Note: We are not including our defaults from .buildscript as we do not need the base Workflow
915
// dependencies that those include.
1016

1117
android {
18+
compileSdk = libsCatalog.version("compileSdk").toInt()
19+
20+
compileOptions {
21+
sourceCompatibility = javaTargetVersion
22+
targetCompatibility = javaTargetVersion
23+
}
24+
25+
kotlinOptions {
26+
jvmTarget = javaTarget
27+
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
28+
}
29+
1230
defaultConfig {
31+
minSdk = 28
32+
targetSdk = libsCatalog.version("targetSdk").toInt()
33+
1334
// TODO why isn't this taking?
1435
testInstrumentationRunner = "androidx.benchmark.junit4.AndroidBenchmarkRunner"
36+
37+
// must be one of: 'None', 'StackSampling', or 'MethodTracing'
38+
testInstrumentationRunnerArguments["androidx.benchmark.profiling.mode"] = "MethodTracing"
39+
testInstrumentationRunnerArguments["androidx.benchmark.output.enable"] = "true"
1540
}
1641

42+
// buildTypes {
43+
// debug {
44+
// isDebuggable = false
45+
// isProfileable = true
46+
// }
47+
// }
48+
49+
testBuildType = "release"
50+
// testBuildType = "debug"
1751
buildTypes {
1852
debug {
19-
isDebuggable = false
53+
// Since isDebuggable can"t be modified by gradle for library modules,
54+
// it must be done in a manifest - see src/androidTest/AndroidManifest.xml
55+
isMinifyEnabled = true
56+
proguardFiles(
57+
getDefaultProguardFile("proguard-android-optimize.txt"), "benchmark-proguard-rules.pro"
58+
)
59+
}
60+
release {
61+
isDefault = true
2062
}
2163
}
2264

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<!--
6+
Important: disable debugging for accurate performance results
7+
8+
In a com.android.library project, this flag must be disabled from this
9+
manifest, as it is not possible to override this flag from Gradle.
10+
-->
11+
<application
12+
android:debuggable="false"
13+
tools:ignore="HardcodedDebugMode"
14+
tools:replace="android:debuggable">
15+
<profileable android:shell="true"/>
16+
</application>
317
</manifest>

benchmarks/compose-workflow/src/androidTest/baseline-proguard-rules.pro

Lines changed: 0 additions & 1 deletion
This file was deleted.

benchmarks/compose-workflow/src/androidTest/java/com/squareup/benchmark/composeworkflow/benchmark/ComposeWorkflowMicroBenchmark.kt

Lines changed: 148 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ package com.squareup.benchmark.composeworkflow.benchmark
44

55
import androidx.benchmark.junit4.BenchmarkRule
66
import androidx.benchmark.junit4.measureRepeated
7-
import androidx.compose.runtime.Composable
87
import androidx.test.ext.junit.runners.AndroidJUnit4
98
import com.squareup.workflow1.RuntimeConfigOptions
109
import com.squareup.workflow1.Workflow
1110
import com.squareup.workflow1.WorkflowExperimentalApi
1211
import com.squareup.workflow1.WorkflowExperimentalRuntime
13-
import com.squareup.workflow1.compose.ComposeWorkflow
1412
import com.squareup.workflow1.compose.composable
1513
import com.squareup.workflow1.compose.renderChild
1614
import com.squareup.workflow1.renderChild
@@ -26,6 +24,8 @@ import org.junit.Test
2624
import org.junit.runner.RunWith
2725
import kotlin.test.assertEquals
2826

27+
private const val MaxChildCount = 100
28+
2929
@OptIn(WorkflowExperimentalRuntime::class)
3030
@RunWith(AndroidJUnit4::class)
3131
class ComposeWorkflowMicroBenchmark {
@@ -34,38 +34,89 @@ class ComposeWorkflowMicroBenchmark {
3434

3535
@Test fun tradRoot_tradChildren_initialRender() {
3636
benchmarkSimpleTreeInitialRender(
37-
maxChildCount = 100,
3837
composeRoot = false,
3938
composeChildren = false
4039
)
4140
}
4241

4342
@Test fun tradRoot_composeChildren_initialRender() {
4443
benchmarkSimpleTreeInitialRender(
45-
maxChildCount = 100,
4644
composeRoot = false,
4745
composeChildren = true
4846
)
4947
}
5048

5149
@Test fun composeRoot_tradChildren_initialRender() {
5250
benchmarkSimpleTreeInitialRender(
53-
maxChildCount = 100,
5451
composeRoot = true,
5552
composeChildren = false
5653
)
5754
}
5855

5956
@Test fun composeRoot_composeChildren_initialRender() {
6057
benchmarkSimpleTreeInitialRender(
61-
maxChildCount = 100,
58+
composeRoot = true,
59+
composeChildren = true
60+
)
61+
}
62+
63+
@Test fun tradRoot_tradChildren_tearDown() {
64+
benchmarkSimpleTreeTearDown(
65+
composeRoot = false,
66+
composeChildren = false
67+
)
68+
}
69+
70+
@Test fun tradRoot_composeChildren_tearDown() {
71+
benchmarkSimpleTreeTearDown(
72+
composeRoot = false,
73+
composeChildren = true
74+
)
75+
}
76+
77+
@Test fun composeRoot_tradChildren_tearDown() {
78+
benchmarkSimpleTreeTearDown(
79+
composeRoot = true,
80+
composeChildren = false
81+
)
82+
}
83+
84+
@Test fun composeRoot_composeChildren_tearDown() {
85+
benchmarkSimpleTreeTearDown(
86+
composeRoot = true,
87+
composeChildren = true
88+
)
89+
}
90+
91+
@Test fun tradRoot_tradChildren_subsequentRender() {
92+
benchmarkSimpleTreeSubsequentRender(
93+
composeRoot = false,
94+
composeChildren = false
95+
)
96+
}
97+
98+
@Test fun tradRoot_composeChildren_subsequentRender() {
99+
benchmarkSimpleTreeSubsequentRender(
100+
composeRoot = false,
101+
composeChildren = true
102+
)
103+
}
104+
105+
@Test fun composeRoot_tradChildren_subsequentRender() {
106+
benchmarkSimpleTreeSubsequentRender(
107+
composeRoot = true,
108+
composeChildren = false
109+
)
110+
}
111+
112+
@Test fun composeRoot_composeChildren_subsequentRender() {
113+
benchmarkSimpleTreeSubsequentRender(
62114
composeRoot = true,
63115
composeChildren = true
64116
)
65117
}
66118

67119
private fun benchmarkSimpleTreeInitialRender(
68-
maxChildCount: Int,
69120
composeRoot: Boolean,
70121
composeChildren: Boolean
71122
) = runTest {
@@ -91,9 +142,91 @@ class ComposeWorkflowMicroBenchmark {
91142
assertEquals(0, renderings.value.rendering)
92143
}
93144

94-
props.value = RootWorkflowProps(childCount = maxChildCount, composeChildren = composeChildren)
145+
props.value = RootWorkflowProps(childCount = MaxChildCount, composeChildren = composeChildren)
146+
testScheduler.runCurrent()
147+
assertEquals(MaxChildCount, renderings.value.rendering)
148+
}
149+
150+
workflowJob.cancel()
151+
}
152+
153+
private fun benchmarkSimpleTreeTearDown(
154+
composeRoot: Boolean,
155+
composeChildren: Boolean
156+
) = runTest {
157+
val props =
158+
MutableStateFlow(RootWorkflowProps(childCount = 0, composeChildren = composeChildren))
159+
val workflowJob = Job(parent = coroutineContext.job)
160+
val renderings = renderWorkflowIn(
161+
workflow = if (composeRoot) {
162+
composeSimpleRoot
163+
} else {
164+
traditionalSimpleRoot
165+
},
166+
props = props,
167+
scope = this + workflowJob,
168+
runtimeConfig = RuntimeConfigOptions.ALL,
169+
onOutput = {}
170+
)
171+
172+
benchmarkRule.measureRepeated {
173+
runWithTimingDisabled {
174+
props.value =
175+
RootWorkflowProps(childCount = MaxChildCount, composeChildren = composeChildren)
176+
testScheduler.runCurrent()
177+
assertEquals(MaxChildCount, renderings.value.rendering)
178+
}
179+
180+
props.value = RootWorkflowProps(childCount = 0, composeChildren = composeChildren)
181+
testScheduler.runCurrent()
182+
assertEquals(0, renderings.value.rendering)
183+
}
184+
185+
workflowJob.cancel()
186+
}
187+
188+
private fun benchmarkSimpleTreeSubsequentRender(
189+
composeRoot: Boolean,
190+
composeChildren: Boolean
191+
) = runTest {
192+
val props = MutableStateFlow(
193+
RootWorkflowProps(
194+
childCount = MaxChildCount,
195+
composeChildren = composeChildren
196+
)
197+
)
198+
val workflowJob = Job(parent = coroutineContext.job)
199+
val renderings = renderWorkflowIn(
200+
workflow = if (composeRoot) {
201+
composeSimpleRoot
202+
} else {
203+
traditionalSimpleRoot
204+
},
205+
props = props,
206+
scope = this + workflowJob,
207+
runtimeConfig = RuntimeConfigOptions.ALL,
208+
onOutput = {}
209+
)
210+
211+
benchmarkRule.measureRepeated {
212+
runWithTimingDisabled {
213+
props.value =
214+
RootWorkflowProps(
215+
childCount = MaxChildCount,
216+
composeChildren = composeChildren,
217+
childProps = 1
218+
)
219+
testScheduler.runCurrent()
220+
assertEquals(MaxChildCount, renderings.value.rendering)
221+
}
222+
223+
props.value = RootWorkflowProps(
224+
childCount = MaxChildCount,
225+
composeChildren = composeChildren,
226+
childProps = 2
227+
)
95228
testScheduler.runCurrent()
96-
assertEquals(maxChildCount, renderings.value.rendering)
229+
assertEquals(MaxChildCount * 2, renderings.value.rendering)
97230
}
98231

99232
workflowJob.cancel()
@@ -102,14 +235,16 @@ class ComposeWorkflowMicroBenchmark {
102235

103236
private data class RootWorkflowProps(
104237
val childCount: Int,
105-
val composeChildren: Boolean
238+
val composeChildren: Boolean,
239+
val childProps: Int = 1,
106240
)
107241

108242
private val traditionalSimpleRoot = Workflow.stateless<RootWorkflowProps, Nothing, Int> { props ->
109243
var rendering = 0
110244
repeat(props.childCount) { child ->
111245
rendering += renderChild(
112246
key = child.toString(),
247+
props = props.childProps,
113248
child = if (props.composeChildren) {
114249
composeSimpleLeaf
115250
} else {
@@ -124,17 +259,16 @@ private val composeSimpleRoot = Workflow.composable<RootWorkflowProps, Nothing,
124259
var rendering = 0
125260
repeat(props.childCount) {
126261
rendering += renderChild(
262+
props = props.childProps,
127263
workflow = if (props.composeChildren) {
128264
composeSimpleLeaf
129265
} else {
130266
traditionalSimpleLeaf
131267
},
132-
props = Unit,
133-
onOutput = null
134268
)
135269
}
136270
rendering
137271
}
138272

139-
private val traditionalSimpleLeaf = Workflow.stateless<Unit, Nothing, Int> { 1 }
140-
private val composeSimpleLeaf = Workflow.composable<Unit, Nothing, Int> { _, _ -> 1 }
273+
private val traditionalSimpleLeaf = Workflow.stateless<Int, Nothing, Int> { it }
274+
private val composeSimpleLeaf = Workflow.composable<Int, Nothing, Int> { props, _ -> props }

benchmarks/cw2/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

0 commit comments

Comments
 (0)