@@ -11,6 +11,7 @@ import com.squareup.workflow1.Sink
1111import com.squareup.workflow1.Snapshot
1212import com.squareup.workflow1.StatefulWorkflow
1313import com.squareup.workflow1.StatelessWorkflow
14+ import com.squareup.workflow1.Workflow
1415import com.squareup.workflow1.WorkflowAction
1516import com.squareup.workflow1.WorkflowExperimentalRuntime
1617import com.squareup.workflow1.WorkflowTracer
@@ -54,6 +55,12 @@ class WorkflowRuntimeMicrobenchmark(
5455 private val runtime : BenchmarkRuntimeOptions = NoOptimizations ,
5556) {
5657
58+ private companion object {
59+ const val WideSiblingCount = 250
60+ const val RememberEntryCount = 250
61+ const val StableHandlerCount = 250
62+ }
63+
5764 @get:Rule val benchmarkRule = BenchmarkRule ()
5865
5966 @Test fun initialRenderAllChildren () = benchmarkWorkflowPropsChange(
@@ -159,13 +166,92 @@ class WorkflowRuntimeMicrobenchmark(
159166 expectedTestRendering = treeShape.leafCount,
160167 )
161168
169+ @Test fun wideSiblingKeys_initialRenderAllChildren () = benchmarkPropsChange(
170+ workflow = ShallowWideWorkflowRoot (childCount = WideSiblingCount ),
171+ setupProps = ShallowWideWorkflowRoot .Props (
172+ renderFirstChild = false ,
173+ renderOtherChildren = false ,
174+ ),
175+ testProps = ShallowWideWorkflowRoot .Props (
176+ renderFirstChild = true ,
177+ renderOtherChildren = true ,
178+ firstChildProps = 1 ,
179+ otherChildrenProps = 1 ,
180+ ),
181+ expectedSetupRendering = 0 ,
182+ expectedTestRendering = WideSiblingCount ,
183+ )
184+
185+ @Test fun wideSiblingKeys_rerenderSingleSiblingByPropsChange () = benchmarkPropsChange(
186+ workflow = ShallowWideWorkflowRoot (childCount = WideSiblingCount ),
187+ setupProps = ShallowWideWorkflowRoot .Props (
188+ renderFirstChild = true ,
189+ renderOtherChildren = true ,
190+ firstChildProps = 1 ,
191+ otherChildrenProps = 1 ,
192+ ),
193+ testProps = ShallowWideWorkflowRoot .Props (
194+ renderFirstChild = true ,
195+ renderOtherChildren = true ,
196+ firstChildProps = 2 ,
197+ otherChildrenProps = 1 ,
198+ ),
199+ expectedSetupRendering = WideSiblingCount ,
200+ expectedTestRendering = WideSiblingCount + 1 ,
201+ )
202+
203+ @Test fun rememberManyEntries_sameInputs () = benchmarkPropsChange(
204+ workflow = RememberHeavyWorkflow (entryCount = RememberEntryCount ),
205+ setupProps = RememberHeavyWorkflow .Props (baseValue = 1 , inputToken = 0 ),
206+ testProps = RememberHeavyWorkflow .Props (baseValue = 2 , inputToken = 0 ),
207+ expectedSetupRendering = rememberedRendering(baseValue = 1 , entryCount = RememberEntryCount ),
208+ expectedTestRendering = rememberedRendering(baseValue = 1 , entryCount = RememberEntryCount ),
209+ )
210+
211+ @Test fun rememberManyEntries_changingInputs () = benchmarkPropsChange(
212+ workflow = RememberHeavyWorkflow (entryCount = RememberEntryCount ),
213+ setupProps = RememberHeavyWorkflow .Props (baseValue = 1 , inputToken = 0 ),
214+ testProps = RememberHeavyWorkflow .Props (baseValue = 2 , inputToken = 1 ),
215+ expectedSetupRendering = rememberedRendering(baseValue = 1 , entryCount = RememberEntryCount ),
216+ expectedTestRendering = rememberedRendering(baseValue = 2 , entryCount = RememberEntryCount ),
217+ )
218+
219+ @Test fun rememberManyEntries_mixedInputTypes () = benchmarkPropsChange(
220+ workflow = RememberHeavyWorkflow (entryCount = RememberEntryCount , mixedInputTypes = true ),
221+ setupProps = RememberHeavyWorkflow .Props (baseValue = 1 , inputToken = 0 ),
222+ testProps = RememberHeavyWorkflow .Props (baseValue = 3 , inputToken = 1 ),
223+ expectedSetupRendering = rememberedRendering(baseValue = 1 , entryCount = RememberEntryCount ),
224+ expectedTestRendering = rememberedRendering(baseValue = 3 , entryCount = RememberEntryCount ),
225+ )
226+
227+ @Test fun stableHandlers_manyCallbacks_propChange () = benchmarkPropsChange(
228+ workflow = StableHandlersWorkflow (handlerCount = StableHandlerCount ),
229+ setupProps = StableHandlersWorkflow .Props (salt = 0 ),
230+ testProps = StableHandlersWorkflow .Props (salt = 1 ),
231+ expectedSetupRendering = StableHandlerCount ,
232+ expectedTestRendering = StableHandlerCount + 1 ,
233+ )
234+
162235 private fun benchmarkWorkflowPropsChange (
163236 setupProps : BenchmarkWorkflowRoot .Props ,
164237 testProps : BenchmarkWorkflowRoot .Props ,
165238 expectedSetupRendering : Int ,
166239 expectedTestRendering : Int ,
240+ ) = benchmarkPropsChange(
241+ workflow = BenchmarkWorkflowRoot (treeShape = treeShape),
242+ setupProps = setupProps,
243+ testProps = testProps,
244+ expectedSetupRendering = expectedSetupRendering,
245+ expectedTestRendering = expectedTestRendering,
246+ )
247+
248+ private fun <PropsT > benchmarkPropsChange (
249+ workflow : Workflow <PropsT , Nothing , Int >,
250+ setupProps : PropsT ,
251+ testProps : PropsT ,
252+ expectedSetupRendering : Int ,
253+ expectedTestRendering : Int ,
167254 ) = runTest {
168- val workflow = BenchmarkWorkflowRoot (treeShape = treeShape)
169255 val props = MutableStateFlow (setupProps)
170256 val workflowJob = Job (parent = coroutineContext.job)
171257 val renderings = renderWorkflowIn(
@@ -454,3 +540,55 @@ private class ShallowWideWorkflowRoot(
454540 override fun snapshotState (state : Int ): Snapshot ? = null
455541 }
456542}
543+
544+ private class RememberHeavyWorkflow (
545+ private val entryCount : Int ,
546+ private val mixedInputTypes : Boolean = false ,
547+ ) : StatelessWorkflow<RememberHeavyWorkflow.Props, Nothing, Int>() {
548+ data class Props (
549+ val baseValue : Int ,
550+ val inputToken : Int ,
551+ )
552+
553+ override fun render (
554+ renderProps : Props ,
555+ context : RenderContext <Props , Nothing >
556+ ): Int {
557+ var rendering = 0
558+ repeat(entryCount) { index ->
559+ val input = if (mixedInputTypes && index % 2 == 0 ) {
560+ " token-${renderProps.inputToken} "
561+ } else {
562+ renderProps.inputToken
563+ }
564+ rendering + = context.remember(" remember-$index " , input) {
565+ renderProps.baseValue + index
566+ }
567+ }
568+ return rendering
569+ }
570+ }
571+
572+ private class StableHandlersWorkflow (
573+ private val handlerCount : Int ,
574+ ) : StatelessWorkflow<StableHandlersWorkflow.Props, Nothing, Int>() {
575+ data class Props (
576+ val salt : Int ,
577+ )
578+
579+ override fun render (
580+ renderProps : Props ,
581+ context : RenderContext <Props , Nothing >
582+ ): Int {
583+ var rendering = renderProps.salt
584+ repeat(handlerCount) { index ->
585+ context.eventHandler<Int >(name = " handler-$index " , remember = true ) { _ -> }
586+ rendering + = 1
587+ }
588+ return rendering
589+ }
590+ }
591+
592+ private fun rememberedRendering (baseValue : Int , entryCount : Int ): Int {
593+ return entryCount * baseValue + (entryCount * (entryCount - 1 ) / 2 )
594+ }
0 commit comments