Skip to content

Commit dbdbef9

Browse files
Merge pull request #230 from preactjs/stats-panel
2 parents b29307c + 7c17f75 commit dbdbef9

31 files changed

+1372
-40
lines changed

.changeset/stats-panel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"preact-devtools": minor
3+
---
4+
5+
Add a new "Statistics"-tab that collects data about the most common operations of the renderer.

src/adapter/10/renderer.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ describe("Renderer 10", () => {
380380
"Add 7 <span> to parent 4",
381381
"Add 8 <span> to parent 4",
382382
"Remove 3", // TODO: Seems wrong
383-
"Remove 1",
383+
"Remove 3", // TODO: Seems wrong
384384
]);
385385
});
386386

src/adapter/10/renderer.ts

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { BaseEvent, PortPageHook } from "../adapter/port";
22
import { Commit, MsgTypes, flush } from "../events/events";
33
import {
4-
Fragment,
54
VNode,
65
FunctionalComponent,
76
ComponentConstructor,
@@ -45,6 +44,13 @@ import {
4544
measureUpdate,
4645
startDrawing,
4746
} from "../adapter/highlightUpdates";
47+
import {
48+
createStats,
49+
DiffType,
50+
getDiffType,
51+
updateDiffStats,
52+
recordComponentStats,
53+
} from "./stats";
4854

4955
export interface RendererConfig10 {
5056
Fragment: FunctionalComponent;
@@ -58,7 +64,7 @@ const forwardRefReg = /^ForwardRef\(/;
5864
* between the various forms of components.
5965
*/
6066
export function getDevtoolsType(vnode: VNode): DevNodeType {
61-
if (typeof vnode.type == "function" && vnode.type !== Fragment) {
67+
if (typeof vnode.type == "function") {
6268
const name = vnode.type.displayName || "";
6369
if (memoReg.test(name)) return DevNodeType.Memo;
6470
if (forwardRefReg.test(name)) return DevNodeType.ForwardRef;
@@ -142,6 +148,10 @@ export function mount(
142148
config: RendererConfig10,
143149
profiler: ProfilerState,
144150
) {
151+
if (commit.stats !== null) {
152+
commit.stats.mounts++;
153+
}
154+
145155
const root = isRoot(vnode, config);
146156

147157
const skip = shouldFilter(vnode, filters, config);
@@ -182,10 +192,18 @@ export function mount(
182192
if (dom) domCache.set(dom, vnode);
183193
}
184194

195+
let diff = DiffType.UNKNOWN;
196+
let childCount = 0;
197+
185198
const children = getActualChildren(vnode);
186199
for (let i = 0; i < children.length; i++) {
187200
const child = children[i];
188201
if (child != null) {
202+
if (commit.stats !== null) {
203+
diff = getDiffType(child, diff);
204+
childCount++;
205+
}
206+
189207
mount(
190208
ids,
191209
commit,
@@ -198,6 +216,11 @@ export function mount(
198216
);
199217
}
200218
}
219+
220+
if (commit.stats !== null) {
221+
updateDiffStats(commit.stats, diff, childCount);
222+
recordComponentStats(config, commit.stats, vnode, children);
223+
}
201224
}
202225

203226
export function resetChildren(
@@ -232,12 +255,24 @@ export function update(
232255
config: RendererConfig10,
233256
profiler: ProfilerState,
234257
) {
258+
if (commit.stats !== null) {
259+
commit.stats.updates++;
260+
}
261+
262+
let diff = DiffType.UNKNOWN;
263+
235264
const skip = shouldFilter(vnode, filters, config);
236265
if (skip) {
266+
let childCount = 0;
237267
const children = getActualChildren(vnode);
238268
for (let i = 0; i < children.length; i++) {
239269
const child = children[i];
240270
if (child != null) {
271+
if (commit.stats !== null) {
272+
diff = getDiffType(child, diff);
273+
childCount++;
274+
}
275+
241276
update(
242277
ids,
243278
commit,
@@ -250,6 +285,11 @@ export function update(
250285
);
251286
}
252287
}
288+
289+
if (commit.stats !== null) {
290+
updateDiffStats(commit.stats, diff, childCount);
291+
recordComponentStats(config, commit.stats, vnode, children);
292+
}
253293
return;
254294
}
255295

@@ -289,6 +329,7 @@ export function update(
289329
: [];
290330

291331
let shouldReorder = false;
332+
let childCount = 0;
292333

293334
const children = getActualChildren(vnode);
294335
for (let i = 0; i < children.length; i++) {
@@ -298,15 +339,28 @@ export function update(
298339
commit.unmountIds.push(oldChildren[i]);
299340
}
300341
} else if (hasVNodeId(ids, child) || shouldFilter(child, filters, config)) {
342+
if (commit.stats !== null) {
343+
diff = getDiffType(child, diff);
344+
childCount++;
345+
}
301346
update(ids, commit, child, id, filters, domCache, config, profiler);
302347
// TODO: This is only sometimes necessary
303348
shouldReorder = true;
304349
} else {
350+
if (commit.stats !== null) {
351+
diff = getDiffType(child, diff);
352+
childCount++;
353+
}
305354
mount(ids, commit, child, id, filters, domCache, config, profiler);
306355
shouldReorder = true;
307356
}
308357
}
309358

359+
if (commit.stats !== null) {
360+
updateDiffStats(commit.stats, diff, childCount);
361+
recordComponentStats(config, commit.stats, vnode, children);
362+
}
363+
310364
if (shouldReorder) {
311365
resetChildren(commit, ids, id, vnode, filters, config);
312366
}
@@ -320,20 +374,28 @@ export function createCommit(
320374
domCache: WeakMap<HTMLElement | Text, VNode>,
321375
config: RendererConfig10,
322376
profiler: ProfilerState,
377+
statState: StatState,
323378
): Commit {
324379
const commit = {
325380
operations: [],
326381
rootId: -1,
327382
strings: new Map(),
328383
unmountIds: [],
329384
renderReasons: new Map(),
385+
stats: statState.isRecording ? createStats() : null,
330386
};
331387

332388
let parentId = -1;
333389

334390
const isNew = !hasVNodeId(ids, vnode);
335391

336392
if (isRoot(vnode, config)) {
393+
if (commit.stats !== null) {
394+
commit.stats.roots.total++;
395+
const children = getActualChildren(vnode);
396+
commit.stats.roots.children.push(children.length);
397+
}
398+
337399
parentId = -1;
338400
roots.add(vnode);
339401
} else {
@@ -370,6 +432,10 @@ export interface ProfilerState {
370432
captureRenderReasons: boolean;
371433
}
372434

435+
export interface StatState {
436+
isRecording: boolean;
437+
}
438+
373439
export interface Supports {
374440
renderReasons: boolean;
375441
hooks: boolean;
@@ -398,6 +464,10 @@ export function createRenderer(
398464
captureRenderReasons: false,
399465
};
400466

467+
const statState: StatState = {
468+
isRecording: false,
469+
};
470+
401471
function onUnmount(vnode: VNode) {
402472
if (!shouldFilter(vnode, filters, config)) {
403473
if (hasVNodeId(ids, vnode)) {
@@ -433,6 +503,13 @@ export function createRenderer(
433503
profiler.pendingHighlightUpdates.clear();
434504
},
435505

506+
startRecordStats: () => {
507+
statState.isRecording = true;
508+
},
509+
stopRecordStats: () => {
510+
statState.isRecording = false;
511+
},
512+
436513
startProfiling: options => {
437514
profiler.isProfiling = true;
438515
profiler.captureRenderReasons =
@@ -517,8 +594,13 @@ export function createRenderer(
517594
rootId,
518595
strings: new Map(),
519596
unmountIds: currentUnmounts,
597+
stats: statState.isRecording ? createStats() : null,
520598
};
521599

600+
if (commit.stats !== null) {
601+
commit.stats.unmounts += commit.unmountIds.length;
602+
}
603+
522604
const unmounts = flush(commit);
523605
if (unmounts) {
524606
currentUnmounts = [];
@@ -538,6 +620,7 @@ export function createRenderer(
538620
domToVNode,
539621
config,
540622
profiler,
623+
statState,
541624
);
542625
const ev = flush(commit);
543626
if (!ev) return;
@@ -556,8 +639,13 @@ export function createRenderer(
556639
domToVNode,
557640
config,
558641
profiler,
642+
statState,
559643
);
560644

645+
if (commit.stats !== null) {
646+
commit.stats.unmounts += currentUnmounts.length;
647+
}
648+
561649
commit.unmountIds.push(...currentUnmounts);
562650
currentUnmounts = [];
563651
const ev = flush(commit);

0 commit comments

Comments
 (0)