Skip to content

Commit dcec792

Browse files
Move Compose runtime optimizations out of core/runtime
1 parent d48eaf6 commit dcec792

File tree

89 files changed

+2120
-1532
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+2120
-1532
lines changed

artifacts.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
"packaging": "jar",
2424
"javaVersion": "1.8"
2525
},
26+
{
27+
"gradlePath": ":workflow-core-compose",
28+
"group": "com.squareup.workflow1",
29+
"artifactId": "workflow-core-compose",
30+
"description": "Workflow Core Compose",
31+
"packaging": "jar",
32+
"javaVersion": "1.8"
33+
},
2634
{
2735
"gradlePath": ":workflow-runtime",
2836
"group": "com.squareup.workflow1",

benchmarks/performance-poetry/complex-poetry/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ dependencies {
5252
// API on an app module so these are transitive dependencies for the benchmarks.
5353
api(project(":samples:containers:android"))
5454
api(project(":samples:containers:poetry"))
55+
api(project(":workflow-core-compose"))
5556
api(project(":workflow-ui:core-android"))
5657

5758
implementation(libs.androidx.activity.ktx)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class RenderPassTest {
8484

8585
@Ignore(
8686
"Not sure why but this gets stuck on initializing. Compose doesn't get the next" +
87-
" frame when this is started by the test, but it does when running directly."
87+
" frame when this is started by the test, but it does when running directly. See #835"
8888
)
8989
@Test fun renderPassCounterFrameTimeoutComposeComplexWithInitializingState() {
9090
runRenderPassCounter(COMPLEX_INITIALIZING, useFrameTimeout = true, useCompose = true)

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ import com.squareup.sample.container.overviewdetail.OverviewDetailScreen
99
import com.squareup.workflow1.Snapshot
1010
import com.squareup.workflow1.StatefulWorkflow
1111
import com.squareup.workflow1.Workflow
12+
import com.squareup.workflow1.WorkflowExperimentalRuntime
1213
import com.squareup.workflow1.action
14+
import com.squareup.workflow1.compose.StatefulComposeWorkflow
1315
import com.squareup.workflow1.runningWorker
1416
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
1517
import kotlinx.coroutines.flow.Flow
1618

1719
typealias IsLoading = Boolean
1820

19-
@OptIn(WorkflowUiExperimentalApi::class)
21+
@OptIn(WorkflowUiExperimentalApi::class, WorkflowExperimentalRuntime::class)
2022
class MaybeLoadingGatekeeperWorkflow<T : Any>(
2123
private val childWithLoading: Workflow<T, Any, OverviewDetailScreen>,
2224
private val childProps: T,
2325
private val isLoading: Flow<Boolean>
24-
) : StatefulWorkflow<Unit, IsLoading, Unit, MayBeLoadingScreen>() {
26+
) : StatefulComposeWorkflow<Unit, IsLoading, Unit, MayBeLoadingScreen>() {
2527
override fun initialState(
2628
props: Unit,
2729
snapshot: Snapshot?
@@ -30,7 +32,7 @@ class MaybeLoadingGatekeeperWorkflow<T : Any>(
3032
override fun render(
3133
renderProps: Unit,
3234
renderState: IsLoading,
33-
context: RenderContext
35+
context: StatefulWorkflow<Unit, IsLoading, Unit, MayBeLoadingScreen>.RenderContext
3436
): MayBeLoadingScreen {
3537
context.runningWorker(isLoading.asTraceableWorker("GatekeeperLoading")) {
3638
action {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ import com.squareup.workflow1.StatefulWorkflow
3131
import com.squareup.workflow1.Worker
3232
import com.squareup.workflow1.WorkflowAction
3333
import com.squareup.workflow1.WorkflowAction.Companion.noAction
34+
import com.squareup.workflow1.WorkflowExperimentalRuntime
3435
import com.squareup.workflow1.action
36+
import com.squareup.workflow1.compose.StatefulComposeWorkflow
3537
import com.squareup.workflow1.runningWorker
3638
import com.squareup.workflow1.ui.Screen
3739
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
@@ -58,11 +60,11 @@ import kotlinx.coroutines.flow.flow
5860
* break ties/conflicts with a token in the start/stop requests. We leave that complexity out
5961
* here. **
6062
*/
61-
@OptIn(WorkflowUiExperimentalApi::class)
63+
@OptIn(WorkflowUiExperimentalApi::class, WorkflowExperimentalRuntime::class)
6264
class PerformancePoemWorkflow(
6365
private val simulatedPerfConfig: SimulatedPerfConfig = SimulatedPerfConfig.NO_SIMULATED_PERF,
6466
private val isLoading: MutableStateFlow<Boolean>,
65-
) : PoemWorkflow, StatefulWorkflow<Poem, State, ClosePoem, OverviewDetailScreen>() {
67+
) : PoemWorkflow, StatefulComposeWorkflow<Poem, State, ClosePoem, OverviewDetailScreen>() {
6668

6769
sealed class State {
6870
// N.B. This state is a smell. We include it to be able to mimic smells
@@ -95,7 +97,7 @@ class PerformancePoemWorkflow(
9597
override fun render(
9698
renderProps: Poem,
9799
renderState: State,
98-
context: RenderContext
100+
context: StatefulWorkflow<Poem, State, ClosePoem, OverviewDetailScreen>.RenderContext
99101
): OverviewDetailScreen {
100102
return when (renderState) {
101103
Initializing -> {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import com.squareup.sample.poetry.PoemsBrowserWorkflow
1919
import com.squareup.sample.poetry.model.Poem
2020
import com.squareup.workflow1.Snapshot
2121
import com.squareup.workflow1.StatefulWorkflow
22+
import com.squareup.workflow1.WorkflowExperimentalRuntime
2223
import com.squareup.workflow1.action
24+
import com.squareup.workflow1.compose.StatefulComposeWorkflow
2325
import com.squareup.workflow1.runningWorker
2426
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
2527
import com.squareup.workflow1.ui.container.BackStackScreen
@@ -44,14 +46,14 @@ import java.lang.IllegalStateException
4446
* break ties/conflicts with a token in the start/stop requests. We leave that complexity out
4547
* here. **
4648
*/
47-
@OptIn(WorkflowUiExperimentalApi::class)
49+
@OptIn(WorkflowUiExperimentalApi::class, WorkflowExperimentalRuntime::class)
4850
class PerformancePoemsBrowserWorkflow(
4951
private val simulatedPerfConfig: SimulatedPerfConfig,
5052
private val poemWorkflow: PoemWorkflow,
5153
private val isLoading: MutableStateFlow<Boolean>,
5254
) :
5355
PoemsBrowserWorkflow,
54-
StatefulWorkflow<List<Poem>, State, Unit, OverviewDetailScreen>() {
56+
StatefulComposeWorkflow<List<Poem>, State, Unit, OverviewDetailScreen>() {
5557

5658
sealed class State {
5759
// N.B. This state is a smell. We include it to be able to mimic smells
@@ -76,7 +78,7 @@ class PerformancePoemsBrowserWorkflow(
7678
override fun render(
7779
renderProps: List<Poem>,
7880
renderState: State,
79-
context: RenderContext
81+
context: StatefulWorkflow<List<Poem>, State, Unit, OverviewDetailScreen>.RenderContext
8082
): OverviewDetailScreen {
8183
val poemListProps = Props(
8284
poems = renderProps,

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@file:OptIn(WorkflowExperimentalRuntime::class)
2+
13
package com.squareup.benchmarks.performance.complex.poetry
24

35
import android.content.pm.ApplicationInfo
@@ -25,6 +27,7 @@ import com.squareup.workflow1.RuntimeConfig.FrameTimeout
2527
import com.squareup.workflow1.RuntimeConfig.RenderPerAction
2628
import com.squareup.workflow1.WorkflowExperimentalRuntime
2729
import com.squareup.workflow1.WorkflowInterceptor
30+
import com.squareup.workflow1.compose.ComposeRuntimePlugin
2831
import com.squareup.workflow1.ui.Screen
2932
import com.squareup.workflow1.ui.ViewEnvironment.Companion.EMPTY
3033
import com.squareup.workflow1.ui.ViewRegistry
@@ -270,12 +273,14 @@ class PoetryModel(
270273
runtimeConfig: RuntimeConfig
271274
) : ViewModel() {
272275
@OptIn(WorkflowUiExperimentalApi::class) val renderings: StateFlow<Screen> by lazy {
276+
val runtimePlugin = if (runtimeConfig.useComposeInRuntime) ComposeRuntimePlugin else null
273277
renderWorkflowIn(
274278
workflow = workflow,
275279
scope = viewModelScope,
276280
savedStateHandle = savedState,
277281
interceptors = interceptor?.let { listOf(it) } ?: emptyList(),
278-
runtimeConfig = runtimeConfig
282+
runtimeConfig = runtimeConfig,
283+
workflowRuntimePlugin = runtimePlugin
279284
)
280285
}
281286

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import com.squareup.workflow1.WorkflowAction
88
import com.squareup.workflow1.WorkflowInterceptor
99
import com.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor
1010
import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
11+
import com.squareup.workflow1.compose.BaseComposeRenderContext
12+
import com.squareup.workflow1.compose.ComposeWorkflowInterceptor
13+
import com.squareup.workflow1.compose.ComposeWorkflowInterceptor.ComposeRenderContextInterceptor
1114

1215
/**
1316
* We use this [WorkflowInterceptor] to add in tracing for the main thread messages that handle
@@ -22,13 +25,13 @@ import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
2225
* annotate the [Worker] using [TraceableWorker] which will set it up with a key such that when
2326
* the action for the result is sent to the sink the main thread message will be traced.
2427
*/
25-
class ActionHandlingTracingInterceptor : WorkflowInterceptor, Resettable {
28+
class ActionHandlingTracingInterceptor : ComposeWorkflowInterceptor, Resettable {
2629

2730
private val actionCounts: MutableMap<String, Int> = mutableMapOf()
2831

2932
class EventHandlingTracingRenderContextInterceptor<P, S, O>(
3033
private val actionCounts: MutableMap<String, Int>
31-
) : RenderContextInterceptor<P, S, O> {
34+
) : ComposeRenderContextInterceptor<P, S, O> {
3235
override fun onActionSent(
3336
action: WorkflowAction<P, S, O>,
3437
proceed: (WorkflowAction<P, S, O>) -> Unit
@@ -76,9 +79,9 @@ class ActionHandlingTracingInterceptor : WorkflowInterceptor, Resettable {
7679
override fun <P, S, O, R> Rendering(
7780
renderProps: P,
7881
renderState: S,
79-
context: BaseRenderContext<P, S, O>,
82+
context: BaseComposeRenderContext<P, S, O>,
8083
session: WorkflowSession,
81-
proceed: @Composable (P, S, RenderContextInterceptor<P, S, O>?) -> R
84+
proceed: @Composable (P, S, ComposeRenderContextInterceptor<P, S, O>?) -> R
8285
): R {
8386
val rci = remember {
8487
EventHandlingTracingRenderContextInterceptor<P, S, O>(actionCounts)

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import androidx.tracing.Trace
77
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemWorkflow
88
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemsBrowserWorkflow
99
import com.squareup.workflow1.BaseRenderContext
10-
import com.squareup.workflow1.WorkflowInterceptor
1110
import com.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor
1211
import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
12+
import com.squareup.workflow1.compose.BaseComposeRenderContext
13+
import com.squareup.workflow1.compose.ComposeWorkflowInterceptor
14+
import com.squareup.workflow1.compose.ComposeWorkflowInterceptor.ComposeRenderContextInterceptor
1315
import com.squareup.workflow1.workflowIdentifier
1416

1517
/**
@@ -21,7 +23,7 @@ import com.squareup.workflow1.workflowIdentifier
2123
*/
2224
class PerformanceTracingInterceptor(
2325
private val sample: Boolean = false
24-
) : WorkflowInterceptor, Resettable {
26+
) : ComposeWorkflowInterceptor, Resettable {
2527
private var totalRenderPasses = 0
2628

2729
override fun <P, S, O, R> onRender(
@@ -42,9 +44,9 @@ class PerformanceTracingInterceptor(
4244
override fun <P, S, O, R> Rendering(
4345
renderProps: P,
4446
renderState: S,
45-
context: BaseRenderContext<P, S, O>,
47+
context: BaseComposeRenderContext<P, S, O>,
4648
session: WorkflowSession,
47-
proceed: @Composable (P, S, RenderContextInterceptor<P, S, O>?) -> R
49+
proceed: @Composable (P, S, ComposeRenderContextInterceptor<P, S, O>?) -> R
4850
): R {
4951
// TODO: Fix that these are illegal side effects in a Composable
5052
val traceIdIndex = remember(session) {

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import androidx.compose.runtime.Composable
44
import androidx.compose.runtime.SideEffect
55
import androidx.compose.runtime.remember
66
import com.squareup.workflow1.BaseRenderContext
7-
import com.squareup.workflow1.WorkflowInterceptor
87
import com.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor
98
import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
9+
import com.squareup.workflow1.compose.BaseComposeRenderContext
10+
import com.squareup.workflow1.compose.ComposeWorkflowInterceptor
11+
import com.squareup.workflow1.compose.ComposeWorkflowInterceptor.ComposeRenderContextInterceptor
1012

1113
/**
1214
* Used to count the number of render passes for a Workflow tree as well as each time that a node
@@ -16,7 +18,7 @@ import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
1618
* This is convenient to use in integration tests that verify that the # of render passes and the
1719
* ratio of 'fresh' to 'stale' renderings for a scenario are constant.
1820
*/
19-
class RenderPassCountingInterceptor : WorkflowInterceptor, Resettable {
21+
class RenderPassCountingInterceptor : ComposeWorkflowInterceptor, Resettable {
2022
val renderEfficiencyTracking = RenderEfficiency()
2123
private var renderPassStats: RenderStats = RenderStats()
2224
private val nodeStates: MutableMap<Long, String> = mutableMapOf()
@@ -38,10 +40,10 @@ class RenderPassCountingInterceptor : WorkflowInterceptor, Resettable {
3840
override fun <P, S, O, R> Rendering(
3941
renderProps: P,
4042
renderState: S,
41-
context: BaseRenderContext<P, S, O>,
43+
context: BaseComposeRenderContext<P, S, O>,
4244
session: WorkflowSession,
4345
proceed: @Composable
44-
(P, S, RenderContextInterceptor<P, S, O>?) -> R
46+
(P, S, ComposeRenderContextInterceptor<P, S, O>?) -> R
4547
): R {
4648
val isRoot = remember(session, renderState) {
4749
before(session, renderState)

samples/containers/poetry/src/main/java/com/squareup/sample/poetry/PoemListWorkflow.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.squareup.sample.poetry
22

3-
import androidx.compose.runtime.Composable
43
import com.squareup.sample.poetry.PoemListWorkflow.Props
54
import com.squareup.sample.poetry.model.Poem
65
import com.squareup.workflow1.StatelessWorkflow
@@ -26,12 +25,4 @@ object PoemListWorkflow : StatelessWorkflow<Props, Int, PoemListScreen>() {
2625
) { index -> setOutput(index) }
2726
)
2827
}
29-
30-
@Composable
31-
override fun Rendering(
32-
renderProps: Props,
33-
context: RenderContext
34-
): PoemListScreen {
35-
return render(renderProps, context)
36-
}
3728
}

samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemWorkflow.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.squareup.sample.poetry
22

3-
import androidx.compose.runtime.Composable
43
import com.squareup.sample.container.overviewdetail.OverviewDetailScreen
54
import com.squareup.sample.poetry.PoemWorkflow.ClosePoem
65
import com.squareup.sample.poetry.RealPoemWorkflow.Action.ClearSelection
@@ -117,13 +116,4 @@ class RealPoemWorkflow : PoemWorkflow,
117116
}
118117
}
119118
}
120-
121-
@Composable
122-
override fun Rendering(
123-
renderProps: Poem,
124-
renderState: SelectedStanza,
125-
context: RenderContext,
126-
): OverviewDetailScreen {
127-
TODO("Not yet implemented")
128-
}
129119
}

samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemsBrowserWorkflow.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.squareup.sample.poetry
22

3-
import androidx.compose.runtime.Composable
43
import com.squareup.sample.container.overviewdetail.OverviewDetailScreen
54
import com.squareup.sample.poetry.PoemListScreen.Companion.NO_POEM_SELECTED
65
import com.squareup.sample.poetry.PoemListWorkflow.Props
@@ -69,13 +68,4 @@ class RealPoemsBrowserWorkflow(
6968
}
7069

7170
private val clearSelection = choosePoem(NO_POEM_SELECTED)
72-
73-
@Composable
74-
override fun Rendering(
75-
renderProps: List<Poem>,
76-
renderState: SelectedPoem,
77-
context: RenderContext,
78-
): OverviewDetailScreen {
79-
TODO("Not yet implemented")
80-
}
8171
}

samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaListWorkflow.kt

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.squareup.sample.poetry
22

3-
import androidx.compose.runtime.Composable
3+
import com.squareup.sample.poetry.StanzaListWorkflow.NO_SELECTED_STANZA
44
import com.squareup.sample.poetry.StanzaListWorkflow.Props
55
import com.squareup.sample.poetry.model.Poem
66
import com.squareup.workflow1.StatelessWorkflow
@@ -46,12 +46,4 @@ object StanzaListWorkflow : StatelessWorkflow<Props, SelectedStanza, StanzaListS
4646
}
4747
)
4848
}
49-
50-
@Composable
51-
override fun Rendering(
52-
renderProps: Props,
53-
context: RenderContext
54-
): StanzaListScreen {
55-
return render(renderProps, context)
56-
}
5749
}

samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaWorkflow.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.squareup.sample.poetry
22

3-
import androidx.compose.runtime.Composable
43
import com.squareup.sample.poetry.StanzaWorkflow.Output
54
import com.squareup.sample.poetry.StanzaWorkflow.Output.CloseStanzas
65
import com.squareup.sample.poetry.StanzaWorkflow.Output.ShowNextStanza
@@ -69,12 +68,4 @@ object StanzaWorkflow : StatelessWorkflow<Props, Output, StanzaScreen>() {
6968
)
7069
}
7170
}
72-
73-
@Composable
74-
override fun Rendering(
75-
renderProps: Props,
76-
context: RenderContext
77-
): StanzaScreen {
78-
return render(renderProps, context)
79-
}
8071
}

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ include(
6767
":workflow-config:config-android",
6868
":workflow-config:config-jvm",
6969
":workflow-core",
70+
":workflow-core-compose",
7071
":workflow-runtime",
7172
":workflow-rx2",
7273
":workflow-testing",

0 commit comments

Comments
 (0)