diff --git a/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryBenchmarks.kt b/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryBenchmarks.kt index d31efaec32..dbe82c9b4b 100644 --- a/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryBenchmarks.kt +++ b/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryBenchmarks.kt @@ -14,12 +14,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity -import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion import com.squareup.benchmarks.performance.complex.poetry.instrumentation.PerformanceTracingInterceptor import com.squareup.benchmarks.performance.complex.poetry.instrumentation.PerformanceTracingInterceptor.Companion.NODES_TO_TRACE -import com.squareup.benchmarks.performance.complex.poetry.instrumentation.SimulatedPerfConfig -import com.squareup.benchmarks.performance.complex.poetry.robots.landscapeOrientation -import com.squareup.benchmarks.performance.complex.poetry.robots.openRavenAndNavigate +import com.squareup.benchmarks.performance.complex.poetry.cyborgs.landscapeOrientation +import com.squareup.benchmarks.performance.complex.poetry.cyborgs.openRavenAndNavigate import org.junit.Before import org.junit.Rule import org.junit.Test @@ -115,15 +113,11 @@ class ComplexPoetryBenchmarks { device.landscapeOrientation() } ) { - startActivityAndWait{ - val renderPassConfig = SimulatedPerfConfig( - isComplex = true, - complexityDelay = 200L, - useInitializingState = true, - traceRenderingPasses = true, - traceLatency = false - ) - it.putExtra(PerformancePoetryActivity.PERF_CONFIG_EXTRA, renderPassConfig) + startActivityAndWait { intent -> + intent.apply { + putExtra(PerformancePoetryActivity.EXTRA_PERF_CONFIG_INITIALIZING, true) + putExtra(PerformancePoetryActivity.EXTRA_PERF_CONFIG_RENDERING, true) + } } device.landscapeOrientation() @@ -139,21 +133,35 @@ class ComplexPoetryBenchmarks { } /** - * This test is focused on two different measurements: + * This test is focused on measuring the latency of Workflow's 'work'. By that we mean how much + * time Workflow spends producing the next set of updates to the View's that can be passed + * to Android to draw as a frame. * - * Frame-Latency-N: is the trace between passing the Rendering to the view layer and the - * 'post frame rendered callback' for the Nth frame in the scenario. In other words, this traces - * the time it takes from a Rendering produced by Workflow to process through the Workflow UI - * layer and then be rendered in the next frame. + * How do we measure this? The [EventHandlingTracingInterceptor] is a [WorkflowInterceptor] that + * sets up a [RenderContextInterceptor] which has a hook for everytime we 'send' an action to the + * [RenderContext]. Because this is done on the main thread, we can wrap this function call in a + * synchronous trace section as it will be equivalent to the main thread 'message' that handles + * all of the work before invoking the Choreographer to draw the updated Views. * - * XScreen-onY-Z: is the time between the execution of event handler 'onY' and the production of - * the next root Rendering by Workflow for the Zth instance of the 'onY' handler on X Screen. - * In other words, this measures the time Workflow takes in processing a UI event into a new - * Rendering. This will be similar to the render pass traced above, but more comprehensive to - * include all of the event handling time. + * We do this for certain [Worker]s results by annotating the [Worker] with a pattern in + * its [toString()] - see [TraceableWorker]. + * We do this for UI events by adding in an injected name to the eventHandler. + * + * These are formatted as: + * - "Worker--Finished-XX" + * - "E---XX" + * + * Where XX is the counted instance of that event's response. */ @OptIn(ExperimentalMetricApi::class) fun benchmarkLatencyTraceSections(compilationMode: CompilationMode) { + fun addLatency(intent: Intent) { + intent.apply { + putExtra(PerformancePoetryActivity.EXTRA_PERF_CONFIG_INITIALIZING, true) + putExtra(PerformancePoetryActivity.EXTRA_PERF_CONFIG_EVENT_LATENCY, true) + } + } + benchmarkRule.measureRepeated( packageName = PACKAGE_NAME, metrics = LATENCY_TRACE_SECTIONS.map { TraceSectionMetric(it) }, @@ -165,68 +173,46 @@ class ComplexPoetryBenchmarks { device.landscapeOrientation() } ) { - startActivityAndWait{ - val renderPassConfig = SimulatedPerfConfig( - isComplex = true, - complexityDelay = 200L, - useInitializingState = true, - traceRenderingPasses = false, - traceLatency = true - ) - it.putExtra(PerformancePoetryActivity.PERF_CONFIG_EXTRA, renderPassConfig) - } + startActivityAndWait(::addLatency) device.landscapeOrientation() + device.waitForIdle() device.openRavenAndNavigate() } } companion object { - const val RENDER_PASSES = 61 + const val RENDER_PASSES = 58 const val PACKAGE_NAME = "com.squareup.benchmarks.performance.complex.poetry" val LATENCY_TRACE_SECTIONS = listOf( - "PoemListScreen-onPoemSelected(2)-1 ", - "StanzaListScreen-onStanzaSelected(4)-1 ", - "StanzaScreen-onGoForth-1 ", - "StanzaScreen-onGoForth-2 ", - "StanzaScreen-onGoForth-3 ", - "StanzaScreen-onGoForth-4 ", - "StanzaScreen-onGoForth-5 ", - "StanzaScreen-onGoBack-1 ", - "StanzaScreen-onGoBack-2 ", - "StanzaScreen-onGoBack-3 ", - "StanzaScreen-onGoBack-4 ", - "StanzaScreen-onGoBack-5 ", - "StanzaListScreen-onExit-1 ", - "Frame-Latency-00 ", - "Frame-Latency-01 ", - "Frame-Latency-02 ", - "Frame-Latency-03 ", - "Frame-Latency-04 ", - "Frame-Latency-05 ", - "Frame-Latency-06 ", - "Frame-Latency-07 ", - "Frame-Latency-08 ", - "Frame-Latency-09 ", - "Frame-Latency-10 ", - "Frame-Latency-11 ", - "Frame-Latency-12 ", - "Frame-Latency-13 ", - "Frame-Latency-14 ", - "Frame-Latency-15 ", - "Frame-Latency-16 ", - "Frame-Latency-17 ", - "Frame-Latency-18 ", - "Frame-Latency-19 ", - "Frame-Latency-20 ", - "Frame-Latency-21 ", - "Frame-Latency-22 ", - "Frame-Latency-23 ", - "Frame-Latency-24 ", - "Frame-Latency-25 ", - "Frame-Latency-26 ", - "Frame-Latency-27 ", + "E-PoemList-PoemSelected-00", + "Worker-ComplexCallBrowser(2)-Finished-00", + "Worker-PoemLoading-Finished-00", + "E-StanzaList-StanzaSelected-00", + "Worker-PoemLoading-Finished-01", + "E-StanzaWorkflow-ShowNextStanza-00", + "Worker-PoemLoading-Finished-02", + "E-StanzaWorkflow-ShowNextStanza-01", + "Worker-PoemLoading-Finished-03", + "E-StanzaWorkflow-ShowNextStanza-02", + "Worker-PoemLoading-Finished-04", + "E-StanzaWorkflow-ShowNextStanza-03", + "Worker-PoemLoading-Finished-05", + "E-StanzaWorkflow-ShowNextStanza-04", + "Worker-PoemLoading-Finished-06", + "E-StanzaWorkflow-ShowPreviousStanza-00", + "Worker-PoemLoading-Finished-07", + "E-StanzaWorkflow-ShowPreviousStanza-01", + "Worker-PoemLoading-Finished-08", + "E-StanzaWorkflow-ShowPreviousStanza-02", + "Worker-PoemLoading-Finished-09", + "E-StanzaWorkflow-ShowPreviousStanza-03", + "Worker-PoemLoading-Finished-10", + "E-StanzaWorkflow-ShowPreviousStanza-04", + "Worker-PoemLoading-Finished-11", + "E-StanzaList-Exit-00", + "Worker-ComplexCallBrowser(-1)-Finished-00", ) } } diff --git a/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryGatherBaseline.kt b/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryGatherBaseline.kt index 6167e2ae10..f2d1c5c769 100644 --- a/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryGatherBaseline.kt +++ b/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryGatherBaseline.kt @@ -7,7 +7,7 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.squareup.benchmarks.performance.complex.poetry.benchmark.ComplexPoetryBenchmarks.Companion.PACKAGE_NAME -import com.squareup.benchmarks.performance.complex.poetry.robots.openRavenAndNavigate +import com.squareup.benchmarks.performance.complex.poetry.cyborgs.openRavenAndNavigate import org.junit.Before import org.junit.Rule import org.junit.Test diff --git a/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryResults.txt b/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryResults.txt index e9d6d936be..f99389ee99 100644 --- a/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryResults.txt +++ b/benchmarks/performance-poetry/complex-benchmark/src/main/java/com/squareup/benchmarks/performance/complex/poetry/benchmark/ComplexPoetryResults.txt @@ -188,55 +188,220 @@ ComplexPoetryBenchmarks_benchmarkTraceSectionsFullAOT 060_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.0, median 0.0, max 0.0 Traces: Iteration 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 +May 13, 2022 -May 6, 2022 > Task :benchmarks:performance-poetry:complex-benchmark:connectedBenchmarkAndroidTest Starting 1 tests on Pixel 6 - 12 -Connected to process 8330 on device 'google-pixel_6-1C041FDF60017G'. -ComplexPoetryBenchmarks_benchmarkLatencySections -Frame-Latency-00 Ms min 41.8, median 45.7, max 57.9 -Frame-Latency-01 Ms min 68.2, median 96.1, max 125.8 -Frame-Latency-02 Ms min 5.1, median 14.0, max 19.0 -Frame-Latency-03 Ms min 15.0, median 23.6, max 35.9 -Frame-Latency-04 Ms min 59.0, median 65.9, max 79.4 -Frame-Latency-05 Ms min 16.8, median 28.3, max 40.3 -Frame-Latency-06 Ms min 58.6, median 70.0, max 78.5 -Frame-Latency-07 Ms min 24.0, median 29.1, max 35.9 -Frame-Latency-08 Ms min 58.8, median 67.2, max 73.0 -Frame-Latency-09 Ms min 26.2, median 32.7, max 39.1 -Frame-Latency-10 Ms min 58.5, median 67.1, max 79.0 -Frame-Latency-11 Ms min 17.7, median 32.5, max 38.3 -Frame-Latency-12 Ms min 53.8, median 70.8, max 79.5 -Frame-Latency-13 Ms min 23.4, median 30.9, max 35.3 -Frame-Latency-14 Ms min 57.9, median 67.0, max 74.9 -Frame-Latency-15 Ms min 22.7, median 30.7, max 39.8 -Frame-Latency-16 Ms min 57.3, median 66.6, max 72.3 -Frame-Latency-17 Ms min 27.6, median 32.9, max 36.8 -Frame-Latency-18 Ms min 54.1, median 65.6, max 74.0 -Frame-Latency-19 Ms min 17.5, median 32.1, max 39.2 -Frame-Latency-20 Ms min 55.6, median 63.5, max 75.6 -Frame-Latency-21 Ms min 25.7, median 31.6, max 39.3 -Frame-Latency-22 Ms min 55.6, median 64.5, max 75.4 -Frame-Latency-23 Ms min 23.3, median 29.6, max 34.4 -Frame-Latency-24 Ms min 57.7, median 67.0, max 72.8 -Frame-Latency-25 Ms min 25.7, median 31.6, max 36.3 -Frame-Latency-26 Ms min 35.1, median 41.6, max 68.9 -Frame-Latency-27 Ms min 18.4, median 24.3, max 33.7 -PoemListScreen-onPoemSelected(2)-1 Ms min 1.5, median 1.6, max 3.8 -StanzaListScreen-onExit-1 Ms min 0.6, median 0.7, max 1.1 -StanzaListScreen-onStanzaSelected(4)-1 Ms min 0.7, median 1.0, max 1.3 -StanzaScreen-onGoBack-1 Ms min 0.7, median 0.8, max 1.1 -StanzaScreen-onGoBack-2 Ms min 0.6, median 0.8, max 1.7 -StanzaScreen-onGoBack-3 Ms min 0.7, median 0.8, max 1.5 -StanzaScreen-onGoBack-4 Ms min 0.7, median 0.8, max 1.1 -StanzaScreen-onGoBack-5 Ms min 0.6, median 0.8, max 1.4 -StanzaScreen-onGoForth-1 Ms min 0.9, median 1.2, max 1.7 -StanzaScreen-onGoForth-2 Ms min 0.6, median 0.9, max 1.7 -StanzaScreen-onGoForth-3 Ms min 0.6, median 0.8, max 1.2 -StanzaScreen-onGoForth-4 Ms min 0.7, median 0.8, max 1.1 -StanzaScreen-onGoForth-5 Ms min 0.6, median 0.8, max 1.3 +ComplexPoetryBenchmarks_benchmarkNodeAndRenderPassTraceSectionsFullAot +000_Render_Pass_Ms min 0.2, median 0.3, max 0.8 +000_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.0, max 0.1 +000_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.6 +001_Render_Pass_Ms min 0.1, median 0.1, max 0.3 +001_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.0, max 0.1 +001_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.3 +002_Render_Pass_Ms min 0.1, median 0.1, max 0.1 +002_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.0, max 0.0 +002_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.0, median 0.0, max 0.1 +003_Render_Pass_Ms min 0.1, median 0.1, max 0.3 +003_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +003_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.2 +004_Render_Pass_Ms min 0.2, median 0.2, max 0.4 +004_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.1 +004_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.3 +005_Render_Pass_Ms min 0.1, median 0.2, max 0.3 +005_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.1, max 0.1 +005_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.2 +006_Render_Pass_Ms min 0.2, median 0.6, max 0.9 +006_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.2, max 0.4 +006_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.3, max 0.6 +007_Render_Pass_Ms min 0.1, median 0.2, max 0.3 +007_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.1, max 0.2 +007_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +008_Render_Pass_Ms min 0.2, median 0.6, max 1.2 +008_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +008_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.4, max 1.0 +009_Render_Pass_Ms min 0.1, median 0.2, max 0.3 +009_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.0, max 0.1 +009_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.2 +010_Render_Pass_Ms min 0.4, median 0.5, max 0.7 +010_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.4 +010_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.6 +011_Render_Pass_Ms min 0.1, median 0.2, max 0.3 +011_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +011_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.2 +012_Render_Pass_Ms min 0.3, median 0.7, max 0.9 +012_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.2, max 0.3 +012_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.5, max 0.6 +013_Render_Pass_Ms min 0.1, median 0.2, max 0.3 +013_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.1, max 0.2 +013_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +014_Render_Pass_Ms min 0.4, median 0.5, max 0.9 +014_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.6 +014_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.7 +015_Render_Pass_Ms min 0.2, median 0.2, max 0.3 +015_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.1 +015_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.2 +016_Render_Pass_Ms min 0.2, median 0.7, max 0.9 +016_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.3, max 0.4 +016_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.5, max 0.7 +017_Render_Pass_Ms min 0.1, median 0.3, max 0.3 +017_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.1, max 0.2 +017_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +018_Render_Pass_Ms min 0.3, median 0.6, max 0.7 +018_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.5 +018_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.4, max 0.6 +019_Render_Pass_Ms min 0.2, median 0.2, max 0.3 +019_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.1 +019_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.2 +020_Render_Pass_Ms min 0.2, median 0.7, max 1.0 +020_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.3, max 0.5 +020_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.5, max 0.7 +021_Render_Pass_Ms min 0.1, median 0.3, max 0.3 +021_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.1, max 0.2 +021_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.0, median 0.2, max 0.2 +022_Render_Pass_Ms min 0.4, median 0.5, max 0.6 +022_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.3 +022_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.4 +023_Render_Pass_Ms min 0.1, median 0.2, max 0.3 +023_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.1 +023_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +024_Render_Pass_Ms min 0.7, median 0.8, max 0.9 +024_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.3, median 0.3, max 0.5 +024_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.5, median 0.5, max 0.7 +025_Render_Pass_Ms min 0.2, median 0.3, max 0.8 +025_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.6 +025_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.2, max 0.7 +026_Render_Pass_Ms min 0.4, median 0.6, max 0.9 +026_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.3, median 0.3, max 0.6 +026_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.7 +027_Render_Pass_Ms min 0.1, median 0.2, max 0.4 +027_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +027_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.3 +028_Render_Pass_Ms min 0.7, median 0.8, max 0.9 +028_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.3, median 0.3, max 0.4 +028_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.5, median 0.5, max 0.7 +029_Render_Pass_Ms min 0.2, median 0.3, max 0.3 +029_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.2, max 0.2 +029_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.2, max 0.3 +030_Render_Pass_Ms min 0.4, median 0.5, max 0.7 +030_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.3, median 0.3, max 0.5 +030_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.6 +031_Render_Pass_Ms min 0.2, median 0.2, max 0.4 +031_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +031_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +032_Render_Pass_Ms min 0.4, median 0.8, max 1.0 +032_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.6 +032_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.6, max 0.8 +033_Render_Pass_Ms min 0.2, median 0.3, max 0.4 +033_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.2, max 0.2 +033_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.3 +034_Render_Pass_Ms min 0.4, median 0.6, max 0.9 +034_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.5 +034_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.7 +035_Render_Pass_Ms min 0.2, median 0.2, max 0.4 +035_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +035_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.3 +036_Render_Pass_Ms min 0.3, median 0.7, max 0.9 +036_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.3, max 0.4 +036_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.5, max 0.6 +037_Render_Pass_Ms min 0.1, median 0.3, max 0.3 +037_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.2, max 0.2 +037_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.3 +038_Render_Pass_Ms min 0.4, median 0.5, max 0.6 +038_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.4 +038_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.5 +039_Render_Pass_Ms min 0.1, median 0.2, max 0.4 +039_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +039_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.3 +040_Render_Pass_Ms min 0.3, median 0.8, max 0.9 +040_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.3, max 0.5 +040_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.5, max 0.7 +041_Render_Pass_Ms min 0.1, median 0.3, max 0.4 +041_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.2, max 0.2 +041_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +042_Render_Pass_Ms min 0.4, median 0.6, max 0.8 +042_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.5 +042_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.6 +043_Render_Pass_Ms min 0.2, median 0.2, max 0.3 +043_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +043_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +044_Render_Pass_Ms min 0.4, median 0.7, max 0.9 +044_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.5 +044_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.5, max 0.7 +045_Render_Pass_Ms min 0.2, median 0.3, max 0.4 +045_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +045_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.2 +046_Render_Pass_Ms min 0.4, median 0.5, max 0.7 +046_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.4 +046_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.4, max 0.5 +047_Render_Pass_Ms min 0.1, median 0.2, max 0.3 +047_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.1 +047_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.2 +048_Render_Pass_Ms min 0.4, median 0.7, max 0.8 +048_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.2, max 0.4 +048_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.3, median 0.5, max 0.6 +049_Render_Pass_Ms min 0.2, median 0.3, max 0.4 +049_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.1, median 0.1, max 0.2 +049_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.3 +050_Render_Pass_Ms min 0.3, median 0.5, max 1.0 +050_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.3, max 0.5 +050_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.4, max 0.8 +051_Render_Pass_Ms min 0.1, median 0.2, max 1.8 +051_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.1, max 1.6 +051_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 1.7 +052_Render_Pass_Ms min 0.6, median 0.7, max 0.8 +052_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.2, median 0.2, max 0.3 +052_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.4, median 0.5, max 0.6 +053_Render_Pass_Ms min 0.1, median 0.2, max 0.4 +053_Render_Pass_Node_PerformancePoemWorkflow_Ms min 0.0, median 0.1, max 0.2 +053_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.2, max 0.3 +054_Render_Pass_Ms min 0.3, median 0.4, max 0.5 +054_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.2, median 0.2, max 0.3 +055_Render_Pass_Ms min 0.1, median 0.1, max 0.2 +055_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.0, median 0.0, max 0.1 +056_Render_Pass_Ms min 0.2, median 0.4, max 0.5 +056_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.1, median 0.1, max 0.1 +057_Render_Pass_Ms min 0.1, median 0.1, max 0.1 +057_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.0, median 0.0, max 0.0 +058_Render_Pass_Ms min 0.2, median 0.2, max 0.6 +058_Render_Pass_Node_PerformancePoemsBrowserWorkflow_Ms min 0.0, median 0.1, max 0.2 Traces: Iteration 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + +May 13, 2022 + > Task :benchmarks:performance-poetry:complex-benchmark:connectedBenchmarkAndroidTest +Starting 1 tests on Pixel 6 - 12 +Connected to process 11952 on device 'google-pixel_6-1C041FDF60017G'. + +ComplexPoetryBenchmarks_benchmarkLatencyTraceSectionsFullAot +E-PoemList-PoemSelected-00Ms min 16.0, median 20.3, max 25.5 +E-StanzaList-Exit-00Ms min 12.3, median 18.5, max 24.6 +E-StanzaList-StanzaSelected-00Ms min 18.1, median 21.4, max 26.8 +E-StanzaWorkflow-ShowNextStanza-00Ms min 14.2, median 22.7, max 27.7 +E-StanzaWorkflow-ShowNextStanza-01Ms min 15.3, median 22.4, max 26.2 +E-StanzaWorkflow-ShowNextStanza-02Ms min 17.7, median 22.2, max 29.5 +E-StanzaWorkflow-ShowNextStanza-03Ms min 17.9, median 22.4, max 29.5 +E-StanzaWorkflow-ShowNextStanza-04Ms min 18.8, median 23.4, max 26.9 +E-StanzaWorkflow-ShowPreviousStanza-00Ms min 19.0, median 21.7, max 28.8 +E-StanzaWorkflow-ShowPreviousStanza-01Ms min 17.4, median 22.4, max 27.4 +E-StanzaWorkflow-ShowPreviousStanza-02Ms min 17.0, median 21.7, max 31.2 +E-StanzaWorkflow-ShowPreviousStanza-03Ms min 18.2, median 21.8, max 30.5 +E-StanzaWorkflow-ShowPreviousStanza-04Ms min 14.6, median 21.7, max 26.6 +Worker-ComplexCallBrowser(-1)-Finished-00Ms min 14.4, median 18.6, max 23.9 +Worker-ComplexCallBrowser(2)-Finished-00Ms min 4.4, median 7.6, max 9.0 +Worker-PoemLoading-Finished-00Ms min 11.5, median 17.1, max 22.6 +Worker-PoemLoading-Finished-01Ms min 16.8, median 21.6, max 26.4 +Worker-PoemLoading-Finished-02Ms min 16.5, median 20.9, max 28.0 +Worker-PoemLoading-Finished-03Ms min 15.1, median 20.5, max 36.5 +Worker-PoemLoading-Finished-04Ms min 16.8, median 20.2, max 30.3 +Worker-PoemLoading-Finished-05Ms min 18.7, median 21.2, max 24.5 +Worker-PoemLoading-Finished-06Ms min 17.4, median 21.6, max 24.3 +Worker-PoemLoading-Finished-07Ms min 17.0, median 20.9, max 24.5 +Worker-PoemLoading-Finished-08Ms min 16.7, median 20.4, max 23.2 +Worker-PoemLoading-Finished-09Ms min 17.0, median 21.1, max 23.8 +Worker-PoemLoading-Finished-10Ms min 16.5, median 21.1, max 27.8 +Worker-PoemLoading-Finished-11Ms min 17.1, median 19.6, max 24.2 +Traces: Iteration 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 diff --git a/benchmarks/performance-poetry/complex-poetry/build.gradle.kts b/benchmarks/performance-poetry/complex-poetry/build.gradle.kts index dfbd77f23f..1b141a7fb3 100644 --- a/benchmarks/performance-poetry/complex-poetry/build.gradle.kts +++ b/benchmarks/performance-poetry/complex-poetry/build.gradle.kts @@ -60,7 +60,6 @@ dependencies { implementation(libs.androidx.recyclerview) implementation(libs.androidx.test.uiautomator) implementation(libs.androidx.tracing.ktx) - implementation(libs.squareup.tart) implementation(libs.timber) androidTestImplementation(project(":workflow-ui:internal-testing-android")) 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 cfbc6f156a..0ee7c78d78 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 @@ -6,13 +6,13 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice -import com.squareup.benchmarks.performance.complex.poetry.PerformancePoetryActivity.Companion.PERF_CONFIG_EXTRA +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_RENDERING +import com.squareup.benchmarks.performance.complex.poetry.cyborgs.landscapeOrientation +import com.squareup.benchmarks.performance.complex.poetry.cyborgs.openRavenAndNavigate +import com.squareup.benchmarks.performance.complex.poetry.cyborgs.resetToRootPoetryList +import com.squareup.benchmarks.performance.complex.poetry.cyborgs.waitForPoetry import com.squareup.benchmarks.performance.complex.poetry.instrumentation.RenderPassCountingInterceptor -import com.squareup.benchmarks.performance.complex.poetry.instrumentation.SimulatedPerfConfig -import com.squareup.benchmarks.performance.complex.poetry.robots.landscapeOrientation -import com.squareup.benchmarks.performance.complex.poetry.robots.openRavenAndNavigate -import com.squareup.benchmarks.performance.complex.poetry.robots.resetToRootPoetryList -import com.squareup.benchmarks.performance.complex.poetry.robots.waitForPoetry import org.junit.Assert.fail import org.junit.Before import org.junit.Test @@ -26,7 +26,7 @@ import org.junit.runner.RunWith class RenderPassTest { data class Scenario( val title: String, - val config: SimulatedPerfConfig, + val useInitializingState: Boolean, val expectedPasses: Int, val expectedFreshRenderings: Int, val expectedStaleRenderings: Int @@ -60,7 +60,11 @@ class RenderPassTest { val intent = Intent(context, PerformancePoetryActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - putExtra(PERF_CONFIG_EXTRA, scenario.config) + putExtra( + EXTRA_PERF_CONFIG_INITIALIZING, + scenario.useInitializingState + ) + putExtra(EXTRA_PERF_CONFIG_RENDERING, true) } InstrumentationRegistry.getInstrumentation().context.startActivity(intent) @@ -171,11 +175,7 @@ class RenderPassTest { companion object { val COMPLEX_INITIALIZING = Scenario( title = "the 'Raven navigation with initializing state scenario'", - config = SimulatedPerfConfig( - isComplex = true, - useInitializingState = true, - complexityDelay = 100L - ), + useInitializingState = true, expectedPasses = 58, expectedFreshRenderings = 85, expectedStaleRenderings = 617 @@ -183,11 +183,7 @@ class RenderPassTest { val COMPLEX_NO_INITIALIZING = Scenario( title = "the 'Raven navigation (no initializing state) scenario'", - config = SimulatedPerfConfig( - isComplex = true, - useInitializingState = false, - complexityDelay = 100L - ), + useInitializingState = false, expectedPasses = 56, expectedFreshRenderings = 83, expectedStaleRenderings = 605 diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/AndroidManifest.xml b/benchmarks/performance-poetry/complex-poetry/src/main/AndroidManifest.xml index e7a56a8ec3..2e48d8fc2a 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/AndroidManifest.xml +++ b/benchmarks/performance-poetry/complex-poetry/src/main/AndroidManifest.xml @@ -21,9 +21,12 @@ android:exported="true"> - + + + + diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/MaybeLoadingGatekeeperWorkflow.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/MaybeLoadingGatekeeperWorkflow.kt index 9275b53326..bc3c448bf9 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/MaybeLoadingGatekeeperWorkflow.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/MaybeLoadingGatekeeperWorkflow.kt @@ -1,5 +1,7 @@ package com.squareup.benchmarks.performance.complex.poetry +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.EventHandlingTracingInterceptor +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.asTraceableWorker import com.squareup.benchmarks.performance.complex.poetry.views.LoaderSpinner import com.squareup.benchmarks.performance.complex.poetry.views.MayBeLoadingScreen import com.squareup.sample.container.overviewdetail.OverviewDetailScreen @@ -7,7 +9,6 @@ import com.squareup.workflow1.Snapshot import com.squareup.workflow1.StatefulWorkflow import com.squareup.workflow1.Workflow import com.squareup.workflow1.action -import com.squareup.workflow1.asWorker import com.squareup.workflow1.runningWorker import com.squareup.workflow1.ui.WorkflowUiExperimentalApi import kotlinx.coroutines.flow.Flow @@ -30,14 +31,18 @@ class MaybeLoadingGatekeeperWorkflow( renderState: IsLoading, context: RenderContext ): MayBeLoadingScreen { - context.runningWorker(isLoading.asWorker()) { + context.runningWorker(isLoading.asTraceableWorker("GatekeeperLoading")) { action { state = it } } return MayBeLoadingScreen( baseScreen = context.renderChild(childWithLoading, childProps) { - action { setOutput(Unit) } + action(EventHandlingTracingInterceptor.keyForTrace("GatekeeperChildFinished")) { + setOutput( + Unit + ) + } }, loaders = if (renderState) listOf(LoaderSpinner) else emptyList() ) 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 256c04454b..452ead2187 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 @@ -8,8 +8,9 @@ import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemWorkflo import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemWorkflow.State.ComplexCall import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemWorkflow.State.Initializing import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemWorkflow.State.Selected +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.EventHandlingTracingInterceptor import com.squareup.benchmarks.performance.complex.poetry.instrumentation.SimulatedPerfConfig -import com.squareup.benchmarks.performance.complex.poetry.instrumentation.trace +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.TraceableWorker import com.squareup.benchmarks.performance.complex.poetry.views.BlankScreen import com.squareup.sample.container.overviewdetail.OverviewDetailScreen import com.squareup.sample.poetry.PoemWorkflow @@ -92,7 +93,7 @@ class PerformancePoemWorkflow( // use of `Worker.from { Unit }`. A Worker doing no work and only shuttling the state // along is usually the sign you have an extraneous state that can be collapsed! // Don't try this at home. - context.runningWorker(Worker.from { Unit }, "initializing") { + context.runningWorker(Worker.from { }, "initializing") { isLoading.value = true action { isLoading.value = false @@ -110,7 +111,7 @@ class PerformancePoemWorkflow( if (currentStateIsLoading) { context.runningWorker( - Worker.from { + TraceableWorker.from("PoemLoading") { isLoading.value = true delay(simulatedPerfConfig.complexityDelay) // No Output for Worker is necessary because the selected index @@ -130,11 +131,19 @@ class PerformancePoemWorkflow( if (stanzaIndex == NO_SELECTED_STANZA) emptyList() else renderProps.stanzas.subList(0, stanzaIndex) .mapIndexed { index, _ -> - context.renderChild(StanzaWorkflow, Props(renderProps, index), "$index") { + context.renderChild( + StanzaWorkflow, + Props( + poem = renderProps, + index = index, + eventHandlerTag = EventHandlingTracingInterceptor::keyForTrace + ), + key = "$index" + ) { noAction() } }.map { originalStanzaScreen -> - originalStanzaScreen.trace() + originalStanzaScreen } val visibleStanza = @@ -142,14 +151,20 @@ class PerformancePoemWorkflow( null } else { context.renderChild( - StanzaWorkflow, Props(renderProps, stanzaIndex), "$stanzaIndex" + StanzaWorkflow, + Props( + poem = renderProps, + index = stanzaIndex, + eventHandlerTag = EventHandlingTracingInterceptor::keyForTrace + ), + key = "$stanzaIndex" ) { when (it) { CloseStanzas -> ClearSelection(simulatedPerfConfig) ShowPreviousStanza -> SelectPrevious(simulatedPerfConfig) ShowNextStanza -> SelectNext(simulatedPerfConfig) } - }.trace() + } } val stackedStanzas = visibleStanza?.let { @@ -159,12 +174,14 @@ class PerformancePoemWorkflow( val stanzaListOverview = context.renderChild( StanzaListWorkflow, - renderProps + StanzaListWorkflow.Props( + poem = renderProps, + eventHandlerTag = EventHandlingTracingInterceptor::keyForTrace + ) ) { selected -> HandleStanzaListOutput(simulatedPerfConfig, selected) } .copy(selection = stanzaIndex) - .trace() stackedStanzas ?.let { @@ -188,8 +205,11 @@ class PerformancePoemWorkflow( abstract val simulatedPerfConfig: SimulatedPerfConfig class ClearSelection(override val simulatedPerfConfig: SimulatedPerfConfig) : Action() + class SelectPrevious(override val simulatedPerfConfig: SimulatedPerfConfig) : Action() + class SelectNext(override val simulatedPerfConfig: SimulatedPerfConfig) : Action() + class HandleStanzaListOutput( override val simulatedPerfConfig: SimulatedPerfConfig, val selection: Int 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 133cf0ec24..4f0942f443 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 @@ -5,18 +5,19 @@ import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemsBrowse import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemsBrowserWorkflow.State.Initializing import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemsBrowserWorkflow.State.NoSelection import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemsBrowserWorkflow.State.Selected +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.EventHandlingTracingInterceptor import com.squareup.benchmarks.performance.complex.poetry.instrumentation.SimulatedPerfConfig -import com.squareup.benchmarks.performance.complex.poetry.instrumentation.trace +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.TraceableWorker 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 import com.squareup.sample.poetry.PoemListWorkflow +import com.squareup.sample.poetry.PoemListWorkflow.Props import com.squareup.sample.poetry.PoemWorkflow 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.Worker import com.squareup.workflow1.action import com.squareup.workflow1.runningWorker import com.squareup.workflow1.ui.WorkflowUiExperimentalApi @@ -75,7 +76,11 @@ class PerformancePoemsBrowserWorkflow( renderState: State, context: RenderContext ): OverviewDetailScreen { - val poemListRendering = context.renderChild(PoemListWorkflow, renderProps) { selected -> + val poemListProps = Props( + poems = renderProps, + eventHandlerTag = EventHandlingTracingInterceptor::keyForTrace + ) + val poemListRendering = context.renderChild(PoemListWorkflow, poemListProps) { selected -> choosePoem(selected) } when (renderState) { @@ -84,7 +89,7 @@ class PerformancePoemsBrowserWorkflow( // along is usually the sign you have an extraneous state that can be collapsed! // Don't try this at home. is Initializing -> { - context.runningWorker(Worker.from { Unit }, "initializing") { + context.runningWorker(TraceableWorker.from("BrowserInitializing") { Unit }, "init") { isLoading.value = true action { isLoading.value = false @@ -96,13 +101,13 @@ class PerformancePoemsBrowserWorkflow( is NoSelection -> { return OverviewDetailScreen( overviewRendering = BackStackScreen( - poemListRendering.copy(selection = NO_POEM_SELECTED).trace() + poemListRendering.copy(selection = NO_POEM_SELECTED) ) ) } is ComplexCall -> { context.runningWorker( - Worker.from { + TraceableWorker.from("ComplexCallBrowser(${renderState.payload})") { isLoading.value = true delay(simulatedPerfConfig.complexityDelay) // No Output for Worker is necessary because the selected index @@ -122,7 +127,7 @@ class PerformancePoemsBrowserWorkflow( } var poems = OverviewDetailScreen( overviewRendering = BackStackScreen( - poemListRendering.copy(selection = renderState.payload).trace() + poemListRendering.copy(selection = renderState.payload) ) ) if (renderState.payload != NO_POEM_SELECTED) { @@ -137,7 +142,7 @@ class PerformancePoemsBrowserWorkflow( is Selected -> { val poems = OverviewDetailScreen( overviewRendering = BackStackScreen( - poemListRendering.copy(selection = renderState.poemIndex).trace() + poemListRendering.copy(selection = renderState.poemIndex) ) ) val poem: OverviewDetailScreen = context.renderChild( @@ -153,7 +158,7 @@ class PerformancePoemsBrowserWorkflow( private fun choosePoem( index: Int - ) = action("goToPoem") { + ) = action { state = if (simulatedPerfConfig.isComplex) { ComplexCall(payload = index) } else { 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 a2b2aad192..d73d30362d 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 @@ -1,5 +1,7 @@ package com.squareup.benchmarks.performance.complex.poetry +import android.content.pm.ApplicationInfo +import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper @@ -12,9 +14,10 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.savedstate.SavedStateRegistryOwner import androidx.tracing.Trace +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.EventHandlingTracingInterceptor import com.squareup.benchmarks.performance.complex.poetry.instrumentation.PerformanceTracingInterceptor +import com.squareup.benchmarks.performance.complex.poetry.instrumentation.Resettable import com.squareup.benchmarks.performance.complex.poetry.instrumentation.SimulatedPerfConfig -import com.squareup.benchmarks.performance.complex.poetry.instrumentation.WorkflowUiEventsTracer import com.squareup.sample.container.SampleContainers import com.squareup.sample.poetry.model.Poem import com.squareup.workflow1.WorkflowInterceptor @@ -49,36 +52,53 @@ class PerformancePoetryActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + val debuggable = (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0 + val profileable = applicationInfo.isProfileableByShell + val traceMain = intent.getBooleanExtra(EXTRA_TRACE_ALL_MAIN_THREADS, false) + + if (traceMain && Build.VERSION.SDK_INT != 28 && (debuggable || profileable)) { + // Add main message tracing to see everything happening in Perfetto. + // See https://py.hashnode.dev/tracing-main-thread-messages for more background. + Looper.getMainLooper().setMessageLogging { log -> + if (!Trace.isEnabled()) { + return@setMessageLogging + } + if (log.startsWith('>')) { + val label = buildSectionLabel(log) + Trace.beginSection(label.take(127)) + } else if (log.startsWith('<')) { + Trace.endSection() + } + } + } + // Default is just to have the basic 'delay' complexity. - var simulatedPerfConfig = SimulatedPerfConfig( + val simulatedPerfConfig = SimulatedPerfConfig( isComplex = true, complexityDelay = 200L, - useInitializingState = false, - traceLatency = false, - traceRenderingPasses = false + useInitializingState = intent.getBooleanExtra(EXTRA_PERF_CONFIG_INITIALIZING, false), + traceFrameLatency = intent.getBooleanExtra(EXTRA_PERF_CONFIG_FRAME_LATENCY, false), + traceEventLatency = intent.getBooleanExtra(EXTRA_PERF_CONFIG_EVENT_LATENCY, false), + traceRenderingPasses = intent.getBooleanExtra(EXTRA_PERF_CONFIG_RENDERING, false) ) - intent.extras?.let { - (it.get(PERF_CONFIG_EXTRA) as? SimulatedPerfConfig)?.let { config -> - simulatedPerfConfig = config - } - } - - require(!(simulatedPerfConfig.traceLatency && simulatedPerfConfig.traceRenderingPasses)) { - "Only trace latency OR rendering passes." + require(!(simulatedPerfConfig.traceFrameLatency && simulatedPerfConfig.traceRenderingPasses)) { + "Only trace render latency OR rendering passes." } // If no interceptor is installed and we are not tracking latency, we will install the tracing // interceptor as that is launched from a separate process. if (installedInterceptor == null && simulatedPerfConfig.traceRenderingPasses) { installedInterceptor = PerformanceTracingInterceptor() + } else if (installedInterceptor == null && simulatedPerfConfig.traceEventLatency) { + installedInterceptor = EventHandlingTracingInterceptor() } val component = PerformancePoetryComponent(installedInterceptor, simulatedPerfConfig) val model: PoetryModel by viewModels { component.poetryModelFactory(this) } - val instrumentedRenderings = if (simulatedPerfConfig.traceLatency) { + val instrumentedRenderings = if (simulatedPerfConfig.traceFrameLatency) { model.renderings.onEach { screen -> traceRenderingLatency(screen) } @@ -104,15 +124,12 @@ class PerformancePoetryActivity : AppCompatActivity() { * benchmark scenarios, even for a HOT start. */ override fun onStart() { - WorkflowUiEventsTracer.reset() - (installedInterceptor as? PerformanceTracingInterceptor)?.reset() + (installedInterceptor as? Resettable)?.reset() super.onStart() } @OptIn(WorkflowUiExperimentalApi::class) private fun traceRenderingLatency(screen: Screen) { - WorkflowUiEventsTracer.endTracesForActiveEventsAndClear() - // Start the trace sections for new rendering produced -> shown. val navigationHolder = navigationInFlight if (navigationHolder == null) { @@ -153,11 +170,38 @@ class PerformancePoetryActivity : AppCompatActivity() { } } + /** + * See methodology from Py - https://py.hashnode.dev/tracing-main-thread-messages + */ + private fun buildSectionLabel(log: String): String { + val logNoPrefix = log.removePrefix(">>>>> Dispatching to ") + val indexOfWhat = logNoPrefix.lastIndexOf(": ") + val indexOfCallback = logNoPrefix.indexOf("} ") + + val targetHandler = logNoPrefix.substring(0, indexOfCallback + 1) + val callback = logNoPrefix.substring(indexOfCallback + 2, indexOfWhat) + .removePrefix("DispatchedContinuation[Dispatchers.Main, Continuation at ") + .removePrefix("DispatchedContinuation[Dispatchers.Main.immediate, Continuation at ") + val what = logNoPrefix.substring(indexOfWhat + 2) + + return if (callback != "null") { + "$callback $targetHandler $what" + } else { + "$targetHandler $what" + } + } + companion object { // Async traces require a unique int not used by any other async trace. private const val TRACE_COOKIE = 133742 const val FRAME_LATENCY_SECTION = "Frame-Latency" - const val PERF_CONFIG_EXTRA = "complex.poetry.performance.config" + const val EXTRA_TRACE_ALL_MAIN_THREADS = "complex.poetry.performance.config.trace.main" + const val EXTRA_PERF_CONFIG_INITIALIZING = "complex.poetry.performance.config.use.initializing" + const val EXTRA_PERF_CONFIG_EVENT_LATENCY = + "complex.poetry.performance.config.track.event.latency" + const val EXTRA_PERF_CONFIG_FRAME_LATENCY = + "complex.poetry.performance.config.track.frame.latency" + const val EXTRA_PERF_CONFIG_RENDERING = "complex.poetry.performance.config.track.rendering" var installedInterceptor: WorkflowInterceptor? = null init { diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/robots/DeviceCyborgs.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/cyborgs/DeviceCyborgs.kt similarity index 94% rename from benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/robots/DeviceCyborgs.kt rename to benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/cyborgs/DeviceCyborgs.kt index 2e787d139f..448b4e91de 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/robots/DeviceCyborgs.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/cyborgs/DeviceCyborgs.kt @@ -1,4 +1,4 @@ -package com.squareup.benchmarks.performance.complex.poetry.robots +package com.squareup.benchmarks.performance.complex.poetry.cyborgs import androidx.test.uiautomator.BySelector import androidx.test.uiautomator.UiDevice diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/robots/PoetryCyborgs.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/cyborgs/PoetryCyborgs.kt similarity index 96% rename from benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/robots/PoetryCyborgs.kt rename to benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/cyborgs/PoetryCyborgs.kt index 05ff2995aa..50298a8ec1 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/robots/PoetryCyborgs.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/cyborgs/PoetryCyborgs.kt @@ -1,4 +1,4 @@ -package com.squareup.benchmarks.performance.complex.poetry.robots +package com.squareup.benchmarks.performance.complex.poetry.cyborgs import android.widget.ImageButton import android.widget.ProgressBar diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/EventHandlingTracingInterceptor.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/EventHandlingTracingInterceptor.kt new file mode 100644 index 0000000000..746ef32a82 --- /dev/null +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/EventHandlingTracingInterceptor.kt @@ -0,0 +1,83 @@ +package com.squareup.benchmarks.performance.complex.poetry.instrumentation + +import androidx.tracing.trace +import com.squareup.workflow1.BaseRenderContext +import com.squareup.workflow1.WorkflowAction +import com.squareup.workflow1.WorkflowInterceptor +import com.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor +import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession + +/** + * We use this [WorkflowInterceptor] to add in tracing for the main thread messages that handle + * particular events. + * + * If you want to trace how long Workflow takes to process a UI event, then + * annotate the [RenderContext.eventHandler] name argument with [keyForTrace]. That will cause + * this interceptor to pick it up when the action is sent into the sink and trace that main thread + * message. + * + * If you want to trace how long Workflow takes to process the result of a [Worker], then + * annotate the [Worker] using [TraceableWorker] which will set it up with a key such that when + * the action for the result is sent to the sink the main thread message will be traced. + */ +class EventHandlingTracingInterceptor : WorkflowInterceptor, Resettable { + + private val actionCounts: MutableMap = mutableMapOf() + + class EventHandlingTracingRenderContextInterceptor( + private val actionCounts: MutableMap + ) : RenderContextInterceptor { + override fun onActionSent( + action: WorkflowAction, + proceed: (WorkflowAction) -> Unit + ) { + // This will capture the entire main thread frame where the event is handled. + val tag = action.actionName + if (tag.isNotEmpty()) { + trace(tag) { + proceed(action) + } + } else { + proceed(action) + } + } + + private val WorkflowAction.actionName: String + get() { + var actionTag = extractTraceTag(toString()) + if (actionTag.isNotEmpty()) { + synchronized(actionCounts) { + val count = actionCounts.getOrDefault(actionTag, 0) + actionCounts[actionTag] = count + 1 + actionTag = "$actionTag-${count.toString().padStart(2, '0')}" + } + } + return actionTag + } + } + + override fun onRender( + renderProps: P, + renderState: S, + context: BaseRenderContext, + proceed: (P, S, RenderContextInterceptor?) -> R, + session: WorkflowSession + ): R { + return proceed( + renderProps, + renderState, + EventHandlingTracingRenderContextInterceptor(actionCounts) + ) + } + + override fun reset() { + actionCounts.clear() + } + + companion object { + private const val TRACE_KEY = "trace_key" + fun keyForTrace(tag: String): String = "$TRACE_KEY:$tag:" + private fun extractTraceTag(fullTag: String): String = + fullTag.substringAfter("$TRACE_KEY:", "").substringBefore(':', "") + } +} diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/PerformanceTracingInterceptor.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/PerformanceTracingInterceptor.kt index 66996ef73e..051fe38741 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/PerformanceTracingInterceptor.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/PerformanceTracingInterceptor.kt @@ -16,7 +16,7 @@ import com.squareup.workflow1.workflowIdentifier * This can be combined with a [androidx.benchmark.macro.TraceSectionMetric] in a benchmark to * conveniently print out results. */ -class PerformanceTracingInterceptor : WorkflowInterceptor { +class PerformanceTracingInterceptor : WorkflowInterceptor, Resettable { private var totalRenderPasses = 0 override fun onRender( @@ -54,7 +54,7 @@ class PerformanceTracingInterceptor : WorkflowInterceptor { } } - fun reset() { + override fun reset() { totalRenderPasses = 0 } diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/RenderPassCountingInterceptor.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/RenderPassCountingInterceptor.kt index 822d71641f..748b691324 100644 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/RenderPassCountingInterceptor.kt +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/RenderPassCountingInterceptor.kt @@ -13,7 +13,7 @@ import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession * This is convenient to use in integration tests that verify that the # of render passes and the * ratio of 'fresh' to 'stale' renderings for a scenario are constant. */ -class RenderPassCountingInterceptor : WorkflowInterceptor { +class RenderPassCountingInterceptor : WorkflowInterceptor, Resettable { val renderEfficiencyTracking = RenderEfficiency() lateinit var renderPassStats: RenderStats private val nodeStates: MutableMap = mutableMapOf() @@ -58,7 +58,7 @@ class RenderPassCountingInterceptor : WorkflowInterceptor { /** * Reset all the counters. */ - fun reset() { + override fun reset() { renderEfficiencyTracking.reset() nodeStates.clear() } diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/Resettable.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/Resettable.kt new file mode 100644 index 0000000000..b60d55ddf5 --- /dev/null +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/Resettable.kt @@ -0,0 +1,5 @@ +package com.squareup.benchmarks.performance.complex.poetry.instrumentation + +interface Resettable { + fun reset() +} 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 9d197572bd..fb5f1bb5a4 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,7 +17,8 @@ data class SimulatedPerfConfig( val complexityDelay: Long, val useInitializingState: Boolean, val traceRenderingPasses: Boolean = false, - val traceLatency: Boolean = false + val traceFrameLatency: Boolean = false, + val traceEventLatency: Boolean = false ) : Parcelable { companion object { val NO_SIMULATED_PERF = SimulatedPerfConfig( @@ -25,7 +26,8 @@ data class SimulatedPerfConfig( complexityDelay = 0, useInitializingState = false, traceRenderingPasses = false, - traceLatency = false + traceFrameLatency = false, + traceEventLatency = false ) } } diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/TraceableWorker.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/TraceableWorker.kt new file mode 100644 index 0000000000..fd17e2ce14 --- /dev/null +++ b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/TraceableWorker.kt @@ -0,0 +1,35 @@ +package com.squareup.benchmarks.performance.complex.poetry.instrumentation + +import com.squareup.workflow1.Worker +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.asFlow + +/** + * A Worker that adds in a key to its [toString] that [EventHandlingTracingInterceptor] knows + * how to read when observing action handling. + */ +@OptIn(FlowPreview::class) +class TraceableWorker( + private val name: String, + private val work: Flow +) : Worker { + override fun run(): Flow = work + override fun toString(): String = EventHandlingTracingInterceptor.keyForTrace(name) + + companion object { + /** + * Just like [from()] in [Worker] but adding in a trace name. + */ + public inline fun from( + name: String, + noinline block: suspend () -> OutputT + ): Worker = block.asFlow().asTraceableWorker(name) + } +} + +/** + * Just like the [Flow.asWorker()] extension in [Worker] but adding in a trace name. + */ +public inline fun Flow.asTraceableWorker(name: String): Worker = + TraceableWorker("Worker-$name-Finished", this) diff --git a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/WorkflowUiEventsTracer.kt b/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/WorkflowUiEventsTracer.kt deleted file mode 100644 index 009ff0cc81..0000000000 --- a/benchmarks/performance-poetry/complex-poetry/src/main/java/com/squareup/benchmarks/performance/complex/poetry/instrumentation/WorkflowUiEventsTracer.kt +++ /dev/null @@ -1,112 +0,0 @@ -package com.squareup.benchmarks.performance.complex.poetry.instrumentation - -import androidx.tracing.Trace -import com.squareup.sample.poetry.PoemListScreen -import com.squareup.sample.poetry.StanzaListScreen -import com.squareup.sample.poetry.StanzaScreen - -/** - * Captures an event callback for any Rendering produced from a Workflow. - */ -data class WorkflowUiEvent( - val callback: String, - val screen: String -) - -/** - * Start traces for active events and then end them whenever the Rendering is produced. - * - * Singleton holds the state for the 'active' events between any Renderings as well as the total - * counts for those type of events so that we can differentiate each one throughout the scenario. - */ -object WorkflowUiEventsTracer { - - private val activeEvents: MutableList = mutableListOf() - private val eventCounts: MutableMap = mutableMapOf() - - fun startTraceForEvent(event: WorkflowUiEvent) { - val tag = synchronized(activeEvents) { - val eventString = "${event.screen}-${event.callback}" - eventCounts[eventString] = eventCounts.getOrDefault(eventString, 0) + 1 - val count = eventCounts[eventString] - val uniqueEventTag = "$eventString-$count " - activeEvents.add(uniqueEventTag) - uniqueEventTag - } - Trace.beginAsyncSection( - tag, - EVENT_COOKIE - ) - } - - fun endTracesForActiveEventsAndClear() { - val copy = synchronized(activeEvents) { - val cache = mutableListOf() - cache.addAll(activeEvents) - activeEvents.clear() - cache - } - copy.forEach { uniqueEventTag -> - Trace.endAsyncSection( - uniqueEventTag, - EVENT_COOKIE - ) - } - } - - fun reset() { - activeEvents.clear() - eventCounts.clear() - } - - private const val EVENT_COOKIE = 12345 -} - -fun StanzaScreen.trace(): StanzaScreen { - return copy( - onGoUp = { - WorkflowUiEventsTracer.startTraceForEvent(WorkflowUiEvent("onGoUp", "StanzaScreen")) - onGoUp() - }, - onGoBack = { - WorkflowUiEventsTracer.startTraceForEvent(WorkflowUiEvent("onGoBack", "StanzaScreen")) - onGoBack?.let { it() } - }, - onGoForth = { - WorkflowUiEventsTracer.startTraceForEvent(WorkflowUiEvent("onGoForth", "StanzaScreen")) - onGoForth?.let { it() } - } - ) -} - -fun StanzaListScreen.trace(): StanzaListScreen { - return copy( - onExit = { - WorkflowUiEventsTracer.startTraceForEvent(WorkflowUiEvent("onExit", "StanzaListScreen")) - onExit() - }, - onStanzaSelected = { selection: Int -> - WorkflowUiEventsTracer.startTraceForEvent( - WorkflowUiEvent( - "onStanzaSelected($selection)", - "StanzaListScreen" - ) - ) - onStanzaSelected(selection) - } - ) -} - -fun PoemListScreen.trace(): PoemListScreen { - return copy( - onPoemSelected = { selection: Int -> - WorkflowUiEventsTracer.startTraceForEvent( - WorkflowUiEvent( - "onPoemSelected($selection)", - "PoemListScreen" - ) - ) - onPoemSelected(selection) - } - ) -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index adf5b00a58..e976c51158 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ targetSdk = "30" androidx-activity = "1.3.0" androidx-appcompat = "1.3.1" -androidx-benchmark = "1.1.0-beta04" +androidx-benchmark = "1.1.0-rc01" androidx-compose = "1.1.0-rc01" androidx-compose-compiler = "1.1.0-rc02" androidx-constraintlayout = "2.1.2" @@ -27,7 +27,7 @@ androidx-test = "1.3.0" androidx-test-espresso = "3.3.0" androidx-test-junit-ext = "1.1.3" androidx-test-truth-ext = "1.4.0" -androidx-tracing = "1.1.0-beta01" +androidx-tracing = "1.1.0-rc01" androidx-transition = "1.4.1" androidx-viewbinding = "4.2.1" androidx-work = "2.6.0" @@ -74,7 +74,6 @@ squareup-okio = "3.0.0" squareup-radiography = "2.4.0" squareup-retrofit = "2.9.0" squareup-seismic = "1.0.2" -squareup-tart = "0.4.1" squareup-workflow = "1.0.0" timber = "4.7.1" @@ -222,8 +221,6 @@ squareup-radiography = { module = "com.squareup.radiography:radiography", versio squareup-seismic = { module = "com.squareup:seismic", version.ref = "squareup-seismic" } -squareup-tart = { module = "com.squareup.tart:tart", version.ref = "squareup-tart"} - timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } truth = { module = "com.google.truth:truth", version.ref = "truth" } diff --git a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/PoemListWorkflow.kt b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/PoemListWorkflow.kt index 18d0e0891f..a9ab0f5f05 100644 --- a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/PoemListWorkflow.kt +++ b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/PoemListWorkflow.kt @@ -1,20 +1,28 @@ package com.squareup.sample.poetry +import com.squareup.sample.poetry.PoemListWorkflow.Props import com.squareup.sample.poetry.model.Poem import com.squareup.workflow1.StatelessWorkflow /** * Renders a given ordered list of [Poem]s. Reports the index of any that are clicked via Output. */ -object PoemListWorkflow : StatelessWorkflow, Int, PoemListScreen>() { +object PoemListWorkflow : StatelessWorkflow() { + + data class Props( + val poems: List, + val eventHandlerTag: (String) -> String = { "" } + ) override fun render( - renderProps: List, + renderProps: Props, context: RenderContext ): PoemListScreen { return PoemListScreen( - poems = renderProps, - onPoemSelected = context.eventHandler { index -> setOutput(index) } + poems = renderProps.poems, + onPoemSelected = context.eventHandler( + name = { renderProps.eventHandlerTag("E-PoemList-PoemSelected") } + ) { index -> setOutput(index) } ) } } diff --git a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemWorkflow.kt b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemWorkflow.kt index c920a9ce6d..11fb9ab692 100644 --- a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemWorkflow.kt +++ b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemWorkflow.kt @@ -75,7 +75,7 @@ class RealPoemWorkflow : PoemWorkflow, val stanzaListOverview = context.renderChild( StanzaListWorkflow, - renderProps + StanzaListWorkflow.Props(renderProps) ) { selected -> HandleStanzaListOutput(selected) } diff --git a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemsBrowserWorkflow.kt b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemsBrowserWorkflow.kt index e5fc8cd706..09b579868d 100644 --- a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemsBrowserWorkflow.kt +++ b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/RealPoemsBrowserWorkflow.kt @@ -2,6 +2,7 @@ package com.squareup.sample.poetry import com.squareup.sample.container.overviewdetail.OverviewDetailScreen import com.squareup.sample.poetry.PoemListScreen.Companion.NO_POEM_SELECTED +import com.squareup.sample.poetry.PoemListWorkflow.Props import com.squareup.sample.poetry.model.Poem import com.squareup.workflow1.Snapshot import com.squareup.workflow1.StatefulWorkflow @@ -40,7 +41,11 @@ class RealPoemsBrowserWorkflow( context: RenderContext ): OverviewDetailScreen { val poems: OverviewDetailScreen = - context.renderChild(PoemListWorkflow, renderProps) { selected -> choosePoem(selected) } + context.renderChild(PoemListWorkflow, Props(poems = renderProps)) { selected -> + choosePoem( + selected + ) + } .copy(selection = renderState) .let { OverviewDetailScreen(BackStackScreen(it)) } diff --git a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaListWorkflow.kt b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaListWorkflow.kt index 812f6fccf4..570cdee4e8 100644 --- a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaListWorkflow.kt +++ b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaListWorkflow.kt @@ -1,5 +1,6 @@ package com.squareup.sample.poetry +import com.squareup.sample.poetry.StanzaListWorkflow.Props import com.squareup.sample.poetry.model.Poem import com.squareup.workflow1.StatelessWorkflow @@ -10,20 +11,38 @@ typealias SelectedStanza = Int * * Output is the index of a clicked stanza, or [-1][NO_SELECTED_STANZA] on exit. */ -object StanzaListWorkflow : StatelessWorkflow() { +object StanzaListWorkflow : StatelessWorkflow() { + + data class Props( + val poem: Poem, + val eventHandlerTag: (String) -> String = { "" } + ) const val NO_SELECTED_STANZA = -1 override fun render( - renderProps: Poem, + renderProps: Props, context: RenderContext ): StanzaListScreen { + val poem = renderProps.poem return StanzaListScreen( - title = renderProps.title, - subtitle = renderProps.poet.fullName, - firstLines = renderProps.initialStanzas, - onStanzaSelected = context.eventHandler { index -> setOutput(index) }, - onExit = context.eventHandler { setOutput(NO_SELECTED_STANZA) } + title = poem.title, + subtitle = poem.poet.fullName, + firstLines = poem.initialStanzas, + onStanzaSelected = context.eventHandler( + name = { renderProps.eventHandlerTag("E-StanzaList-StanzaSelected") } + ) { index -> + setOutput( + index + ) + }, + onExit = context.eventHandler( + name = { renderProps.eventHandlerTag("E-StanzaList-Exit") } + ) { + setOutput( + NO_SELECTED_STANZA + ) + } ) } } diff --git a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaWorkflow.kt b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaWorkflow.kt index c343c80244..befbb4353d 100644 --- a/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaWorkflow.kt +++ b/samples/containers/poetry/src/main/java/com/squareup/sample/poetry/StanzaWorkflow.kt @@ -11,7 +11,8 @@ import com.squareup.workflow1.StatelessWorkflow object StanzaWorkflow : StatelessWorkflow() { data class Props( val poem: Poem, - val index: Int + val index: Int, + val eventHandlerTag: (String) -> String = { "" } ) enum class Output { @@ -28,19 +29,37 @@ object StanzaWorkflow : StatelessWorkflow() { val onGoBack: (() -> Unit)? = when (index) { 0 -> null else -> { - context.eventHandler { setOutput(ShowPreviousStanza) } + context.eventHandler( + name = { renderProps.eventHandlerTag("E-StanzaWorkflow-${ShowPreviousStanza.name}") } + ) { + setOutput( + ShowPreviousStanza + ) + } } } val onGoForth: (() -> Unit)? = when (index) { poem.stanzas.size - 1 -> null else -> { - context.eventHandler { setOutput(ShowNextStanza) } + context.eventHandler( + name = { renderProps.eventHandlerTag("E-StanzaWorkflow-${ShowNextStanza.name}") } + ) { + setOutput( + ShowNextStanza + ) + } } } return StanzaScreen( - onGoUp = context.eventHandler { setOutput(CloseStanzas) }, + onGoUp = context.eventHandler( + name = { renderProps.eventHandlerTag("E-StanzaWorkflow-${CloseStanzas.name}") } + ) { + setOutput( + CloseStanzas + ) + }, title = poem.title, stanzaNumber = index + 1, lines = poem.stanzas[index],