Skip to content

Commit f26ab17

Browse files
committed
feat: heap src
1 parent 0899f49 commit f26ab17

File tree

17 files changed

+134
-134
lines changed

17 files changed

+134
-134
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*---------------------------------------------------------
2+
* Copyright (C) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------*/
4+
5+
import { INode } from './model';
6+
7+
/**
8+
* Gets the human-readable label for the given node.
9+
*/
10+
export const getNodeText = (node: INode) => {
11+
if (!node.callFrame.url) {
12+
return; // 'virtual' frames like (program) or (idle)
13+
}
14+
15+
if (!node.src?.source.path) {
16+
let text = `${node.callFrame.url}`;
17+
if (node.callFrame.lineNumber >= 0) {
18+
text += `:${node.callFrame.lineNumber}`;
19+
}
20+
21+
return text;
22+
}
23+
24+
if (node.src.relativePath) {
25+
return `${node.src.relativePath}:${node.src.lineNumber}`;
26+
}
27+
28+
return `${node.src.source.path}:${node.src.lineNumber}`;
29+
};
30+
31+
export const decimalFormat = new Intl.NumberFormat(undefined, {
32+
maximumFractionDigits: 2,
33+
minimumFractionDigits: 2,
34+
});

packages/vscode-js-profile-core/src/common/model.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export interface INode {
1919
id: number;
2020
category: Category;
2121
callFrame: Cdp.Runtime.CallFrame;
22+
src?: ISourceLocation;
2223
}
2324

