Status Update
Comments
ra...@google.com <ra...@google.com> #2
reemission of the same liveData is racy
ml...@google.com <ml...@google.com> #3
ra...@google.com <ra...@google.com> #4
ml...@google.com <ml...@google.com> #5
@Test
fun raceTest() {
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData)
emitSource(subLiveData) //crashes
}
subject.addObserver().apply {
testScope.advanceUntilIdle()
}
}
ra...@google.com <ra...@google.com> #6
ml...@google.com <ml...@google.com> #7
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} )
}
cc...@google.com <cc...@google.com> #8
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
ra...@google.com <ra...@google.com> #9
I'd prefer we say method tracing is always on during the measurement in macrobenchmarks (assuming you use macrobench to start/kill the process)
When a process is being started is not entirely obvious to an app developer. Additionally, method traces collected during startup are actually very important; so we need to make that part easy. Which is why startActivityAndWait(...)
signals a method trace start (when StartupMode.COLD
is being used), and the end of the measurement is when a method trace ends.
ml...@google.com <ml...@google.com> #10
What scenario do you have in mind that you'd want the method tracing for startup, but it wouldn't be covered by the startActivityAndWait
or measureBlock
?
If I have
startupMode = COLD
setupBlock= {
// prepare something
}
measureBlock = {
startActivityAndWait()
}
I would say I still want to only see the method trace of what I'm measuring.
If I have
startupMode = COLD
setupBlock= {
startActivityAndWait()
}
measureBlock = {
// do something in the app
}
This doesn't work, because the process is killed between setupBlock
and measureBlock
.
I can have something like
startupMode = COLD
setupBlock= {
sendABroadcastWhichWakesTheProcess()
}
measureBlock = {
startActivityAndWait()
}
But I would still expect the method trace to run in the measureBlock
?
The process would be killed after setupBlock
anyway, so the method trace can't really survive, can it?
Maybe I'm missing some scenario though.
cc...@google.com <cc...@google.com> #11
Summarizing an offline convo about how we plan to do this:
- at beginning of measure block:
- start method tracing if process alive
- (in measure block) process started
- start process with method tracing
- (in measure block) process killed
- flush method trace before kill
- at end of measure block:
- flush method trace
No special handling for startup modes, or tracing of the setup block.
This requires a lot of checking process state, but that should only happen while method tracing, so it's worth the cost to get predictable tracing.
Note that you'll potentially get arbitrary numbers of traces depending on how many instances of the process run sequentially.
ml...@google.com <ml...@google.com> #12
I think that SG. I think the arbitraty numbers of traces is fine, because these probably matter only for further analysis.
ra...@google.com <ra...@google.com>
ap...@google.com <ap...@google.com> #13
Branch: androidx-main
commit 81955ec73236d3862de4897aa4fa8ad53c453e89
Author: Rahul Ravikumar <rahulrav@google.com>
Date: Fri Apr 12 15:10:25 2024
Improve lifecycle of a method trace in a Macrobenchmark.
* Previously, when method tracing was turned on for a Macrobenchmark, the trace session would start with a process cold start, and end at the end of a `measureBlock()`.
* This change makes it so that Macrobenchmark automatically attaches to the process to start a profiler or uses `start-profiler` under the hood when using `startActivityAndWait(...)`.
* Tracing starts correctly on process start inside a `measureBlock` or at the beginning of a `measureBlock` and therefore we always get a well scoped trace at the end.
Test: Added MacrobenchmarkScopeTest
Bug: 300651094
Relnote: Make it simpler to capture method traces for a Macrobenchmark is scoped to the duration of the actual `measureBlock()`. Previously, it started at target process launch and only supported cold startss
Change-Id: Iee85a37d5b03d92a3128c976b41bd145b2921161
M benchmark/benchmark-common/src/main/java/androidx/benchmark/Profiler.kt
M benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
M benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
Description
When you enable method tracing for benchmarks, it's currently started with
startActivityAndWait
and it's disabled after the benchmark finishes.Method tracing collects huge amount of data which might result in big trace file and might take long due to its nature to slow down the app's performance.
This causes problems for scenarios navigating to a certain screen and starting collection from there. For example start the app, log in, navigate to a screen and scroll some content. The interested part is only scrolling the content.
There might be several options how this could work:
Enable method traces for
measureBlock
. This would be intuitive with when benchmarks actually record data.Have API to dynamically enable/disable method tracing. This might be helpful to record only part of the measure block. This could result in more polluted API though. What if you don't pass method androidx.benchmark.profiling.mode=MethodTracing`, but call the API?