Skip to content

Commit 410fbd1

Browse files
Cleanup Side Effects; Able to Freeze
1 parent 5fe9107 commit 410fbd1

File tree

31 files changed

+462
-376
lines changed

31 files changed

+462
-376
lines changed

benchmarks/performance-poetry/complex-poetry/src/androidTest/java/com/squareup/benchmarks/performance/complex/poetry/ComposeInheritanceTest.kt

Lines changed: 0 additions & 59 deletions
This file was deleted.

benchmarks/performance-poetry/complex-poetry/src/androidTest/java/com/squareup/benchmarks/performance/complex/poetry/RenderPassTest.kt

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import androidx.test.platform.app.InstrumentationRegistry
88
import androidx.test.uiautomator.UiDevice
99
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_PERF_CONFIG_INITIALIZING
1010
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_PERF_CONFIG_REPEAT
11+
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_RUNTIME_COMPOSE_RUNTIME
1112
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_RUNTIME_FRAME_TIMEOUT
1213
import com.squareup.benchmarks.performance.complex.poetry.cyborgs.landscapeOrientation
1314
import com.squareup.benchmarks.performance.complex.poetry.cyborgs.openRavenAndNavigate
@@ -16,6 +17,7 @@ import com.squareup.benchmarks.performance.complex.poetry.cyborgs.waitForPoetry
1617
import com.squareup.benchmarks.performance.complex.poetry.instrumentation.RenderPassCountingInterceptor
1718
import org.junit.Assert.fail
1819
import org.junit.Before
20+
import org.junit.Ignore
1921
import org.junit.Test
2022
import org.junit.runner.RunWith
2123

@@ -30,7 +32,8 @@ class RenderPassTest {
3032
val useInitializingState: Boolean,
3133
val useHighFrequencyRange: Boolean,
3234
val baselineExpectation: RenderExpectation,
33-
val frameTimeoutExpectation: RenderExpectation
35+
val frameTimeoutExpectation: RenderExpectation,
36+
val frameTimeoutComposeExpectation: RenderExpectation
3437
)
3538

