Skip to content

Commit 72940af

Browse files
committed
WIP traced value support
1 parent b1a9cf1 commit 72940af

File tree

20 files changed

+834
-18
lines changed

20 files changed

+834
-18
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"common-tags": "^1.8.2",
8383
"copy-to-clipboard": "^3.3.3",
8484
"core-js": "^3.44.0",
85+
"devtools-reps": "^0.24.0",
8586
"escape-string-regexp": "^4.0.0",
8687
"gecko-profiler-demangle": "^0.3.3",
8788
"idb": "^8.0.3",
@@ -190,7 +191,7 @@
190191
"jsx"
191192
],
192193
"transformIgnorePatterns": [
193-
"/node_modules/(?!(query-string|decode-uri-component|split-on-first|filter-obj|@fetch-mock/jest|fetch-mock)/)"
194+
"/node_modules/(?!(query-string|decode-uri-component|split-on-first|filter-obj|@fetch-mock/jest|fetch-mock|devtools-reps)/)"
194195
],
195196
"moduleNameMapper": {
196197
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|ftl)$": "<rootDir>/src/test/fixtures/mocks/file-mock.js",

res/css/global.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,17 @@
2929
.colored-border.ellipsis {
3030
opacity: 0;
3131
}
32+
33+
/* Colors for DevTools Reps */
34+
:root {
35+
--number-color: #058b00;
36+
--string-color: #dd00a9;
37+
--null-color: #5c5c5f;
38+
--object-color: #0074e8;
39+
--caption-color: #0074e8;
40+
--location-color: #5c5c5f;
41+
--source-link-color: #0060df;
42+
--node-color: #003eaa;
43+
--reference-color: #0074e8;
44+
--comment-node-color: #5c5c5f;
45+
}

src/components/stack-chart/Canvas.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
typeof changeMouseTimePosition as ChangeMouseTimePosition,
2222
} from '../../actions/profile-view';
2323
import { mapCategoryColorNameToStackChartStyles } from '../../utils/colors';
24+
import { ValueSummaryReader } from '../../utils/value-summaries';
2425
import { TooltipCallNode } from '../tooltip/CallNode';
2526
import { TooltipMarker } from '../tooltip/Marker';
2627

@@ -101,6 +102,7 @@ const TEXT_CSS_PIXELS_OFFSET_TOP = 11;
101102
const FONT_SIZE = 10;
102103
const BORDER_OPACITY = 0.4;
103104

105+
104106
class StackChartCanvasImpl extends React.PureComponent<Props> {
105107
_textMeasurement: null | TextMeasurement;
106108
_textMeasurementCssToDeviceScale: number = 1;
@@ -601,13 +603,22 @@ class StackChartCanvasImpl extends React.PureComponent<Props> {
601603
);
602604
}
603605

606+
604607
const callNodeIndex = timing.callNode[stackTimingIndex];
605608
if (callNodeIndex === undefined) {
606609
return null;
607610
}
608611
const duration =
609612
timing.end[stackTimingIndex] - timing.start[stackTimingIndex];
610613

614+
let argumentSummaries = undefined;
615+
if (timing.argumentValues) {
616+
const argumentValues = timing.argumentValues[stackTimingIndex];
617+
if (argumentValues != -1) {
618+
argumentSummaries = ValueSummaryReader.getArgumentSummaries(thread.tracedValuesBuffer, thread.tracedObjectShapes, argumentValues);
619+
}
620+
}
621+
611622
return (
612623
<TooltipCallNode
613624
thread={thread}
@@ -621,6 +632,7 @@ class StackChartCanvasImpl extends React.PureComponent<Props> {
621632
callTreeSummaryStrategy="timing"
622633
durationText={formatMilliseconds(duration)}
623634
displayStackType={displayStackType}
635+
argumentValues={argumentSummaries}
624636
/>
625637
);
626638
};

src/components/tooltip/CallNode.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ import type {
3232
} from 'firefox-profiler/profile-logic/profile-data';
3333
import type { CallNodeInfo } from 'firefox-profiler/profile-logic/call-node-info';
3434

35+
import {
36+
REPS,
37+
MODE,
38+
} from 'devtools-reps'
39+
const { Rep } = REPS;
40+
41+
3542
import './CallNode.css';
3643
import classNames from 'classnames';
3744

@@ -129,6 +136,7 @@ type Props = {|
129136
+timings?: TimingsForPath,
130137
+callTreeSummaryStrategy: CallTreeSummaryStrategy,
131138
+displayStackType: boolean,
139+
+argumentValues?: Array<{...}>,
132140
|};
133141

