From 612e10509492a0edf9150fa0093df0cefd791b49 Mon Sep 17 00:00:00 2001 From: Stephen Edwards Date: Fri, 12 Aug 2022 15:46:27 -0400 Subject: [PATCH] Add Simultaneous Worker Listener Actions Simulates multiple workers subscribing to same event and then triggering multiple actions all queued. --- .../complex/poetry/RenderPassTest.kt | 39 +++++++++++++++++-- .../complex/poetry/PerformancePoemWorkflow.kt | 11 ++++++ .../poetry/PerformancePoemsBrowserWorkflow.kt | 12 ++++++ .../poetry/PerformancePoetryActivity.kt | 2 + .../instrumentation/SimulatedPerfConfig.kt | 2 + 5 files changed, 63 insertions(+), 3 deletions(-) diff --git a/benchmarks/performance-poetry/complex-poetry/src/androidTest/java/com/squareup/benchmarks/performance/complex/poetry/RenderPassTest.kt b/benchmarks/performance-poetry/complex-poetry/src/androidTest/java/com/squareup/benchmarks/performance/complex/poetry/RenderPassTest.kt index 44972fb87..92e93ecc9 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/androidTest/java/com/squareup/benchmarks/performance/complex/poetry/RenderPassTest.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/androidTest/java/com/squareup/benchmarks/performance/complex/poetry/RenderPassTest.kt @@ -8,6 +8,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_PERF_CONFIG_INITIALIZING import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_PERF_CONFIG_REPEAT +import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_PERF_CONFIG_SIMULTANEOUS import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.EXTRA_RUNTIME_FRAME_TIMEOUT import com.squareup.benchmarks.performance.complex.poetry.cyborgs.landscapeOrientation import com.squareup.benchmarks.performance.complex.poetry.cyborgs.openRavenAndNavigate @@ -16,7 +17,6 @@ import com.squareup.benchmarks.performance.complex.poetry.cyborgs.waitForPoetry import com.squareup.benchmarks.performance.complex.poetry.instrumentation.RenderPassCountingInterceptor import org.junit.Assert.fail import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith @@ -30,6 +30,7 @@ class RenderPassTest { val title: String, val useInitializingState: Boolean, val useHighFrequencyRange: Boolean, + val simultaneousActions: Int, val baselineExpectation: RenderExpectation, val frameTimeoutExpectation: RenderExpectation ) @@ -68,6 +69,10 @@ class RenderPassTest { runRenderPassCounter(COMPLEX_NO_INITIALIZING_HIGH_FREQUENCY, useFrameTimeout = false) } + @Test fun renderPassCounterBaselineComplexNoInitializingStateSimultaneous() { + runRenderPassCounter(COMPLEX_NO_INITIALIZING_SIMULTANEOUS, useFrameTimeout = false) + } + @Test fun renderPassCounterFrameTimeoutComplexWithInitializingState() { runRenderPassCounter(COMPLEX_INITIALIZING, useFrameTimeout = true) } @@ -76,11 +81,14 @@ class RenderPassTest { runRenderPassCounter(COMPLEX_NO_INITIALIZING, useFrameTimeout = true) } - @Ignore("#841") @Test fun renderPassCounterFrameTimeoutComplexNoInitializingStateHighFrequencyEvents() { runRenderPassCounter(COMPLEX_NO_INITIALIZING_HIGH_FREQUENCY, useFrameTimeout = true) } + @Test fun renderPassCounterFrameTimeoutComplexNoInitializingStateSimultaneous() { + runRenderPassCounter(COMPLEX_NO_INITIALIZING_SIMULTANEOUS, useFrameTimeout = true) + } + private fun runRenderPassCounter( scenario: Scenario, useFrameTimeout: Boolean @@ -92,6 +100,10 @@ class RenderPassTest { EXTRA_PERF_CONFIG_INITIALIZING, scenario.useInitializingState ) + putExtra( + EXTRA_PERF_CONFIG_SIMULTANEOUS, + scenario.simultaneousActions + ) if (useFrameTimeout) { putExtra(EXTRA_RUNTIME_FRAME_TIMEOUT, useFrameTimeout) } @@ -220,6 +232,7 @@ class RenderPassTest { title = "the 'Raven navigation with initializing state scenario'", useInitializingState = true, useHighFrequencyRange = false, + simultaneousActions = 0, baselineExpectation = RenderExpectation( totalPasses = 57..57, freshRenderedNodes = 85..85, @@ -236,6 +249,7 @@ class RenderPassTest { title = "the 'Raven navigation (no initializing state) scenario'", useInitializingState = false, useHighFrequencyRange = false, + simultaneousActions = 0, baselineExpectation = RenderExpectation( totalPasses = 56..56, freshRenderedNodes = 83..83, @@ -266,18 +280,37 @@ class RenderPassTest { title = "the 'Raven navigation (no initializing state) scenario with high frequency events'", useInitializingState = false, useHighFrequencyRange = true, + simultaneousActions = 0, baselineExpectation = RenderExpectation( totalPasses = 181..181, freshRenderedNodes = 213..213, staleRenderedNodes = 2350..2350 ), frameTimeoutExpectation = RenderExpectation( - totalPasses = 88..97, + totalPasses = 88..97, // On Pixel 6: 56..61 freshRenderedNodes = 106..108, staleRenderedNodes = 679..698 ) ) + val COMPLEX_NO_INITIALIZING_SIMULTANEOUS = Scenario( + title = "the 'Raven navigation (no initializing state) scenario with simultaneous events" + + " AND high frequency events'", + useInitializingState = false, + useHighFrequencyRange = true, + simultaneousActions = 20, + baselineExpectation = RenderExpectation( + totalPasses = 762..762, + freshRenderedNodes = 253..253, + staleRenderedNodes = 38919..38919 + ), + frameTimeoutExpectation = RenderExpectation( + totalPasses = 88..97, // on Pixel 6: 56..61, + freshRenderedNodes = 176..180, + staleRenderedNodes = 4690..4700 + ) + ) + fun congrats( subject: String, value: String, diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemWorkflow.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemWorkflow.kt index a24d2cf55..9cfc4e592 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemWorkflow.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemWorkflow.kt @@ -63,6 +63,7 @@ class PerformancePoemWorkflow( ) : PoemWorkflow, StatefulWorkflow() { sealed class State { + val isLoading: Boolean = false // N.B. This state is a smell. We include it to be able to mimic smells // we encounter in real life. Best practice would be to fold it // into [Selected(NO_SELECTED_STANZA)] at the very least. @@ -95,6 +96,16 @@ class PerformancePoemWorkflow( renderState: State, context: RenderContext ): OverviewDetailScreen { + if (simulatedPerfConfig.simultaneousActions > 0) { + repeat(simulatedPerfConfig.simultaneousActions) { index -> + context.runningWorker( + worker = isLoading.asTraceableWorker("SimultaneousSubscribePoem-$index"), + key = "Poem-$index" + ) { + noAction() + } + } + } return when (renderState) { Initializing -> { // Again, the entire `Initializing` state is a smell, which is most obvious from the diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemsBrowserWorkflow.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemsBrowserWorkflow.kt index bb12e905c..9c5c1619e 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemsBrowserWorkflow.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoemsBrowserWorkflow.kt @@ -8,6 +8,7 @@ import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemsBrowse import com.squareup.benchmarks.performance.complex.poetry.instrumentation.ActionHandlingTracingInterceptor import com.squareup.benchmarks.performance.complex.poetry.instrumentation.SimulatedPerfConfig import com.squareup.benchmarks.performance.complex.poetry.instrumentation.TraceableWorker +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.asTraceableWorker import com.squareup.benchmarks.performance.complex.poetry.views.BlankScreen import com.squareup.sample.container.overviewdetail.OverviewDetailScreen import com.squareup.sample.poetry.PoemListScreen.Companion.NO_POEM_SELECTED @@ -18,6 +19,7 @@ import com.squareup.sample.poetry.PoemsBrowserWorkflow import com.squareup.sample.poetry.model.Poem import com.squareup.workflow1.Snapshot import com.squareup.workflow1.StatefulWorkflow +import com.squareup.workflow1.WorkflowAction.Companion.noAction import com.squareup.workflow1.action import com.squareup.workflow1.runningWorker import com.squareup.workflow1.ui.WorkflowUiExperimentalApi @@ -76,6 +78,16 @@ class PerformancePoemsBrowserWorkflow( renderState: State, context: RenderContext ): OverviewDetailScreen { + if (simulatedPerfConfig.simultaneousActions > 0) { + repeat(simulatedPerfConfig.simultaneousActions) { index -> + context.runningWorker( + worker = isLoading.asTraceableWorker("SimultaneousSubscribeBrowser-$index"), + key = "Browser-$index" + ) { + noAction() + } + } + } val poemListProps = Props( poems = renderProps, eventHandlerTag = ActionHandlingTracingInterceptor::keyForTrace diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoetryActivity.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoetryActivity.kt index 19d178423..509191ac6 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoetryActivity.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/PerformancePoetryActivity.kt @@ -66,6 +66,7 @@ class PerformancePoetryActivity : AppCompatActivity() { complexityDelay = intent.getLongExtra(EXTRA_PERF_CONFIG_DELAY, 200L), useInitializingState = intent.getBooleanExtra(EXTRA_PERF_CONFIG_INITIALIZING, false), repeatOnNext = intent.getIntExtra(EXTRA_PERF_CONFIG_REPEAT, 0), + simultaneousActions = intent.getIntExtra(EXTRA_PERF_CONFIG_SIMULTANEOUS, 0), traceFrameLatency = intent.getBooleanExtra(EXTRA_PERF_CONFIG_FRAME_LATENCY, false), traceEventLatency = intent.getBooleanExtra(EXTRA_PERF_CONFIG_ACTION_TRACING, false), traceRenderingPasses = intent.getBooleanExtra(EXTRA_PERF_CONFIG_RENDERING, false) @@ -241,6 +242,7 @@ class PerformancePoetryActivity : AppCompatActivity() { const val EXTRA_PERF_CONFIG_RENDERING = "complex.poetry.performance.config.track.rendering" const val EXTRA_PERF_CONFIG_REPEAT = "complex.poetry.performance.config.repeat.amount" const val EXTRA_PERF_CONFIG_DELAY = "complex.poetry.performance.config.delay.length" + const val EXTRA_PERF_CONFIG_SIMULTANEOUS = "complex.poetry.performance.config.simultaneous" const val EXTRA_RUNTIME_FRAME_TIMEOUT = "complex.poetry.performance.config.runtime.frametimeout" diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/SimulatedPerfConfig.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/SimulatedPerfConfig.kt index 0566f56b3..968712a04 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/SimulatedPerfConfig.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/SimulatedPerfConfig.kt @@ -17,6 +17,7 @@ data class SimulatedPerfConfig( val complexityDelay: Long, val useInitializingState: Boolean, val repeatOnNext: Int = 0, + val simultaneousActions: Int = 0, val traceRenderingPasses: Boolean = false, val traceFrameLatency: Boolean = false, val traceEventLatency: Boolean = false @@ -27,6 +28,7 @@ data class SimulatedPerfConfig( complexityDelay = 0, useInitializingState = false, repeatOnNext = 0, + simultaneousActions = 0, traceRenderingPasses = false, traceFrameLatency = false, traceEventLatency = false