2425
export interface ICommonNode extends INode {

packages/vscode-js-profile-core/src/cpu/display.ts

-26
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,6 @@
22
* Copyright (C) Microsoft Corporation. All rights reserved.
33
*--------------------------------------------------------*/
44

5-
import { ILocation } from './model';
6-
7-
/**
8-
* Gets the human-readable label for the given location.
9-
*/
10-
export const getLocationText = (location: ILocation) => {
11-
if (!location.callFrame.url) {
12-
return; // 'virtual' frames like (program) or (idle)
13-
}
14-
15-
if (!location.src?.source.path) {
16-
let text = `${location.callFrame.url}`;
17-
if (location.callFrame.lineNumber >= 0) {
18-
text += `:${location.callFrame.lineNumber}`;
19-
}
20-
21-
return text;
22-
}
23-
24-
if (location.src.relativePath) {
25-
return `${location.src.relativePath}:${location.src.lineNumber}`;
26-
}
27-
28-
return `${location.src.source.path}:${location.src.lineNumber}`;
29-
};
30-
315
export const decimalFormat = new Intl.NumberFormat(undefined, {
326
maximumFractionDigits: 2,
337
minimumFractionDigits: 2,

packages/vscode-js-profile-core/src/cpu/model.ts

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export interface ILocation extends INode {
2929
selfTime: number;
3030
aggregateTime: number;
3131
ticks: number;
32-
src?: ISourceLocation;
3332
}
3433

3534
export interface IGraphNode extends ILocation {

packages/vscode-js-profile-core/src/heap/display.ts

-18
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,6 @@
22
* Copyright (C) Microsoft Corporation. All rights reserved.
33
*--------------------------------------------------------*/
44

5-
import { ITreeNode } from './model';
6-
7-
/**
8-
* Gets the human-readable label for the given node.
9-
*/
10-
export const getNodeText = (node: ITreeNode) => {
11-
if (!node.callFrame.url) {
12-
return; // 'virtual' frames like (program) or (idle)
13-
}
14-
15-
let text = `${node.callFrame.url}`;
16-
if (node.callFrame.lineNumber >= 0) {
17-
text += `:${node.callFrame.lineNumber}`;
18-
}
19-
20-
return text;
21-
};
22-
235
export const decimalFormat = new Intl.NumberFormat(undefined, {
246
maximumFractionDigits: 0,
257
minimumFractionDigits: 0,

packages/vscode-js-profile-core/src/heap/model.ts

+33-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import { Protocol as Cdp } from 'devtools-protocol';
66
import { INode } from '../common/model';
7+
import { ISourceLocation } from '../location-mapping';
8+
import { maybeFileUrlToPath } from '../path';
79

810
export interface IHeapProfileNode extends INode {
911
selfSize: number;
@@ -30,17 +32,47 @@ export interface IHeapProfileRaw extends Cdp.HeapProfiler.SamplingHeapProfile {
3032
$vscode?: IJsDebugAnnotations;
3133
}
3234

35+
export interface IProfileModelNode
36+
extends Omit<Cdp.HeapProfiler.SamplingHeapProfileNode, 'children'> {
37+
src?: ISourceLocation;
38+
children: IProfileModelNode[];
39+
}
40+
3341
/**
3442
* Data model for the profile.
3543
*/
36-
export type IProfileModel = Cdp.HeapProfiler.SamplingHeapProfile & {
44+
export type IProfileModel = {
45+
head: IProfileModelNode;
46+
samples: Cdp.HeapProfiler.SamplingHeapProfileSample[];
3747
rootPath?: string;
3848
};
3949

4050
/**
4151
* Computes the model for the given profile.
4252
*/
4353
export const buildModel = (profile: IHeapProfileRaw): IProfileModel => {
54+
let nodes = [profile.head];
55+
56+
while (nodes.length) {
57+
const node = nodes.pop();
58+
59+
if (node) {
60+
const { callFrame } = node;
61+
(node as unknown as IHeapProfileNode).src = {
62+
lineNumber: callFrame.lineNumber,
63+
columnNumber: callFrame.columnNumber,
64+
source: {
65+
name: maybeFileUrlToPath(callFrame.url),
66+
path: maybeFileUrlToPath(callFrame.url),
67+
sourceReference: 0,
68+
},
69+
};
70+
if (node.children) {
71+
nodes = nodes.concat(node.children);
72+
}
73+
}
74+
}
75+
4476
return {
4577
head: profile.head,
4678
samples: profile.samples,

packages/vscode-js-profile-core/src/heap/tree.ts

+9-8
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
* Copyright (C) Microsoft Corporation. All rights reserved.
33
*--------------------------------------------------------*/
44

5-
import { Protocol as Cdp } from 'devtools-protocol';
65
import { categorize, Category } from '../common/model';
7-
import { IProfileModel, ITreeNode } from './model';
6+
import { IProfileModel, IProfileModelNode, ITreeNode } from './model';
87

98
export class TreeNode implements ITreeNode {
109
public static root() {
@@ -22,7 +21,7 @@ export class TreeNode implements ITreeNode {
2221
});
2322
}
2423

25-
public children: { [id: number]: ITreeNode } = {};
24+
public children: { [id: number]: TreeNode } = {};
2625
public totalSize = 0;
2726
public selfSize = 0;
2827
public childrenSize = 0;
@@ -36,10 +35,11 @@ export class TreeNode implements ITreeNode {
3635
return this.node.callFrame;
3736
}
3837

39-
constructor(
40-
public readonly node: Cdp.HeapProfiler.SamplingHeapProfileNode,
41-
public readonly parent?: TreeNode,
42-
) {
38+
public get src() {
39+
return this.node.src;
40+
}
41+
42+
constructor(public readonly node: IProfileModelNode, public readonly parent?: TreeNode) {
4343
this.category = categorize(node.callFrame, undefined);
4444
}
4545

@@ -52,11 +52,12 @@ export class TreeNode implements ITreeNode {
5252
totalSize: this.totalSize,
5353
id: this.id,
5454
callFrame: this.callFrame,
55+
src: this.src,
5556
};
5657
}
5758
}
5859

59-
const processNode = (node: Cdp.HeapProfiler.SamplingHeapProfileNode, parent: TreeNode) => {
60+
const processNode = (node: IProfileModelNode, parent: TreeNode) => {
6061
const treeNode = new TreeNode(node, parent);
6162

6263
node.children.forEach(child => {

packages/vscode-js-profile-flame/src/client/common/stack-list.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { useCallback, useContext, useEffect, useMemo, useState } from 'preact/ho
77
import * as GoToFileIcon from 'vscode-codicons/src/icons/go-to-file.svg';
88
import { Icon } from 'vscode-js-profile-core/out/esm/client/icons';
99
import { IVscodeApi, VsCodeApi } from 'vscode-js-profile-core/out/esm/client/vscodeApi';
10+
import { getNodeText } from 'vscode-js-profile-core/out/esm/common/display';
1011
import { IOpenDocumentMessage } from 'vscode-js-profile-core/out/esm/common/types';
11-
import { getLocationText } from 'vscode-js-profile-core/out/esm/cpu/display';
1212
import { Constants } from '../common/constants';
1313
import getBoxInRowColumn from '../common/get-boxIn-row-column';
1414
import styles from './common.css';
@@ -83,7 +83,7 @@ const BoxLink: FunctionComponent<{ box: IBox; onClick(box: IBox): void; link?: b
8383
);
8484

8585
const click = useCallback(() => onClick(box), [box, onClick]);
86-
const locText = getLocationText(box.loc);
86+
const locText = getNodeText(box.loc);
8787
const linkContent = (
8888
<Fragment>
8989
{box.loc.callFrame.functionName} <em>({locText})</em>

packages/vscode-js-profile-flame/src/client/common/types.ts

+6-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
* Copyright (C) Microsoft Corporation. All rights reserved.
33
*--------------------------------------------------------*/
44

5-
import { Category } from 'vscode-js-profile-core/out/esm/common/model';
5+
import { ILocation } from 'vscode-js-profile-core/out/esm/cpu/model';
6+
import { IHeapProfileNode } from 'vscode-js-profile-core/out/esm/heap/model';
67

78
export interface IBox {
89
column: number;
@@ -14,8 +15,8 @@ export interface IBox {
1415
color: number;
1516
level: number;
1617
text: string;
17-
loc: any;
18-
category: any;
18+
category: number;
19+
loc: IColumnRow;
1920
}
2021

2122
export interface IBounds {
@@ -30,13 +31,9 @@ export interface ICanvasSize {
3031
height: number;
3132
}
3233

33-
export interface IColumnRow {
34+
export type IColumnRow = (ILocation | IHeapProfileNode) & {
3435
graphId: number; //. unique ID of the location in the graph
35-
category: Category;
36-
callFrame?: any;
37-
id: number;
38-
[key: string]: any;
39-
}
36+
};
4037

4138
export interface IColumn {
4239
x1: number;

packages/vscode-js-profile-flame/src/client/cpu/client.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import { cpuProfileLayoutFactory } from 'vscode-js-profile-core/out/esm/cpu/layo
1313
import { IProfileModel } from 'vscode-js-profile-core/out/esm/cpu/model';
1414
import { IQueryResults, PropertyType } from 'vscode-js-profile-core/out/esm/ql';
1515
import styles from '../common/client.css';
16+
import { IColumn } from '../common/types';
1617
import { FlameGraph } from './flame-graph';
17-
import { buildColumns, buildLeftHeavyColumns, IColumn, LocationAccessor } from './stacks';
18+
import { buildColumns, buildLeftHeavyColumns, LocationAccessor } from './stacks';
1819

1920
declare const MODEL: IProfileModel;
2021

packages/vscode-js-profile-flame/src/client/cpu/flame-graph.tsx

+7-21
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,15 @@
55
import { Fragment, FunctionComponent, h } from 'preact';
66
import { MiddleOut } from 'vscode-js-profile-core/out/esm/client/middleOutCompression';
77
import { classes } from 'vscode-js-profile-core/out/esm/client/util';
8-
import { decimalFormat, getLocationText } from 'vscode-js-profile-core/out/esm/cpu/display';
8+
import { getNodeText } from 'vscode-js-profile-core/out/esm/common/display';
9+
import { decimalFormat } from 'vscode-js-profile-core/out/esm/cpu/display';
910
import { ILocation, IProfileModel } from 'vscode-js-profile-core/out/esm/cpu/model';
1011
import { Constants } from '../common/constants';
1112
import DragHandle from '../common/drag-handle';
1213
import styles from '../common/flame-graph.css';
1314
import StackList from '../common/stack-list';
14-
import { HighlightSource } from '../common/types';
15+
import { HighlightSource, IBox, IColumn } from '../common/types';
1516
import useFlame from '../common/use-flame';
16-
import { IColumn, IColumnLocation } from './stacks';
17-
18-
export interface IBox {
19-
column: number;
20-
row: number;
21-
x1: number;
22-
y1: number;
23-
x2: number;
24-
y2: number;
25-
color: number;
26-
level: number;
27-
text: string;
28-
category: number;
29-
loc: IColumnLocation;
30-
}
3117

3218
const clamp = (min: number, v: number, max: number) => Math.max(Math.min(v, max), min);
3319

@@ -103,7 +89,7 @@ export const FlameGraph: FunctionComponent<{
10389
upperY={canvasSize.height - hovered.box.y1 + bounds.y}
10490
lowerY={hovered.box.y2 - bounds.y}
10591
src={hovered.src}
106-
location={hovered.box.loc}
92+
location={hovered.box.loc as ILocation}
10793
/>
10894
)}
10995
{focused && showInfo && (
@@ -128,7 +114,7 @@ const Tooltip: FunctionComponent<{
128114
location: ILocation;
129115
src: HighlightSource;
130116
}> = ({ left, lowerY, upperY, src, location, canvasWidth, canvasHeight }) => {
131-
const label = getLocationText(location);
117+
const label = getNodeText(location);
132118
const above = lowerY + 300 > canvasHeight && lowerY > canvasHeight / 2;
133119

134120
const file = label?.split(/\\|\//g).pop();
@@ -183,9 +169,9 @@ const InfoBox: FunctionComponent<{
183169
<div className={styles.info}>
184170
<dl>
185171
<dt>Self Time</dt>
186-
<dd>{decimalFormat.format(localLocation.selfTime / 1000)}ms</dd>
172+
<dd>{decimalFormat.format((localLocation as ILocation).selfTime / 1000)}ms</dd>
187173
<dt>Total Time</dt>
188-
<dd>{decimalFormat.format(localLocation.aggregateTime / 1000)}ms</dd>
174+
<dd>{decimalFormat.format((localLocation as ILocation).aggregateTime / 1000)}ms</dd>
189175
<dt>
190176
Self Time<small>Entire Profile</small>
191177
</dt>

0 commit comments

Comments
 (0)