Skip to content

Commit

Permalink
Added Network measures to the Scheduling Profiler
Browse files Browse the repository at this point in the history
Also slightly refactored the preprocessData data function to split separate sections out into helper functions for readability. (We can do more of this for other mark types in a follow up commit.)
  • Loading branch information
Brian Vaughn committed Aug 17, 2021
1 parent 8893622 commit 7b55689
Show file tree
Hide file tree
Showing 14 changed files with 733 additions and 111 deletions.
77 changes: 71 additions & 6 deletions packages/react-devtools-scheduling-profiler/src/CanvasPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
ComponentMeasuresView,
FlamechartView,
NativeEventsView,
NetworkMeasuresView,
ReactMeasuresView,
SchedulingEventsView,
SnapshotsView,
Expand Down Expand Up @@ -158,6 +159,7 @@ function AutoSizedCanvas({
const componentMeasuresViewRef = useRef(null);
const reactMeasuresViewRef = useRef(null);
const flamechartViewRef = useRef(null);
const networkMeasuresViewRef = useRef(null);
const snapshotsViewRef = useRef(null);

const {hideMenu: hideContextMenu} = useContext(RegistryContext);
Expand Down Expand Up @@ -318,6 +320,22 @@ function AutoSizedCanvas({
);
}

let networkMeasuresViewWrapper = null;
if (data.snapshots.length > 0) {
const networkMeasuresView = new NetworkMeasuresView(
surface,
defaultFrame,
data,
);
networkMeasuresViewRef.current = networkMeasuresView;
networkMeasuresViewWrapper = createViewHelper(
networkMeasuresView,
'network',
true,
true,
);
}

const flamechartView = new FlamechartView(
surface,
defaultFrame,
Expand Down Expand Up @@ -357,6 +375,9 @@ function AutoSizedCanvas({
if (snapshotsViewWrapper !== null) {
rootView.addSubview(snapshotsViewWrapper);
}
if (networkMeasuresViewWrapper !== null) {
rootView.addSubview(networkMeasuresViewWrapper);
}
rootView.addSubview(flamechartViewWrapper);

const verticalScrollOverflowView = new VerticalScrollOverflowView(
Expand Down Expand Up @@ -405,6 +426,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure: null,
nativeEvent: null,
networkMeasure: null,
schedulingEvent: null,
snapshot: null,
suspenseEvent: null,
Expand Down Expand Up @@ -464,6 +486,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure: null,
nativeEvent: null,
networkMeasure: null,
schedulingEvent: null,
snapshot: null,
suspenseEvent: null,
Expand All @@ -483,6 +506,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure: null,
nativeEvent,
networkMeasure: null,
schedulingEvent: null,
snapshot: null,
suspenseEvent: null,
Expand All @@ -502,6 +526,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure: null,
nativeEvent: null,
networkMeasure: null,
schedulingEvent,
snapshot: null,
suspenseEvent: null,
Expand All @@ -521,6 +546,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure: null,
nativeEvent: null,
networkMeasure: null,
schedulingEvent: null,
snapshot: null,
suspenseEvent,
Expand All @@ -540,6 +566,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure,
nativeEvent: null,
networkMeasure: null,
schedulingEvent: null,
snapshot: null,
suspenseEvent: null,
Expand All @@ -562,6 +589,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure: null,
nativeEvent: null,
networkMeasure: null,
schedulingEvent: null,
snapshot: null,
suspenseEvent: null,
Expand All @@ -581,6 +609,7 @@ function AutoSizedCanvas({
flamechartStackFrame: null,
measure: null,
nativeEvent: null,
networkMeasure: null,
schedulingEvent: null,
snapshot,
suspenseEvent: null,
Expand All @@ -603,6 +632,7 @@ function AutoSizedCanvas({
flamechartStackFrame,
measure: null,
nativeEvent: null,
networkMeasure: null,
schedulingEvent: null,
snapshot: null,
suspenseEvent: null,
Expand All @@ -611,53 +641,80 @@ function AutoSizedCanvas({
}
});
}

const {current: networkMeasuresView} = networkMeasuresViewRef;
if (networkMeasuresView) {
networkMeasuresView.onHover = networkMeasure => {
if (!hoveredEvent || hoveredEvent.networkMeasure !== networkMeasure) {
setHoveredEvent({
componentMeasure: null,
data,
flamechartStackFrame: null,
measure: null,
nativeEvent: null,
networkMeasure,
schedulingEvent: null,
snapshot: null,
suspenseEvent: null,
userTimingMark: null,
});
}
};
}
}, [
hoveredEvent,
data, // Attach onHover callbacks when views are re-created on data change
]);

useLayoutEffect(() => {
const {current: userTimingMarksView} = userTimingMarksViewRef;
const userTimingMarksView = userTimingMarksViewRef.current;
if (userTimingMarksView) {
userTimingMarksView.setHoveredMark(
hoveredEvent ? hoveredEvent.userTimingMark : null,
);
}

const {current: nativeEventsView} = nativeEventsViewRef;
const nativeEventsView = nativeEventsViewRef.current;
if (nativeEventsView) {
nativeEventsView.setHoveredEvent(
hoveredEvent ? hoveredEvent.nativeEvent : null,
);
}

const {current: schedulingEventsView} = schedulingEventsViewRef;
const schedulingEventsView = schedulingEventsViewRef.current;
if (schedulingEventsView) {
schedulingEventsView.setHoveredEvent(
hoveredEvent ? hoveredEvent.schedulingEvent : null,
);
}

const {current: suspenseEventsView} = suspenseEventsViewRef;
const suspenseEventsView = suspenseEventsViewRef.current;
if (suspenseEventsView) {
suspenseEventsView.setHoveredEvent(
hoveredEvent ? hoveredEvent.suspenseEvent : null,
);
}

const {current: reactMeasuresView} = reactMeasuresViewRef;
const reactMeasuresView = reactMeasuresViewRef.current;
if (reactMeasuresView) {
reactMeasuresView.setHoveredMeasure(
hoveredEvent ? hoveredEvent.measure : null,
);
}

const {current: flamechartView} = flamechartViewRef;
const flamechartView = flamechartViewRef.current;
if (flamechartView) {
flamechartView.setHoveredFlamechartStackFrame(
hoveredEvent ? hoveredEvent.flamechartStackFrame : null,
);
}

const networkMeasuresView = networkMeasuresViewRef.current;
if (networkMeasuresView) {
networkMeasuresView.setHoveredEvent(
hoveredEvent ? hoveredEvent.networkMeasure : null,
);
}
}, [hoveredEvent]);

// Draw to canvas in React's commit phase
Expand All @@ -677,6 +734,7 @@ function AutoSizedCanvas({
componentMeasure,
flamechartStackFrame,
measure,
networkMeasure,
schedulingEvent,
suspenseEvent,
} = contextData.hoveredEvent;
Expand All @@ -689,6 +747,13 @@ function AutoSizedCanvas({
Copy component name
</ContextMenuItem>
)}
{networkMeasure !== null && (
<ContextMenuItem
onClick={() => copy(networkMeasure.url)}
title="Copy URL">
Copy URL
</ContextMenuItem>
)}
{schedulingEvent !== null && (
<ContextMenuItem
onClick={() => copy(schedulingEvent.componentName)}
Expand Down
15 changes: 13 additions & 2 deletions packages/react-devtools-scheduling-profiler/src/EventTooltip.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
}

.TooltipSection,
.TooltipWarningSection {
.TooltipWarningSection,
.SingleLineTextSection {
display: block;
border-radius: 0.125rem;
max-width: 300px;
padding: 0.25rem;
user-select: none;
pointer-events: none;
Expand All @@ -19,6 +19,13 @@
margin-top: 0.25rem;
background-color: var(--color-warning-background);
}
.TooltipSection,
.TooltipWarningSection {
max-width: 300px;
}
.SingleLineTextSection {
white-space: nowrap;
}

.Divider {
height: 1px;
Expand Down Expand Up @@ -75,4 +82,8 @@

.Image {
border: 1px solid var(--color-border);
}

.DimText {
color: var(--color-dim);
}
49 changes: 49 additions & 0 deletions packages/react-devtools-scheduling-profiler/src/EventTooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {Point} from './view-base';
import type {
FlamechartStackFrame,
NativeEvent,
NetworkMeasure,
ReactComponentMeasure,
ReactHoverContextInfo,
ReactMeasure,
Expand All @@ -29,6 +30,8 @@ import {getBatchRange} from './utils/getBatchRange';
import useSmartTooltip from './utils/useSmartTooltip';
import styles from './EventTooltip.css';

const MAX_TOOLTIP_TEXT_LENGTH = 60;

type Props = {|
canvasRef: {|current: HTMLCanvasElement | null|},
data: ReactProfilerData,
Expand Down Expand Up @@ -87,6 +90,7 @@ export default function EventTooltip({
flamechartStackFrame,
measure,
nativeEvent,
networkMeasure,
schedulingEvent,
snapshot,
suspenseEvent,
Expand All @@ -104,6 +108,13 @@ export default function EventTooltip({
return (
<TooltipNativeEvent nativeEvent={nativeEvent} tooltipRef={tooltipRef} />
);
} else if (networkMeasure !== null) {
return (
<TooltipNetworkMeasure
networkMeasure={networkMeasure}
tooltipRef={tooltipRef}
/>
);
} else if (schedulingEvent !== null) {
return (
<TooltipSchedulingEvent
Expand Down Expand Up @@ -238,6 +249,44 @@ const TooltipNativeEvent = ({
);
};

const TooltipNetworkMeasure = ({
networkMeasure,
tooltipRef,
}: {
networkMeasure: NetworkMeasure,
tooltipRef: Return<typeof useRef>,
}) => {
const {
finishTimestamp,
lastReceivedDataTimestamp,
priority,
sendRequestTimestamp,
url,
} = networkMeasure;

let urlToDisplay = url;
if (urlToDisplay.length > MAX_TOOLTIP_TEXT_LENGTH) {
const half = Math.floor(MAX_TOOLTIP_TEXT_LENGTH / 2);
urlToDisplay = url.substr(0, half) + '…' + url.substr(url.length - half);
}

const timestampBegin = sendRequestTimestamp;
const timestampEnd = finishTimestamp || lastReceivedDataTimestamp;
const duration =
timestampEnd > 0
? formatDuration(finishTimestamp - timestampBegin)
: '(incomplete)';

return (
<div className={styles.Tooltip} ref={tooltipRef}>
<div className={styles.SingleLineTextSection}>
{duration} <span className={styles.DimText}>{priority}</span>{' '}
{urlToDisplay}
</div>
</div>
);
};

const TooltipSchedulingEvent = ({
data,
schedulingEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export class ComponentMeasuresView extends View {
this.currentCursor = 'context-menu';
viewRefs.hoveredView = this;
onHover(componentMeasure);
return;
return true;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ class FlamechartStackLayerView extends View {
this.currentCursor = 'context-menu';
viewRefs.hoveredView = this;
_onHover(flamechartStackFrame);
return;
return true;
}
}

Expand Down
Loading

0 comments on commit 7b55689

Please sign in to comment.