mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-09-29 16:57:00 +08:00
Reduce the number of inferred interfaces for heap snapshots
When implementing categorization of objects by interface, I used an arbitrary limit of 1000 interfaces. After using this implementation, I believe that 1000 is far too high: it creates a long tail of low-value categories that don't help analysis. In this change, I propose a different heuristic, where each inferred interface must match at least 1 in 1000 Objects. The exact number of interfaces generated with this approach varies; I've seen from 52 to 117 in some brief manual testing. Bug: 356183770 Change-Id: I8604130503e0c03212294bee07cdd4c3892bc5cc Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6164863 Commit-Queue: Seth Brenith <seth.brenith@microsoft.com> Reviewed-by: Simon Zünd <szuend@chromium.org>
This commit is contained in:
committed by
Devtools-frontend LUCI CQ
parent
79efda09d9
commit
1ea78154d9
@@ -715,9 +715,6 @@ const BITMASK_FOR_DOM_LINK_STATE = 3;
|
||||
// The class index is stored in the upper 30 bits of the detachedness field.
|
||||
const SHIFT_FOR_CLASS_INDEX = 2;
|
||||
|
||||
// The maximum number of results produced by inferInterfaceDefinitions.
|
||||
const MAX_INTERFACE_COUNT = 1000;
|
||||
|
||||
// After this many properties, inferInterfaceDefinitions can stop adding more
|
||||
// properties to an interface definition if the name is getting too long.
|
||||
const MIN_INTERFACE_PROPERTY_COUNT = 1;
|
||||
@@ -732,6 +729,11 @@ const MAX_INTERFACE_NAME_LENGTH = 120;
|
||||
// only a single object.
|
||||
const MIN_OBJECT_COUNT_PER_INTERFACE = 2;
|
||||
|
||||
// Each interface definition produced by inferInterfaceDefinitions should
|
||||
// match at least 1 out of 1000 Objects in the heap. Otherwise, we end up with a
|
||||
// long tail of unpopular interfaces that don't help analysis.
|
||||
const MIN_OBJECT_PROPORTION_PER_INTERFACE = 1000;
|
||||
|
||||
export abstract class HeapSnapshot {
|
||||
nodes: Platform.TypedArrayUtilities.BigUint32Array;
|
||||
containmentEdges: Platform.TypedArrayUtilities.BigUint32Array;
|
||||
@@ -2017,11 +2019,13 @@ export abstract class HeapSnapshot {
|
||||
}
|
||||
// A map from interface names to their definitions.
|
||||
const candidates = new Map<string, InterfaceDefinitionCandidate>();
|
||||
let totalObjectCount = 0;
|
||||
for (let it = this.allNodes(); it.hasNext(); it.next()) {
|
||||
const node = it.item();
|
||||
if (!this.isPlainJSObject(node)) {
|
||||
continue;
|
||||
}
|
||||
++totalObjectCount;
|
||||
let interfaceName = '{';
|
||||
const properties: string[] = [];
|
||||
for (let edgeIt = node.edges(); edgeIt.hasNext(); edgeIt.next()) {
|
||||
@@ -2041,7 +2045,7 @@ export abstract class HeapSnapshot {
|
||||
interfaceName += formattedEdgeName;
|
||||
properties.push(edgeName);
|
||||
}
|
||||
// The empty interface is not a very meaningful, and can be sort of misleading
|
||||
// The empty interface is not very meaningful, and can be sort of misleading
|
||||
// since someone might incorrectly interpret it as objects with no properties.
|
||||
if (properties.length === 0) {
|
||||
continue;
|
||||
@@ -2063,10 +2067,10 @@ export abstract class HeapSnapshot {
|
||||
const sortedCandidates = Array.from(candidates.values());
|
||||
sortedCandidates.sort((a, b) => b.count - a.count);
|
||||
const result: InterfaceDefinition[] = [];
|
||||
const maxResultSize = Math.min(sortedCandidates.length, MAX_INTERFACE_COUNT);
|
||||
for (let i = 0; i < maxResultSize; ++i) {
|
||||
const minCount = Math.max(MIN_OBJECT_COUNT_PER_INTERFACE, totalObjectCount / MIN_OBJECT_PROPORTION_PER_INTERFACE);
|
||||
for (let i = 0; i < sortedCandidates.length; ++i) {
|
||||
const candidate = sortedCandidates[i];
|
||||
if (candidate.count < MIN_OBJECT_COUNT_PER_INTERFACE) {
|
||||
if (candidate.count < minCount) {
|
||||
break;
|
||||
}
|
||||
result.push(candidate);
|
||||
|
||||
Reference in New Issue
Block a user