Fixed
Status Update
Comments
ap...@google.com <ap...@google.com> #2
Yigit, do you have time to fix it?
reemission of the same liveData is racy
reemission of the same liveData is racy
sj...@google.com <sj...@google.com>
cc...@google.com <cc...@google.com> #3
yea i'll take it.
ap...@google.com <ap...@google.com> #4
Thanks for the detailed analysis. This may not be an issue anymore since we've started using Main.immediate there but I' not sure; I'll try to create a test case.
ap...@google.com <ap...@google.com> #5
just emitting same live data reproduces the issue.
@Test
fun raceTest() {
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData)
emitSource(subLiveData) //crashes
}
subject.addObserver().apply {
testScope.advanceUntilIdle()
}
}
@Test
fun raceTest() {
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData)
emitSource(subLiveData) //crashes
}
subject.addObserver().apply {
testScope.advanceUntilIdle()
}
}
cc...@google.com <cc...@google.com> #6
With 2.2.0-alpha04 (that use Main.immediate), the issue seems to be still there (I tested it by calling emitSource() twice, like your test case)
cc...@google.com <cc...@google.com> #7
yea sorry immediate does not fix it.
I actually have a WIP fix for it:
https://android-review.googlesource.com/c/platform/frameworks/support/+/1112186
if your case is the one i found (emitting same LiveData multiple times, as shown in #5) you can work around it by adding a dummy transformation.
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData.map {it })
emitSource(subLiveData.map {it} )
}
I actually have a WIP fix for it:
if your case is the one i found (emitting same LiveData multiple times, as shown in #5) you can work around it by adding a dummy transformation.
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData.map {it })
emitSource(subLiveData.map {it} )
}
ap...@google.com <ap...@google.com> #8
Project: platform/frameworks/support
Branch: androidx-master-dev
commit af12e75e6b4110f48e44ca121466943909de8f06
Author: Yigit Boyar <yboyar@google.com>
Date: Tue Sep 03 12:58:11 2019
Fix coroutine livedata race condition
This CL fixes a bug in liveData builder where emitting same
LiveData source twice would make it crash because the second
emission registry could possibly happen before first one is
removed as source.
We fix it by using a suspending dispose function. It does feel
a bit hacky but we cannot make DisposableHandle.dispose async
and we do not want to block there. This does not mean that there
is a problem if developer disposes it manually since our emit
functions take care of making sure it disposes (and there is
no other way to add source to the underlying MediatorLiveData)
Bug: 140249349
Test: BuildLiveDataTest#raceTest_*
Change-Id: I0b464c242a583da4669af195cf2504e2adc4de40
M lifecycle/lifecycle-livedata-ktx/api/2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/current.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_current.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_current.txt
M lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt
M lifecycle/lifecycle-livedata-ktx/src/test/java/androidx/lifecycle/BuildLiveDataTest.kt
https://android-review.googlesource.com/1112186
https://goto.google.com/android-sha1/af12e75e6b4110f48e44ca121466943909de8f06
Branch: androidx-master-dev
commit af12e75e6b4110f48e44ca121466943909de8f06
Author: Yigit Boyar <yboyar@google.com>
Date: Tue Sep 03 12:58:11 2019
Fix coroutine livedata race condition
This CL fixes a bug in liveData builder where emitting same
LiveData source twice would make it crash because the second
emission registry could possibly happen before first one is
removed as source.
We fix it by using a suspending dispose function. It does feel
a bit hacky but we cannot make DisposableHandle.dispose async
and we do not want to block there. This does not mean that there
is a problem if developer disposes it manually since our emit
functions take care of making sure it disposes (and there is
no other way to add source to the underlying MediatorLiveData)
Bug: 140249349
Test: BuildLiveDataTest#raceTest_*
Change-Id: I0b464c242a583da4669af195cf2504e2adc4de40
M lifecycle/lifecycle-livedata-ktx/api/2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/current.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_current.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_current.txt
M lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt
M lifecycle/lifecycle-livedata-ktx/src/test/java/androidx/lifecycle/BuildLiveDataTest.kt
cc...@google.com <cc...@google.com> #9
We've got initial traces in CI! For example,
Current Constraints:
- only captured on API 29: Pixel 2016 (can support 28, with some
)additional work - only small subset of benchmarks capture a trace, due to overhead (
)b/171749803
Next step is to capture traces for all benchmarks with app tag disabled. This will mean no e.g. compose trace sections will be captured, but it will allow us to see CPU usage, thread scheduling, GCs, etc. We'll keep the app tag enabled on the *WithTracing
variants.
ap...@google.com <ap...@google.com> #10
Project: platform/frameworks/support
Branch: androidx-main
commit f5d35eb9ca852dfac791c2dc1d6ce953b2843880
Author: Chris Craik <ccraik@google.com>
Date: Wed Aug 11 17:35:21 2021
Move perfetto capture and protos to benchmark-common
Test: ./gradlew benchmark:benchmark-common:cC benchmark:benchmark-macro:cC benchmark:benchmark-macro-junit4:cC benchmark:benchmark-junit4:cC
Bug: 196115387
Bug: 145598917
Relnote: N/A
PerfettoTraceProcessor and its binary will stay in benchmark-macro.
Moves PerfettoRule to benchmark-junit, so that microbenchmarks don't
need to depend on benchmark-macro-junit4. Eventually, this
functionality can be merged into BenchmarkRule, as long as
in-process/app tag tracing is configurable, and off by
default. UserspaceTracing will enable us to still capture
BenchmarkState lifecycle events, like different modes (warmup /
measure / allocation count).
This unblocks raising the minAPI of Macrobench to the long-term goal
of API 21, which is the lowest that can support shell commands, as
well as perfetto capture.
This change also moves a few supporting classes, such as DeviceInfo
and ConfigurationError, which were always intended to gradually
replace benchmark-common's error / device state querying. This starts
that process.
As testutils-ktx is used by benchmark-common now, add to all project
config flavors.
Change-Id: I6559b6735d0106e38ec5d8eaeddcac9297d0c431
M benchmark/benchmark-common/api/current.txt
M benchmark/benchmark-common/api/public_plus_experimental_current.txt
M benchmark/benchmark-common/api/restricted_current.txt
M benchmark/benchmark-common/build.gradle
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ConfigurationErrorTest.kt
A benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/Packages.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellBehaviorTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/AtraceTagTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/PerfettoConfigTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/UiStateTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/ConfigurationError.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/AtraceTag.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/UiState.kt
M benchmark/benchmark-common/src/main/java/perfetto/protos/package-info.java
M benchmark/benchmark-common/src/main/proto/perfetto_config.proto
M benchmark/benchmark-common/src/main/proto/perfetto_trace.proto
M benchmark/benchmark-junit4/api/current.txt
M benchmark/benchmark-junit4/api/public_plus_experimental_current.txt
M benchmark/benchmark-junit4/api/restricted_current.txt
M benchmark/benchmark-junit4/build.gradle
M benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/PerfettoRuleTest.kt
M benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/PerfettoRule.kt
M benchmark/benchmark-macro-junit4/api/current.txt
M benchmark/benchmark-macro-junit4/api/public_plus_experimental_current.txt
M benchmark/benchmark-macro-junit4/api/restricted_current.txt
M benchmark/benchmark-macro/api/current.txt
M benchmark/benchmark-macro/api/public_plus_experimental_current.txt
M benchmark/benchmark-macro/api/restricted_current.txt
M benchmark/benchmark-macro/build.gradle
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/FileLinkingRule.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessorTest.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
M benchmark/benchmark/build.gradle
M benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/PerfettoOverheadBenchmark.kt
M buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
M compose/ui/ui-graphics/benchmark/build.gradle
M compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
M development/build_log_simplifier/messages.ignore
M settings.gradle
https://android-review.googlesource.com/1795168
Branch: androidx-main
commit f5d35eb9ca852dfac791c2dc1d6ce953b2843880
Author: Chris Craik <ccraik@google.com>
Date: Wed Aug 11 17:35:21 2021
Move perfetto capture and protos to benchmark-common
Test: ./gradlew benchmark:benchmark-common:cC benchmark:benchmark-macro:cC benchmark:benchmark-macro-junit4:cC benchmark:benchmark-junit4:cC
Bug: 196115387
Bug: 145598917
Relnote: N/A
PerfettoTraceProcessor and its binary will stay in benchmark-macro.
Moves PerfettoRule to benchmark-junit, so that microbenchmarks don't
need to depend on benchmark-macro-junit4. Eventually, this
functionality can be merged into BenchmarkRule, as long as
in-process/app tag tracing is configurable, and off by
default. UserspaceTracing will enable us to still capture
BenchmarkState lifecycle events, like different modes (warmup /
measure / allocation count).
This unblocks raising the minAPI of Macrobench to the long-term goal
of API 21, which is the lowest that can support shell commands, as
well as perfetto capture.
This change also moves a few supporting classes, such as DeviceInfo
and ConfigurationError, which were always intended to gradually
replace benchmark-common's error / device state querying. This starts
that process.
As testutils-ktx is used by benchmark-common now, add to all project
config flavors.
Change-Id: I6559b6735d0106e38ec5d8eaeddcac9297d0c431
M benchmark/benchmark-common/api/current.txt
M benchmark/benchmark-common/api/public_plus_experimental_current.txt
M benchmark/benchmark-common/api/restricted_current.txt
M benchmark/benchmark-common/build.gradle
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ConfigurationErrorTest.kt
A benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/Packages.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellBehaviorTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ShellTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/AtraceTagTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/PerfettoConfigTest.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/perfetto/UiStateTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/ConfigurationError.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/AtraceTag.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoConfig.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/UiState.kt
M benchmark/benchmark-common/src/main/java/perfetto/protos/package-info.java
M benchmark/benchmark-common/src/main/proto/perfetto_config.proto
M benchmark/benchmark-common/src/main/proto/perfetto_trace.proto
M benchmark/benchmark-junit4/api/current.txt
M benchmark/benchmark-junit4/api/public_plus_experimental_current.txt
M benchmark/benchmark-junit4/api/restricted_current.txt
M benchmark/benchmark-junit4/build.gradle
M benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/PerfettoRuleTest.kt
M benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/PerfettoRule.kt
M benchmark/benchmark-macro-junit4/api/current.txt
M benchmark/benchmark-macro-junit4/api/public_plus_experimental_current.txt
M benchmark/benchmark-macro-junit4/api/restricted_current.txt
M benchmark/benchmark-macro/api/current.txt
M benchmark/benchmark-macro/api/public_plus_experimental_current.txt
M benchmark/benchmark-macro/api/restricted_current.txt
M benchmark/benchmark-macro/build.gradle
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/FileLinkingRule.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessorTest.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
M benchmark/benchmark/build.gradle
M benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/PerfettoOverheadBenchmark.kt
M buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
M compose/ui/ui-graphics/benchmark/build.gradle
M compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
M development/build_log_simplifier/messages.ignore
M settings.gradle
cc...@google.com <cc...@google.com> #11
I see the next step here being to always enable tracing, but to disable the app tag. Just need to use something (like ForceTracing, which just landed in macrobench) to ensure high level lifecycle events are captured.
ap...@google.com <ap...@google.com> #12
Project: platform/frameworks/support
Branch: androidx-main
commit ec8b0e22b5e2415f1c165d5ff1b9e73fff4b956b
Author: Chris Craik <ccraik@google.com>
Date: Fri Nov 19 14:52:10 2021
Capture Perfetto traces during Microbenchmarks
Bug: 205636583
Fixes: 145598917
Test: ./gradlew benchmark-common
Relnote: "Add low-overhead System Tracing to microbench output on
Android Q (API 29+). Note that this does not currently capture custom
tracing (via android.os.Trace or androidx.tracing Jetpack APIs) to
avoid affecting results. This tracing should be useful in diagnosing
instability, especially from sources outside the benchmark."
Uses same timing information as microbench itself to generate
userspace tracing information, which is appended into a captured
perfetto trace.
Eventually this approach could enable other metrics available in
traces (such as time a thread is running vs not).
This approach has multiple drawbacks/constraints currently:
* Ignores calls to Trace.beginSection/endSection
* These have been found to be too high overhead in common
scenarios to be on by default. Turning it on drastically affected
many compose benchmarks.
* Eventually we can either make app tracing tag configurable,
offer microbenchmark-specific userspace tracing (easier than
general case, since we can append manually), or offer a more
general userspace tracing solution (which would also be much
lower overhead).
* Puts microbench library tracing in separate track, separate from
the app process
* This can be fixed with improvements to the proto generation to
pick the correct track id, given the test TID .
* Only traces with bundled perfetto (API 29+)
* If deemed useful enough, we can use unbundled perfetto as well
(move perfetto tracebox from benchmark-macro to benchmark-common)
Change-Id: I298be3c9f9f7ef9ba1d2c63d79c864e8c8b16e04
M benchmark/benchmark-junit4/api/current.txt
M benchmark/benchmark-junit4/api/restricted_current.txt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/MetricCaptureTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/InstrumentationResults.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
M benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/PerfettoRule.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InstrumentationResultsTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricCapture.kt
M benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
M benchmark/benchmark-junit4/api/public_plus_experimental_current.txt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/Profiler.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
https://android-review.googlesource.com/1898071
Branch: androidx-main
commit ec8b0e22b5e2415f1c165d5ff1b9e73fff4b956b
Author: Chris Craik <ccraik@google.com>
Date: Fri Nov 19 14:52:10 2021
Capture Perfetto traces during Microbenchmarks
Bug: 205636583
Fixes: 145598917
Test: ./gradlew benchmark-common
Relnote: "Add low-overhead System Tracing to microbench output on
Android Q (API 29+). Note that this does not currently capture custom
tracing (via android.os.Trace or androidx.tracing Jetpack APIs) to
avoid affecting results. This tracing should be useful in diagnosing
instability, especially from sources outside the benchmark."
Uses same timing information as microbench itself to generate
userspace tracing information, which is appended into a captured
perfetto trace.
Eventually this approach could enable other metrics available in
traces (such as time a thread is running vs not).
This approach has multiple drawbacks/constraints currently:
* Ignores calls to Trace.beginSection/endSection
* These have been found to be too high overhead in common
scenarios to be on by default. Turning it on drastically affected
many compose benchmarks.
* Eventually we can either make app tracing tag configurable,
offer microbenchmark-specific userspace tracing (easier than
general case, since we can append manually), or offer a more
general userspace tracing solution (which would also be much
lower overhead).
* Puts microbench library tracing in separate track, separate from
the app process
* This can be fixed with improvements to the proto generation to
pick the correct track id, given the test TID .
* Only traces with bundled perfetto (API 29+)
* If deemed useful enough, we can use unbundled perfetto as well
(move perfetto tracebox from benchmark-macro to benchmark-common)
Change-Id: I298be3c9f9f7ef9ba1d2c63d79c864e8c8b16e04
M benchmark/benchmark-junit4/api/current.txt
M benchmark/benchmark-junit4/api/restricted_current.txt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/MetricCaptureTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/InstrumentationResults.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
M benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/PerfettoRule.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InstrumentationResultsTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricCapture.kt
M benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/StartupTimingMetricTest.kt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
M benchmark/benchmark-junit4/api/public_plus_experimental_current.txt
M benchmark/benchmark-common/src/main/java/androidx/benchmark/Profiler.kt
M benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
Description
one-pager: