Skip to content

Commit 37cd49f

Browse files
Merge pull request #187 from preactjs/profiler-refactor2
2 parents b070deb + 2bc2741 commit 37cd49f

32 files changed

+917
-523
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"devDependencies": {
3030
"@babel/core": "^7.9.0",
3131
"@babel/plugin-transform-react-jsx": "^7.9.4",
32+
"@rollup/plugin-alias": "^3.1.0",
3233
"@rollup/plugin-replace": "^2.3.2",
3334
"@testing-library/preact": "^1.0.2",
3435
"@types/archiver": "^3.1.0",

rollup.config.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import resolve from "rollup-plugin-node-resolve";
55
import postcss from "rollup-plugin-postcss";
66
import commonjs from "rollup-plugin-commonjs";
77
import replace from "@rollup/plugin-replace";
8+
import alias from "@rollup/plugin-alias";
89
import path from "path";
910

1011
const BROWSERS = ["chrome", "edge", "firefox", "inline"].filter(x => {
@@ -112,6 +113,16 @@ export default entries.map(data => ({
112113
return comment + code;
113114
},
114115
},
116+
process.env.DEBUG === "true" &&
117+
alias({
118+
entries: [
119+
{
120+
find: "preact/hooks",
121+
replacement: "./node_modules/preact/hooks/src/index.js",
122+
},
123+
{ find: "preact", replacement: "./node_modules/preact/src/index.js" },
124+
],
125+
}),
115126
resolve(),
116127
commonjs(),
117128
replace({

src/adapter/events/operations.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,14 @@ export function ops2Tree(oldTree: Tree, ops: number[]) {
5555
const id = ops[i + 1];
5656
if (!pending.has(id)) {
5757
const node = oldTree.get(id)!;
58-
pending.set(id, deepClone(node));
58+
try {
59+
pending.set(id, deepClone(node));
60+
} catch (err) {
61+
// eslint-disable-next-line no-console
62+
console.error(`Missing node ${id} detected.`);
63+
throw err;
64+
}
5965
}
60-
6166
const x = pending.get(id)!;
6267
x.startTime = ops[i + 2] / 1000;
6368
x.endTime = ops[i + 3] / 1000;

src/shells/shared/panel/panel.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ async function initDevtools() {
3535
store.theme.on(v => storeTheme(v));
3636
store.profiler.captureRenderReasons.on(v => storeCaptureRenderReasons(v));
3737

38+
if (process.env.DEBUG) {
39+
(window as any).store = store;
40+
}
41+
3842
// Render our application
3943
const root = window.document.getElementById("root")!;
4044
render(h(DevTools, { store, window }), root);
@@ -52,14 +56,13 @@ port.onDisconnect.addListener(() => {
5256

5357
// Subscribe to messages from content script
5458
port.onMessage.addListener(async message => {
55-
debug("> message", message);
56-
5759
if (!initialized) {
5860
debug("initialize devtools panel");
5961
await initDevtools();
6062
}
6163

6264
if (message.type === "init") {
65+
debug("> message", message);
6366
port.postMessage({
6467
type: "init",
6568
tabId: chrome.devtools.inspectedWindow.tabId,

src/view/components/profiler/components/CommitTimeline/CommitTimeline.tsx

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -91,32 +91,30 @@ export function CommitTimeline(props: CommitTimelineProps) {
9191
const paneContainerRef = useRef<HTMLDivElement>();
9292

9393
useEffect(() => {
94-
const sizes = calcSize(
95-
container,
96-
inner,
97-
pane,
98-
paneContainerRef,
99-
items.length,
100-
selected,
101-
);
102-
setPaneWidth(sizes.pane);
103-
setViewportWidth(sizes.viewport);
104-
setOffset(sizes.offset);
105-
}, [pane, inner, pane, paneContainerRef, items.length, selected]);
106-
107-
useResize(() => {
108-
const sizes = calcSize(
109-
container,
110-
inner,
111-
pane,
112-
paneContainerRef,
113-
items.length,
114-
selected,
115-
);
116-
setPaneWidth(sizes.pane);
117-
setViewportWidth(sizes.viewport);
118-
setOffset(sizes.offset);
119-
}, [pane, container, paneContainerRef, inner, items.length, selected]);
94+
if (pane.current) {
95+
const active = pane.current.querySelector("[data-selected]");
96+
// JSDOM doesn't support scrollIntoView
97+
if (active && active.scrollIntoView) active.scrollIntoView();
98+
}
99+
}, [selected]);
100+
101+
useResize(
102+
() => {
103+
const sizes = calcSize(
104+
container,
105+
inner,
106+
pane,
107+
paneContainerRef,
108+
items.length,
109+
selected,
110+
);
111+
setPaneWidth(sizes.pane);
112+
setViewportWidth(sizes.viewport);
113+
setOffset(sizes.offset);
114+
},
115+
[pane, container, paneContainerRef, inner, items.length, selected],
116+
true,
117+
);
120118

121119
const onPrev = useCallback(() => {
122120
const next = selected - 1;

src/view/components/profiler/components/RenderedAt/RenderedAt.tsx

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,28 @@ import { useStore, useObserver } from "../../../../store/react-bindings";
33
import { SidebarPanel, Empty } from "../../../sidebar/SidebarPanel";
44
import s from "./RenderedAt.css";
55
import { formatTime } from "../../util";
6-
import { mapParents } from "../../flamegraph/transform/util";
76

87
export function RenderedAt() {
98
const store = useStore();
109
const data = useObserver(() => {
1110
const id = store.profiler.selectedNodeId.$;
1211

13-
return store.profiler.commits.$.filter(x => x.nodes.has(id))
14-
.filter(x => {
15-
if (id === x.commitRootId) return true;
16-
let keep = false;
17-
mapParents(x.nodes, id, node => {
18-
if (node.id === x.commitRootId) keep = true;
19-
});
20-
return keep;
21-
})
22-
.map((commit, commitIdx) => {
23-
const node = commit.nodes.get(id)!;
24-
return {
25-
id: commitIdx,
26-
startTime: node.startTime,
27-
selfDuration: node.selfDuration,
28-
};
29-
});
12+
return store.profiler.commits.$.filter(x => {
13+
if (x.nodes.has(id)) {
14+
const node = x.nodes.get(id)!;
15+
const root = x.nodes.get(x.commitRootId)!;
16+
return node.startTime >= root.startTime && node.endTime <= root.endTime;
17+
}
18+
19+
return false;
20+
}).map(commit => {
21+
const node = commit.nodes.get(id)!;
22+
return {
23+
index: store.profiler.commits.$.findIndex(x => x === commit),
24+
startTime: node.startTime,
25+
selfDuration: node.selfDuration,
26+
};
27+
});
3028
});
3129

3230
const commitIdx = useObserver(() => store.profiler.activeCommitIdx.$);
@@ -38,14 +36,14 @@ export function RenderedAt() {
3836
{data.length <= 0 ? (
3937
<Empty>Did not render during this profiling session</Empty>
4038
) : (
41-
<nav>
39+
<nav data-testid="rendered-at">
4240
{data.map(node => {
4341
return (
4442
<button
45-
key={node.id}
43+
key={node.index}
4644
class={s.item}
47-
data-active={commitIdx === node.id}
48-
onClick={() => (store.profiler.activeCommitIdx.$ = node.id)}
45+
data-active={commitIdx === node.index}
46+
onClick={() => (store.profiler.activeCommitIdx.$ = node.index)}
4947
>
5048
<span>
5149
{formatTime(node.startTime)} for{" "}

src/view/components/profiler/components/TimelineBar/TimelineBar.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ export function TimelineBar() {
2121

2222
const onCommitChange = useCallback(
2323
(n: number) => {
24-
store.profiler.activeCommitIdx.$ = n;
24+
const { activeCommitIdx, selectedNodeId, activeCommit } = store.profiler;
25+
26+
activeCommitIdx.$ = n;
27+
28+
if (activeCommit.$ && !activeCommit.$.nodes.has(selectedNodeId.$)) {
29+
selectedNodeId.$ = activeCommit.$.rootId;
30+
}
2531
},
2632
[store],
2733
);

src/view/components/profiler/data/commits.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
RenderReasonMap,
77
RenderReasonData,
88
} from "../../../../adapter/10/renderer/renderReasons";
9+
import { flattenNodeTree } from "../flamegraph/placeNodes";
910

1011
export interface ProfilerNode extends DevNode {
1112
selfDuration: number;
@@ -164,7 +165,7 @@ export function resetProfiler(state: ProfilerState) {
164165
export function recordProfilerCommit(
165166
tree: Map<ID, DevNode>,
166167
profiler: ProfilerState,
167-
rootId: number,
168+
commitRootId: number,
168169
) {
169170
const nodes = new Map<ID, ProfilerNode>();
170171

@@ -174,8 +175,13 @@ export function recordProfilerCommit(
174175
// The time of the node that took the longest to render
175176
let maxSelfDuration = 0;
176177

178+
const rootId = getRoot(tree, commitRootId);
179+
const items = new Set(flattenNodeTree(tree, rootId).map(x => x.id));
180+
177181
// Make shallow copies of each node
178182
tree.forEach((node, id) => {
183+
if (!items.has(id)) return;
184+
179185
nodes.set(id, {
180186
// deep clone
181187
...JSON.parse(JSON.stringify(node)),
@@ -216,15 +222,15 @@ export function recordProfilerCommit(
216222

217223
// Total commit duration
218224
let duration = 0;
219-
const root = nodes.get(rootId);
225+
const root = nodes.get(commitRootId);
220226
if (root) {
221227
duration = root.treeEndTime - root.treeStartTime;
222228
}
223229

224230
profiler.commits.update(arr => {
225231
arr.push({
226-
rootId: getRoot(tree, rootId),
227-
commitRootId: rootId,
232+
rootId: getRoot(tree, commitRootId),
233+
commitRootId: commitRootId,
228234
nodes,
229235
maxDepth,
230236
maxSelfDuration,

src/view/components/profiler/data/gradient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ export function getGradient(max: number, n: number) {
1010
}
1111
}
1212

13-
return i;
13+
return Math.max(i, 0);
1414
}

src/view/components/profiler/flamegraph/FlameGraph.css

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,29 @@
22
width: 100%;
33
max-width: 100%;
44
height: 100%;
5-
overflow: hidden;
65
position: relative;
6+
overflow-x: hidden;
77
}
88

99
.node {
1010
position: absolute;
1111
cursor: pointer;
1212
color: black;
1313
font-size: 0.8rem;
14-
padding: 0 0.2rem;
14+
padding: 0;
1515
height: 100%;
16-
white-space: nowrap;
17-
overflow: hidden;
18-
text-overflow: ellipsis;
1916
transition-property: all;
2017
transition-duration: 0.3s;
2118
padding-bottom: 1px;
19+
display: flex;
20+
align-items: center;
21+
}
22+
23+
.text {
24+
padding: 0 0.2rem;
25+
white-space: nowrap;
26+
text-overflow: ellipsis;
27+
overflow: hidden;
2228
}
2329

2430
.node::after {
@@ -36,24 +42,40 @@
3642
display: none;
3743
}
3844

39-
.node[data-weight="-1"]:not([data-overflow]) {
45+
.node[data-visible] {
46+
transition-property: all;
47+
}
48+
.node:not([data-visible]) {
49+
transition-property: opacity;
50+
transition-duration: 0.2s;
51+
opacity: 0;
52+
pointer-events: none;
53+
}
54+
.node[data-visible]:not([data-maximized]) {
55+
opacity: 1;
56+
}
57+
58+
.node[data-weight="-2"]:not([data-overflow]) {
4059
color: var(--color-bystander-text);
4160
}
42-
.node[data-weight="-1"]::after {
61+
.node[data-weight="-2"]::after {
4362
/* inline-pattern */
4463
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0IDQiPgo8ZGVmcz4KICA8cGF0dGVybgogICAgaWQ9ImRpYWdvbmFsLWhhdGNoIgogICAgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgIHdpZHRoPSI0IgogICAgaGVpZ2h0PSI0IgogID4KICAgIDxwYXRoCiAgICAgIGQ9Ik0tMSwxIGwyLC0yCk0wLDQgbDQsLTQKTTMsNSBsMiwtMiIKc3Ryb2tlPSIjZGVkZWRlIgpzdHJva2Utd2lkdGg9IjEiCiAgICAvPgogIDwvcGF0dGVybj4KICA8L2RlZnM+CiAgPHJlY3QKICAgIHg9IjAiCiAgICB5PSIwIgogICAgd2lkdGg9IjQiCiAgICBoZWlnaHQ9IjQiCiAgICBmaWxsPSJ1cmwoI2RpYWdvbmFsLWhhdGNoKSIKICA+PC9yZWN0Pgo8L3N2Zz4=");
4564
background-repeat: repeat;
4665
background-color: transparent;
4766
background-size: 0.25rem 0.25rem;
4867
}
49-
:global(.dark) .node[data-weight="-1"]::after {
68+
:global(.dark) .node[data-weight="-2"]::after {
5069
opacity: 0.5;
5170
}
5271

5372
.node[data-maximized]:not([data-selected]) {
5473
opacity: 0.5;
5574
}
5675

76+
.node[data-weight="-1"]::after {
77+
background: var(--color-profiler-old);
78+
}
5779
.node[data-weight="0"]::after {
5880
background: var(--color-profiler-gradient-0);
5981
}

0 commit comments

Comments
 (0)