134142
/**
@@ -358,6 +366,7 @@ export class TooltipCallNode extends React.PureComponent<Props> {
358366
thread,
359367
durationText,
360368
categories,
369+
argumentValues,
361370
displayData,
362371
timings,
363372
callTreeSummaryStrategy,
@@ -423,6 +432,25 @@ export class TooltipCallNode extends React.PureComponent<Props> {
423432
];
424433
}
425434

435+
let argumentsElement = null;
436+
if (argumentValues) {
437+
if (argumentValues.length == 0) {
438+
argumentsElement = <div className="arguments">No arguments.</div>;
439+
} else {
440+
let argumentValuesEl = [];
441+
for(const previewObject of argumentValues) {
442+
argumentValuesEl.push(Rep({
443+
object: previewObject,
444+
mode: MODE.LONG,
445+
}));
446+
}
447+
argumentsElement = <div className="arguments">
448+
<div className="argumentsLabel">Arguments</div>
449+
{argumentValuesEl}
450+
</div>;
451+
}
452+
}
453+
426454
// Finding current frame and parent frame URL(if there is).
427455
let pageAndParentPageURL;
428456
if (innerWindowIDToPageMap) {
@@ -539,6 +567,7 @@ export class TooltipCallNode extends React.PureComponent<Props> {
539567
{resource}
540568
</div>
541569
{this._renderCategoryTimings(timings)}
570+
{argumentsElement}
542571
</div>
543572
</div>
544573
);

src/components/tooltip/Tooltip.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,12 @@
145145
.sidebar .tooltipDetailSeparator {
146146
display: none;
147147
}
148+
149+
.argumentsLabel {
150+
/* match tooltips label, without being aligned to the right */
151+
color: var(--grey-50);
152+
}
153+
.arguments > span {
154+
display: block;
155+
border-bottom: 1px solid var(--grey-40);
156+
}

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import '../res/css/global.css';
1515
import '../res/css/categories.css';
1616
import '../res/css/network.css';
1717
import 'react-splitter-layout/lib/index.css';
18+
import 'devtools-reps/reps.css';
1819

1920
import React from 'react';
2021
import { createRoot } from 'react-dom/client';

src/profile-logic/process-profile.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,10 @@ function _processSamples(geckoSamples: GeckoSampleStruct): RawSamplesTable {
10271027
}
10281028
}
10291029

