Migrate framework events backing data structure to datasource

Summary: This will allow us to build a nice table easily.

Reviewed By: lblasa

Differential Revision: D47520029

fbshipit-source-id: 3cdd776533b66688329171eb29b892e0b9153540
This commit is contained in:
Luke De Feo
2023-07-19 08:58:20 -07:00
committed by Facebook GitHub Bot
parent 16480a95f3
commit 7812dae764
6 changed files with 46 additions and 53 deletions

View File

@@ -17,14 +17,12 @@ import {
} from '../types';
import React, {useMemo} from 'react';
import {
Atom,
DataInspector,
DataSource,
DataTable,
DataTableColumn,
DetailSidebar,
Layout,
useValue,
} from 'flipper-plugin';
export function PerfStats(props: {
@@ -32,15 +30,13 @@ export function PerfStats(props: {
nodes: Map<Id, UINode>;
rootId?: Id;
events: DataSource<DynamicPerformanceStatsEvent, number>;
frameworkEvents: Atom<Map<Id, FrameworkEvent[]>>;
frameworkEvents: DataSource<FrameworkEvent>;
}) {
const uiStateValues = Object.entries(props.uiState).map(([key, value]) => [
key,
value.get(),
]);
const frameworkEventsValue = useValue(props.frameworkEvents);
const allColumns = useMemo(() => {
if (props.events.size > 0) {
const row = props.events.get(0);
@@ -65,7 +61,6 @@ export function PerfStats(props: {
return columns;
}, [props.events]);
const newLocal = [...frameworkEventsValue.entries()];
return (
<Layout.Container grow>
<DataTable<PerformanceStatsEvent>
@@ -79,11 +74,7 @@ export function PerfStats(props: {
rootId: props.rootId,
nodesCount: props.nodes.size,
rootNode: props.nodes.get(props.rootId ?? 'noroot'),
frameworkEvents: newLocal,
frameworkEventsSize: newLocal.reduce(
(acc, value) => acc + value[1].length,
0,
),
frameworkEventsSize: props.frameworkEvents.size,
}}></DataInspector>
</DetailSidebar>
</Layout.Container>

View File

@@ -24,6 +24,7 @@ import React, {
useRef,
} from 'react';
import {
DataSource,
getFlipperLib,
HighlightManager,
HighlightProvider,
@@ -69,6 +70,7 @@ export type TreeNode = UINode & {
idx: number;
isExpanded: boolean;
indentGuide: NodeIndentGuide | null;
frameworkEvents: number | null;
};
export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
const instance = usePlugin(plugin);
@@ -79,7 +81,6 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
const isContextMenuOpen = useValue(instance.uiState.isContextMenuOpen);
const hoveredNode = head(useValue(instance.uiState.hoveredNodes));
const frameworkEvents = useValue(instance.frameworkEvents);
const filterMainThreadMonitoring = useValue(
instance.uiState.filterMainThreadMonitoring,
);
@@ -94,6 +95,9 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
focusedNode || rootId,
expandedNodes,
selectedNode?.id,
instance.frameworkEvents,
frameworkEventsMonitoring,
filterMainThreadMonitoring,
);
const refs: React.RefObject<HTMLLIElement>[] = treeNodes.map(() =>
@@ -101,7 +105,16 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
);
return {treeNodes, refs};
}, [expandedNodes, focusedNode, nodes, rootId, selectedNode]);
}, [
expandedNodes,
filterMainThreadMonitoring,
focusedNode,
frameworkEventsMonitoring,
instance.frameworkEvents,
nodes,
rootId,
selectedNode?.id,
]);
const isUsingKBToScrollUtill = useRef<MillisSinceEpoch>(0);
@@ -240,9 +253,6 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
innerRef={refs[virtualRow.index]}
key={virtualRow.index}
treeNode={treeNodes[virtualRow.index]}
frameworkEvents={frameworkEvents}
frameworkEventsMonitoring={frameworkEventsMonitoring}
filterMainThreadMonitoring={filterMainThreadMonitoring}
highlightedNodes={highlightedNodes}
selectedNode={selectedNode?.id}
hoveredNode={hoveredNode}
@@ -292,9 +302,6 @@ function TreeItemContainer({
transform,
innerRef,
treeNode,
frameworkEvents,
frameworkEventsMonitoring,
filterMainThreadMonitoring,
highlightedNodes,
selectedNode,
hoveredNode,
@@ -308,10 +315,7 @@ function TreeItemContainer({
transform: string;
innerRef: Ref<any>;
treeNode: TreeNode;
frameworkEvents: Map<Id, FrameworkEvent[]>;
highlightedNodes: Set<Id>;
frameworkEventsMonitoring: Map<FrameworkEventType, boolean>;
filterMainThreadMonitoring: boolean;
selectedNode?: Id;
hoveredNode?: Id;
isUsingKBToScroll: RefObject<MillisSinceEpoch>;
@@ -321,15 +325,6 @@ function TreeItemContainer({
onCollapseNode: (node: Id) => void;
onHoverNode: (node: Id) => void;
}) {
let events = frameworkEvents.get(treeNode.id);
if (events) {
events = events
.filter((e) => frameworkEventsMonitoring.get(e.type))
.filter(
(e) => filterMainThreadMonitoring === false || e.thread === 'main',
);
}
return (
<div
ref={innerRef}
@@ -375,9 +370,9 @@ function TreeItemContainer({
{nodeIcon(treeNode)}
<TreeItemRowContent treeNode={treeNode} />
{events && (
{treeNode.frameworkEvents && (
<Badge
count={events.length}
count={treeNode.frameworkEvents}
style={{
backgroundColor: theme.primaryColor,
marginLeft: theme.space.small,
@@ -616,6 +611,9 @@ function toTreeNodes(
rootId: Id,
expandedNodes: Set<Id>,
selectedNode: Id | undefined,
frameworkEvents: DataSource<FrameworkEvent>,
frameworkEventsMonitoring: Map<FrameworkEventType, boolean>,
filterMainThreadMonitoring: boolean,
): TreeNode[] {
const root = nodes.get(rootId);
if (root == null) {
@@ -643,11 +641,21 @@ function toTreeNodes(
const isExpanded = expandedNodes.has(node.id);
const isSelected = node.id === selectedNode;
let events = frameworkEvents.getAllRecordsByIndex({nodeId: node.id});
if (events) {
events = events
.filter((e) => frameworkEventsMonitoring.get(e.type))
.filter(
(e) => filterMainThreadMonitoring === false || e.thread === 'main',
);
}
treeNodes.push({
...node,
idx: i,
depth,
isExpanded,
frameworkEvents: events.length > 0 ? events.length : null,
indentGuide: stackItem.isChildOfSelectedNode
? {
depth: stackItem.selectedNodeDepth,

View File

@@ -42,7 +42,6 @@ export const Inspector: React.FC<Props> = ({
}) => {
const instance = usePlugin(plugin);
const selectedNodeId = useValue(instance.uiState.selectedNode)?.id;
const frameworkEvents = useValue(instance.frameworkEvents);
const selectedNode = selectedNodeId ? nodes.get(selectedNodeId) : undefined;
if (!selectedNode) {
@@ -50,8 +49,8 @@ export const Inspector: React.FC<Props> = ({
}
const selectedFrameworkEvents = selectedNodeId
? frameworkEvents?.get(selectedNodeId)
: undefined;
? instance.frameworkEvents.getAllRecordsByIndex({nodeId: selectedNodeId})
: [];
return (
<Layout.Container gap pad>
@@ -108,7 +107,7 @@ export const Inspector: React.FC<Props> = ({
/>
</Tab>
)}
{selectedFrameworkEvents && (
{selectedFrameworkEvents?.length > 0 && (
<Tab
key={'events'}
tab={

View File

@@ -15,7 +15,7 @@ import {StackTraceInspector} from './StackTraceInspector';
type Props = {
node: UINode;
events: FrameworkEvent[];
events: readonly FrameworkEvent[];
showExtra?: (element: ReactNode) => void;
};
export const FrameworkEventsInspector: React.FC<Props> = ({
@@ -41,7 +41,7 @@ export const FrameworkEventsInspector: React.FC<Props> = ({
};
const hasStacktrace = (event: FrameworkEvent) => {
return event.attribution?.type === 'stacktrace';
return event?.attribution?.type === 'stacktrace';
};
return (

View File

@@ -143,7 +143,7 @@ export function plugin(client: PluginClient<Events>) {
clearCallBack: async () => {
uiState.streamState.set({state: 'Ok'});
nodesAtom.set(new Map());
frameworkEvents.set(new Map());
frameworkEvents.clear();
snapshot.set(null);
},
});
@@ -191,7 +191,10 @@ export function plugin(client: PluginClient<Events>) {
});
const nodesAtom = createState<Map<Id, UINode>>(new Map());
const frameworkEvents = createState<Map<Id, FrameworkEvent[]>>(new Map());
const frameworkEvents = createDataSource<FrameworkEvent>([], {
indices: [['nodeId']],
limit: 10000,
});
const highlightedNodes = createState(new Set<Id>());
const snapshot = createState<SnapshotInfo | null>(null);
@@ -279,18 +282,9 @@ export function plugin(client: PluginClient<Events>) {
};
function applyFrameworkEvents(frameScan: FrameScanEvent) {
frameworkEvents.update((draft) => {
if (frameScan?.frameworkEvents) {
frameScan.frameworkEvents.forEach((frameworkEvent) => {
const frameworkEventsForNode = draft.get(frameworkEvent.nodeId);
if (frameworkEventsForNode) {
frameworkEventsForNode.push(frameworkEvent);
} else {
draft.set(frameworkEvent.nodeId, [frameworkEvent]);
for (const frameworkEvent of frameScan.frameworkEvents ?? []) {
frameworkEvents.append(frameworkEvent);
}
});
}
});
if (uiState.isPaused.get() === true) {
return;

View File

@@ -110,6 +110,7 @@ type UpstreamEvent = {type: 'upstreamEvent'; eventId: Id};
type FrameworkEventAttribution = Stacktrace | Reason | UpstreamEvent;
export type FrameworkEvent = {
id: number;
nodeId: Id;
type: FrameworkEventType;
timestamp: number;