I'm occasionally pulling and building master branc...
# compose
m
I'm occasionally pulling and building master branch of compose/runtime module. I'm using CfD. I'd like to report that with this commit my app insanely slowed down, and, as I benchmarked, ~90% of all the cpu time is spend on this single new line. When zoomed in, in the flame graph it looks so:
👀 3
z
@shikasd
m
Btw, even besides
derivedStates.removeScope(value)
, there are still some performance issues with `recordReadOf`: •
identityHashCode
, used in `IdentityScopeMap`seems to be surprisingly expensive (at least on my Eclipse Adoptium 18.0.1). I've read that JDK lazely initializes it and then has to decode it from the object header, but still. Or it is just due to the binary search in
IdentityScopeMap.find
. • There are a cupule of iterations over non-linked hash sets. That shouldn't matter that much tho, unless the set ever shrinks? • When called from
DerivedSnapshotState.getValue()
, the non-trivial `getCurrentValue()`function is called twice.
s
Interesting, I always assumed that identityHashCode will take almost constant time, I believe that's why we use it Maybe there's a better strategy for CfD there
Unfortunately, we kinda need to call
removeScope
to make sure we don't leak derived state for now Maybe it is worth investing into a better strategy for handling it Overall, Compose heavily relies on identity hashcode, assuming it is calculated in a constant time, so it taking long to calculate will slow down everything quite severely
One of the things that might help is to check if your JVM supports
-XX:hashCode
Maybe tweaking that will result in somehow better performance :)
m
For now I have removed usage of derivedStateOf and my app is like 10x faster.
s
Btw, would you be able to share your perf trace (through perfetto or any other exportable format)? Could be interesting to look into those at some point
m
I think it'd be easier if I make some example app. Because basically all I do is I build a tree view and the derivedState in question like this:
Copy code
class TreeNode {
   val parent: TreeNode
   var isExpanded by mutableStateOf(true)
   val isVisible by derivedStateOf { parent.isExpanded && parent.isVisible && !isFilteredOutBySearch() }
}
s
Interesting, I am wondering if nested derived states are also part of the problem here If you could create an example app and file a bug, that would be great :)
n
I have never looked into how identity hash code is generated but it seems that it should not be used in performance critical code because its implementation may depend on Java version, host platform, or even configuration by
-XXhashCode
. E.g. https://shipilev.net/jvm/anatomy-quarks/26-identity-hash-code/
s
Although it is true for desktop, Compose is designed with Android in mind, where the implementation is fixed Platform specific actuals can provide identityHashCode implementation that doesn't use system values though, but not sure if it is going to be reasonable Similarly, Compose avoids ThreadLocals/WeakReferences because of performance concerns on Android, although they might work just fine on Desktop systems I still wonder if we ever hit the same penalty on Android as well, that's why the sample would be great Cross platform is complicated 😅
👍🏻 1