1030+
if (geckoSamples.argumentValues) {
1031+
samples.argumentValues = geckoSamples.argumentValues;
1032+
}
1033+
10301034
if (geckoSamples.eventDelay) {
10311035
samples.eventDelay = geckoSamples.eventDelay;
10321036
} else if (geckoSamples.responsiveness) {
@@ -1266,6 +1270,14 @@ function _processThread(
12661270
newThread.nativeAllocations = nativeAllocations;
12671271
}
12681272

1273+
if (thread.tracedValues) {
1274+
newThread.tracedValuesBuffer = thread.tracedValues;
1275+
}
1276+
1277+
if (thread.tracedObjectShapes) {
1278+
newThread.tracedObjectShapes = thread.tracedObjectShapes;
1279+
}
1280+
12691281
function processJsTracer() {
12701282
// Optionally extract the JS Tracer information, if they exist.
12711283
const { jsTracerEvents } = thread;

src/profile-logic/profile-data.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,13 @@ export function filterThreadSamplesToRange(
16401640
);
16411641
}
16421642

1643+
if (samples.argumentValues) {
1644+
newSamples.argumentValues = samples.argumentValues.slice(
1645+
beginSampleIndex,
1646+
endSampleIndex
1647+
);
1648+
}
1649+
16431650
if (samples.threadId) {
16441651
newSamples.threadId = samples.threadId.slice(
16451652
beginSampleIndex,
@@ -1766,6 +1773,13 @@ export function filterRawThreadSamplesToRange(
17661773
);
17671774
}
17681775

1776+
if (samples.argumentValues) {
1777+
newSamples.argumentValues = samples.argumentValues.slice(
1778+
beginSampleIndex,
1779+
endSampleIndex
1780+
);
1781+
}
1782+
17691783
if (samples.threadId) {
17701784
newSamples.threadId = samples.threadId.slice(
17711785
beginSampleIndex,
@@ -1872,6 +1886,9 @@ export function filterCounterSamplesToRange(
18721886
number: samples.number
18731887
? samples.number.slice(beginSampleIndex, endSampleIndex)
18741888
: undefined,
1889+
argumentValues: samples.argumentValues
1890+
? samples.argumentValues.slice(beginSampleIndex, endSampleIndex)
1891+
: undefined,
18751892
};
18761893

18771894
return newCounter;
@@ -2196,6 +2213,7 @@ export function computeSamplesTableFromRawSamplesTable(
21962213
const {
21972214
responsiveness,
21982215
eventDelay,
2216+
argumentValues,
21992217
stack,
22002218
weight,
22012219
weightType,
@@ -2222,6 +2240,7 @@ export function computeSamplesTableFromRawSamplesTable(
22222240
// These fields are copied from the raw samples table:
22232241
responsiveness,
22242242
eventDelay,
2243+
argumentValues,
22252244
stack,
22262245
weight,
22272246
weightType,
@@ -2241,7 +2260,8 @@ export function createThreadFromDerivedTables(
22412260
rawThread: RawThread,
22422261
samples: SamplesTable,
22432262
stackTable: StackTable,
2244-
stringTable: StringTable
2263+
stringTable: StringTable,
2264+
tracedValuesBuffer: ArrayBuffer | null,
22452265
): Thread {
22462266
const {
22472267
processType,
@@ -2268,6 +2288,7 @@ export function createThreadFromDerivedTables(
22682288
jsTracer,
22692289
isPrivateBrowsing,
22702290
userContextId,
2291+
tracedObjectShapes,
22712292
} = rawThread;
22722293

22732294
const thread: Thread = {
@@ -2296,11 +2317,13 @@ export function createThreadFromDerivedTables(
22962317
jsTracer,
22972318
isPrivateBrowsing,
22982319
userContextId,
2320+
tracedObjectShapes,
22992321

23002322
// These fields are derived:
23012323
samples,
23022324
stackTable,
23032325
stringTable,
2326+
tracedValuesBuffer: tracedValuesBuffer || undefined
23042327
};
23052328
return thread;
23062329
}

src/profile-logic/stack-timing.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export type StackTiming = {|
8888
sameWidthsStart: number[],
8989
sameWidthsEnd: number[],
9090
callNode: IndexIntoCallNodeTable[],
91+
argumentValues?: number[],
9192
length: number,
9293
|};
9394

@@ -114,14 +115,20 @@ export function getStackTimingByDepth(
114115
subtreeRangeEnd: callNodeTableSubtreeRangeEndColumn,
115116
depth: callNodeTableDepthColumn,
116117
} = callNodeTable;
117-
const stackTimingByDepth = Array.from({ length: maxDepthPlusOne }, () => ({
118-
start: [],
119-
end: [],
120-
sameWidthsStart: [],
121-
sameWidthsEnd: [],
122-
callNode: [],
123-
length: 0,
124-
}));
118+
const stackTimingByDepth = Array.from({ length: maxDepthPlusOne }, () => {
119+
const shape: StackTiming = {
120+
start: [],
121+
end: [],
122+
sameWidthsStart: [],
123+
sameWidthsEnd: [],
124+
callNode: [],
125+
length: 0,
126+
};
127+
if (samples.argumentValues) {
128+
shape.argumentValues = [];
129+
};
130+
return shape;
131+
});
125132

126133
const sameWidthsIndexToTimestampMap = [];
127134

@@ -152,6 +159,7 @@ export function getStackTimingByDepth(
152159
let deepestOpenBoxDepth = -1;
153160
const openBoxStartTimeByDepth = new Float64Array(maxDepthPlusOne);
154161
const openBoxStartTickByDepth = new Float64Array(maxDepthPlusOne);
162+
const openBoxArgsByDepth = new Int32Array(maxDepthPlusOne);
155163

156164
let currentStackTick = 0;
157165
for (let sampleIndex = 0; sampleIndex < samples.length; sampleIndex++) {
@@ -160,6 +168,11 @@ export function getStackTimingByDepth(
160168
continue;
161169
}
162170

171+
let sampleArgs : number = -1;
172+
if (samples.argumentValues) {
173+
sampleArgs = samples.argumentValues[sampleIndex] !== null ? samples.argumentValues[sampleIndex] : -1;
174+
}
175+
163176
const sampleTime = samples.time[sampleIndex];
164177

165178
// Phase 1: Commit open boxes which are not shared by the current call node,
@@ -191,6 +204,9 @@ export function getStackTimingByDepth(
191204
stackTimingForThisDepth.sameWidthsStart[index] = startStackTick;
192205
stackTimingForThisDepth.sameWidthsEnd[index] = currentStackTick;
193206
stackTimingForThisDepth.callNode[index] = deepestOpenBoxCallNodeIndex;
207+
if (stackTimingForThisDepth.argumentValues) {
208+
stackTimingForThisDepth.argumentValues[index] = openBoxArgsByDepth[deepestOpenBoxDepth];
209+
}
194210
deepestOpenBoxCallNodeIndex =
195211
callNodeTablePrefixColumn[deepestOpenBoxCallNodeIndex];
196212
deepestOpenBoxDepth--;
@@ -206,6 +222,9 @@ export function getStackTimingByDepth(
206222
deepestOpenBoxDepth++;
207223
openBoxStartTimeByDepth[deepestOpenBoxDepth] = sampleTime;
208224
openBoxStartTickByDepth[deepestOpenBoxDepth] = currentStackTick;
225+
if (samples.argumentValues) {
226+
openBoxArgsByDepth[deepestOpenBoxDepth] = sampleArgs;
227+
}
209228
}
210229
}
211230

@@ -227,6 +246,9 @@ export function getStackTimingByDepth(
227246
stackTimingForThisDepth.sameWidthsStart[index] = startStackTick;
228247
stackTimingForThisDepth.sameWidthsEnd[index] = currentStackTick;
229248
stackTimingForThisDepth.callNode[index] = deepestOpenBoxCallNodeIndex;
249+
if (stackTimingForThisDepth.argumentValues) {
250+
stackTimingForThisDepth.argumentValues[index] = openBoxArgsByDepth[deepestOpenBoxDepth];
251+
}
230252
deepestOpenBoxCallNodeIndex =
231253
callNodeTablePrefixColumn[deepestOpenBoxCallNodeIndex];
232254
deepestOpenBoxDepth--;

0 commit comments

Comments
 (0)