3639
data class RenderExpectation(
@@ -56,15 +59,15 @@ class RenderPassTest {
5659
}
5760

5861
@Test fun renderPassCounterBaselineComplexWithInitializingState() {
59-
runRenderPassCounter(COMPLEX_INITIALIZING, useFrameTimeout = false)
62+
runRenderPassCounter(COMPLEX_INITIALIZING)
6063
}
6164

6265
@Test fun renderPassCounterBaselineComplexNoInitializingState() {
63-
runRenderPassCounter(COMPLEX_NO_INITIALIZING, useFrameTimeout = false)
66+
runRenderPassCounter(COMPLEX_NO_INITIALIZING)
6467
}
6568

6669
@Test fun renderPassCounterBaselineComplexNoInitializingStateHighFrequencyEvents() {
67-
runRenderPassCounter(COMPLEX_NO_INITIALIZING_HIGH_FREQUENCY, useFrameTimeout = false)
70+
runRenderPassCounter(COMPLEX_NO_INITIALIZING_HIGH_FREQUENCY)
6871
}
6972

7073
@Test fun renderPassCounterFrameTimeoutComplexWithInitializingState() {
@@ -79,19 +82,41 @@ class RenderPassTest {
7982
runRenderPassCounter(COMPLEX_NO_INITIALIZING_HIGH_FREQUENCY, useFrameTimeout = true)
8083
}
8184

85+
@Ignore("Not sure why but this gets stuck on initializing. Compose doesn't get the next" +
86+
" frame when this is started by the test, but it does when running directly.")
87+
@Test fun renderPassCounterFrameTimeoutComposeComplexWithInitializingState() {
88+
runRenderPassCounter(COMPLEX_INITIALIZING, useFrameTimeout = true, useCompose = true)
89+
}
90+
91+
@Test fun renderPassCounterFrameTimeoutComposeComplexNoInitializingState() {
92+
runRenderPassCounter(COMPLEX_NO_INITIALIZING, useFrameTimeout = true, useCompose = true)
93+
}
94+
95+
@Test fun renderPassCounterFrameTimeoutComposeComplexNoInitializingStateHighFrequencyEvents() {
96+
runRenderPassCounter(
97+
COMPLEX_NO_INITIALIZING_HIGH_FREQUENCY,
98+
useFrameTimeout = true,
99+
useCompose = true
100+
)
101+
}
102+
82103
private fun runRenderPassCounter(
83104
scenario: Scenario,
84-
useFrameTimeout: Boolean
105+
useFrameTimeout: Boolean = false,
106+
useCompose: Boolean = false
85107
) {
108+
if (useCompose) require(useFrameTimeout) { "Only use Compose Frame Timeout." }
109+
86110
val intent = Intent(context, PerformancePoetryActivity::class.java).apply {
87111
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
88112
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
89113
putExtra(
90114
EXTRA_PERF_CONFIG_INITIALIZING,
91115
scenario.useInitializingState
92116
)
117+
putExtra(EXTRA_RUNTIME_FRAME_TIMEOUT, useFrameTimeout)
93118
if (useFrameTimeout) {
94-
putExtra(EXTRA_RUNTIME_FRAME_TIMEOUT, useFrameTimeout)
119+
putExtra(EXTRA_RUNTIME_COMPOSE_RUNTIME, useCompose)
95120
}
96121
if (scenario.useHighFrequencyRange) {
97122
putExtra(EXTRA_PERF_CONFIG_REPEAT, PerformancePoetryActivity.HIGH_FREQUENCY_REPEAT_COUNT)
@@ -111,11 +136,19 @@ class RenderPassTest {
111136
device.openRavenAndNavigate()
112137

113138
val expectation =
114-
if (useFrameTimeout) scenario.frameTimeoutExpectation else
139+
if (useFrameTimeout) {
140+
if (useCompose) {
141+
scenario.frameTimeoutComposeExpectation
142+
} else {
143+
scenario.frameTimeoutExpectation
144+
}
145+
} else {
115146
scenario.baselineExpectation
147+
}
116148

117149
val title = if (useFrameTimeout) {
118-
"Runtime: FrameTimeout; "
150+
val usingCompose = if (useCompose) "(Using Compose Optimizations)" else "(No Compose)"
151+
"Runtime: FrameTimeout $usingCompose;"
119152
} else {
120153
"Runtime: RenderPerAction; "
121154
} + scenario.title
@@ -227,6 +260,11 @@ class RenderPassTest {
227260
totalPasses = 41..42,
228261
freshRenderedNodes = 85..85,
229262
staleRenderedNodes = 436..436
263+
),
264+
frameTimeoutComposeExpectation = RenderExpectation(
265+
totalPasses = 41..42,
266+
freshRenderedNodes = 85..85,
267+
staleRenderedNodes = 436..436
230268
)
231269
)
232270

@@ -243,6 +281,11 @@ class RenderPassTest {
243281
totalPasses = 40..41,
244282
freshRenderedNodes = 83..83,
245283
staleRenderedNodes = 431..431
284+
),
285+
frameTimeoutComposeExpectation = RenderExpectation(
286+
totalPasses = 40..41,
287+
freshRenderedNodes = 113..113,
288+
staleRenderedNodes = 82..82
246289
)
247290
)
248291

@@ -252,11 +295,11 @@ class RenderPassTest {
252295
*
253296
* Physical Pixel 6:
254297
* ```
255-
RenderExpectation(
256-
totalPasses = 56..61,
257-
freshRenderedNodes = 106..108,
258-
staleRenderedNodes = 679..698
259-
)
298+
RenderExpectation(
299+
totalPasses = 56..61,
300+
freshRenderedNodes = 106..108,
301+
staleRenderedNodes = 679..698
302+
)
260303
* ```
261304
* We use the values expected in CI for what we commit to the repo.
262305
*/
@@ -270,9 +313,14 @@ class RenderPassTest {
270313
staleRenderedNodes = 2350..2350
271314
),
272315
frameTimeoutExpectation = RenderExpectation(
273-
totalPasses = 64..68,
316+
totalPasses = 60..64,
274317
freshRenderedNodes = 106..108,
275318
staleRenderedNodes = 679..698
319+
),
320+
frameTimeoutComposeExpectation = RenderExpectation(
321+
totalPasses = 60..64,
322+
freshRenderedNodes = 259..259,
323+
staleRenderedNodes = 207..207
276324
)
277325
)
278326

benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemWorkflow.kt

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ class PerformancePoemWorkflow(
326326
.copy(selection = stanzaIndex)
327327

328328
if (stanzaIndex != NO_SELECTED_STANZA) {
329-
val previousStanzas = renderProps.stanzas.subList(0, stanzaIndex)
329+
val stackedStanzas = renderProps.stanzas.subList(0, stanzaIndex + 1)
330330
.mapIndexed { index, _ ->
331331
context.ChildRendering(
332332
StanzaWorkflow,
@@ -337,28 +337,13 @@ class PerformancePoemWorkflow(
337337
),
338338
key = "$index",
339339
) {
340-
noAction()
340+
when (it) {
341+
CloseStanzas -> ClearSelection(simulatedPerfConfig)
342+
ShowPreviousStanza -> SelectPrevious(simulatedPerfConfig)
343+
ShowNextStanza -> SelectNext(simulatedPerfConfig)
344+
}
341345
}
342-
}
343-
val visibleStanza = context.ChildRendering(
344-
StanzaWorkflow,
345-
Props(
346-
poem = renderProps,
347-
index = stanzaIndex,
348-
eventHandlerTag = ActionHandlingTracingInterceptor::keyForTrace
349-
),
350-
key = "$stanzaIndex",
351-
) {
352-
when (it) {
353-
CloseStanzas -> ClearSelection(simulatedPerfConfig)
354-
ShowPreviousStanza -> SelectPrevious(simulatedPerfConfig)
355-
ShowNextStanza -> SelectNext(simulatedPerfConfig)
356-
}
357-
}
358-
359-
val stackedStanzas = visibleStanza.let {
360-
(previousStanzas + it).toBackStackScreen<Screen>()
361-
}
346+
}.toBackStackScreen<Screen>()
362347

363348
return OverviewDetailScreen(
364349
overviewRendering = BackStackScreen(stanzaListOverview),

benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemsBrowserWorkflow.kt

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
2525
import com.squareup.workflow1.ui.container.BackStackScreen
2626
import kotlinx.coroutines.delay
2727
import kotlinx.coroutines.flow.MutableStateFlow
28+
import java.lang.IllegalStateException
2829

2930
/**
3031
* Version of [PoemsBrowserWorkflow] that takes in a [SimulatedPerfConfig] to control the
@@ -161,6 +162,22 @@ class PerformancePoemsBrowserWorkflow(
161162
renderState: State,
162163
context: RenderContext,
163164
): OverviewDetailScreen {
165+
166+
// Again, then entire `Initializing` state is a smell, which is most obvious from the
167+
// use of `Worker.from { Unit }`. A Worker doing no work and only shuttling the state
168+
// along is usually the sign you have an extraneous state that can be collapsed!
169+
// Don't try this at home.
170+
if (renderState is Initializing) {
171+
context.runningWorker(TraceableWorker.from("BrowserInitializing") { Unit }, "init") {
172+
isLoading.value = true
173+
action {
174+
isLoading.value = false
175+
state = NoSelection
176+
}
177+
}
178+
return OverviewDetailScreen(overviewRendering = BackStackScreen(BlankScreen))
179+
}
180+
164181
val poemListProps = Props(
165182
poems = renderProps,
166183
eventHandlerTag = ActionHandlingTracingInterceptor::keyForTrace
@@ -174,20 +191,6 @@ class PerformancePoemsBrowserWorkflow(
174191
choosePoem(selected)
175192
}
176193
when (renderState) {
177-
// Again, then entire `Initializing` state is a smell, which is most obvious from the
178-
// use of `Worker.from { Unit }`. A Worker doing no work and only shuttling the state
179-
// along is usually the sign you have an extraneous state that can be collapsed!
180-
// Don't try this at home.
181-
is Initializing -> {
182-
context.runningWorker(TraceableWorker.from("BrowserInitializing") { Unit }, "init") {
183-
isLoading.value = true
184-
action {
185-
isLoading.value = false
186-
state = NoSelection
187-
}
188-
}
189-
return OverviewDetailScreen(overviewRendering = BackStackScreen(BlankScreen))
190-
}
191194
is NoSelection -> {
192195
return OverviewDetailScreen(
193196
overviewRendering = BackStackScreen(
@@ -243,8 +246,10 @@ class PerformancePoemsBrowserWorkflow(
243246
key = "",
244247
) { clearSelection }
245248
}
249+
else -> {
250+
throw IllegalStateException("$renderState state is impossible.")
251+
}
246252
}
247-
248253
}
249254

250255
override fun snapshotState(state: State): Snapshot? = null

benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoetryActivity.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ class PerformancePoetryActivity : AppCompatActivity() {
8484
}
8585

8686
val isFrameTimeout = intent.getBooleanExtra(EXTRA_RUNTIME_FRAME_TIMEOUT, false)
87-
val runtimeConfig = if (isFrameTimeout) {
87+
val useCompose = intent.getBooleanExtra(EXTRA_RUNTIME_COMPOSE_RUNTIME, false)
88+
val runtimeConfig = if (true) {
8889
FrameTimeout(useComposeInRuntime = true)
8990
} else {
9091
RenderPerAction
@@ -247,6 +248,8 @@ class PerformancePoetryActivity : AppCompatActivity() {
247248
const val EXTRA_PERF_CONFIG_DELAY = "complex.poetry.performance.config.delay.length"
248249
const val EXTRA_RUNTIME_FRAME_TIMEOUT =
249250
"complex.poetry.performance.config.runtime.frametimeout"
251+
const val EXTRA_RUNTIME_COMPOSE_RUNTIME =
252+
"complex.poetry.performance.config.runtime.compose"
250253

251254
const val SELECT_ON_TIMEOUT_LOG_NAME =
252255
"kotlinx.coroutines.selects.SelectBuilderImpl\$onTimeout\$\$inlined\$Runnable"

benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/cyborgs/PoetryCyborgs.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.squareup.benchmarks.performance.complex.poetry.cyborgs
22

33
import android.widget.ImageButton
44
import android.widget.ProgressBar
5+
import androidx.compose.runtime.currentComposer
56
import androidx.test.uiautomator.By
67
import androidx.test.uiautomator.BySelector
78
import androidx.test.uiautomator.UiDevice
@@ -48,6 +49,7 @@ fun UiDevice.resetToRootPoetryList() {
4849
*/
4950
fun UiDevice.openRavenAndNavigate() {
5051
waitForIdle()
52+
waitForIdle(5_000)
5153
waitForAndClick(RavenPoemSelector)
5254
waitForLoadingInterstitial()
5355
waitForAndClick(By.textStartsWith("Deep into that darkness peering"))

0 commit comments

Comments
 (0)