-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize reference readers to handle virtual islands as if the in bri…
…dge was directly connected to all the non outgoing nodes in the data structure compoment. This automatically deduplicates the paths that we get out of heap diffs. We were seeing duplicate entries because a map would be surfaced as a node with growing children, but then an internal element of the map, e.g. the background array or a node from its linked list, would also be surfaced as a distinct node with growing childre. With this solution, essentially each wrapped reference reader now does its own local graph traversal. The isLeafObject property allows to communicate to the larger graph traversal code that a specific node doesn't need to be re explored
- Loading branch information
Showing
7 changed files
with
135 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
shark/shark/src/main/java/shark/FlatteningFiniteTraversalReferenceReader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") | ||
|
||
package shark | ||
|
||
import shark.ChainingInstanceReferenceReader.VirtualInstanceReferenceReader | ||
import shark.HeapObject.HeapClass | ||
import shark.HeapObject.HeapInstance | ||
import shark.HeapObject.HeapObjectArray | ||
import shark.HeapObject.HeapPrimitiveArray | ||
import shark.internal.hppc.LongScatterSet | ||
|
||
class FlatteningFiniteTraversalReferenceReader( | ||
private val graph: HeapGraph, | ||
private val virtualInstanceReader: VirtualInstanceReferenceReader, | ||
private val instanceReferenceReader: ReferenceReader<HeapInstance>, | ||
private val objectArrayReferenceReader: ReferenceReader<HeapObjectArray>, | ||
) : VirtualInstanceReferenceReader { | ||
|
||
private val visited = LongScatterSet() | ||
|
||
override fun matches(instance: HeapInstance) = virtualInstanceReader.matches(instance) | ||
|
||
override fun read(source: HeapInstance): Sequence<Reference> { | ||
visited.clear() | ||
val toVisit = mutableListOf<Reference>() | ||
visited += source.objectId | ||
|
||
val sourceTrackingSequence = virtualInstanceReader.read(source).map { reference -> | ||
visited += reference.valueObjectId | ||
reference | ||
} | ||
var startedTraversing = false | ||
|
||
val traversingSequence = generateSequence { | ||
if (!startedTraversing) { | ||
startedTraversing = true | ||
toVisit.enqueueNewReferenceVisit(instanceReferenceReader.read(source), visited) | ||
} | ||
val nextReference = toVisit.removeFirstOrNull() ?: return@generateSequence null | ||
|
||
val childReferences = | ||
when (val nextObject = graph.findObjectById(nextReference.valueObjectId)) { | ||
is HeapInstance -> instanceReferenceReader.read(nextObject) | ||
is HeapObjectArray -> objectArrayReferenceReader.read(nextObject) | ||
// We're assuming that classes should be reached through other nodes. Reaching a class | ||
// here first would be bad as it opens us up to traversing the entire graph, vs the local | ||
// finite traversal we want. This should be fine on Android, but could be different on | ||
// JVMs. | ||
is HeapClass -> emptySequence() | ||
is HeapPrimitiveArray -> emptySequence() | ||
} | ||
// TODO Can we change the name to capture the parent relationship as well? | ||
toVisit.enqueueNewReferenceVisit(childReferences, visited) | ||
nextReference.copy(isLeafObject = true) | ||
} | ||
return sourceTrackingSequence + traversingSequence | ||
} | ||
|
||
private fun MutableList<Reference>.enqueueNewReferenceVisit( | ||
references: Sequence<Reference>, | ||
visited: LongScatterSet | ||
) { | ||
references.forEach { reference -> | ||
val added = visited.add(reference.valueObjectId) | ||
if (added) { | ||
this += reference | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters