Skip to content

Commit 2d79656

Browse files
committed
When double-clicking a node, display the assembly code for the native symbol with the highest sample count.
1 parent a8f8a5d commit 2d79656

File tree

3 files changed

+67
-19
lines changed

3 files changed

+67
-19
lines changed

src/profile-logic/bottom-box.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
getCallNodeFramePerStack,
1717
getNativeSymbolInfo,
1818
getNativeSymbolsForCallNode,
19+
getNativeSymbolTimingsForCallNode,
1920
} from './profile-data';
2021
import { mapGetKeyWithMaxValue } from 'firefox-profiler/utils';
2122
import { getLineTimingsForCallNode } from './line-timings';
@@ -56,18 +57,34 @@ export function getBottomBoxInfoForCallNode(
5657
callNodeInfo,
5758
stackTable
5859
);
60+
61+
// If we have at least one native symbol to show assembly for, pick
62+
// the one with the highest total.
5963
const nativeSymbolsForCallNode = getNativeSymbolsForCallNode(
6064
callNodeFramePerStack,
6165
frameTable
6266
);
67+
let initialNativeSymbol = null;
68+
const nativeSymbolTimings = getNativeSymbolTimingsForCallNode(
69+
samples,
70+
callNodeFramePerStack,
71+
frameTable
72+
);
73+
const hottestNativeSymbol = mapGetKeyWithMaxValue(nativeSymbolTimings);
74+
if (hottestNativeSymbol !== undefined) {
75+
nativeSymbolsForCallNode.add(hottestNativeSymbol);
76+
initialNativeSymbol = hottestNativeSymbol;
77+
}
78+
const nativeSymbolsForCallNodeArr = [...nativeSymbolsForCallNode];
79+
nativeSymbolsForCallNodeArr.sort((a, b) => a - b);
80+
if (
81+
nativeSymbolsForCallNodeArr.length !== 0 &&
82+
initialNativeSymbol === null
83+
) {
84+
initialNativeSymbol = nativeSymbolsForCallNodeArr[0];
85+
}
6386

64-
// If we have at least one native symbol to show assembly for, pick
65-
// the first one arbitrarily.
66-
// TODO: If the we have more than one native symbol, pick the one
67-
// with the highest total sample count.
68-
const initialNativeSymbol = nativeSymbolsForCallNode.length !== 0 ? 0 : null;
69-
70-
const nativeSymbolInfosForCallNode = nativeSymbolsForCallNode.map(
87+
const nativeSymbolInfosForCallNode = nativeSymbolsForCallNodeArr.map(
7188
(nativeSymbolIndex) =>
7289
getNativeSymbolInfo(
7390
nativeSymbolIndex,
@@ -91,17 +108,18 @@ export function getBottomBoxInfoForCallNode(
91108
samples,
92109
callNodeFramePerStack,
93110
frameTable,
94-
initialNativeSymbol !== null
95-
? nativeSymbolsForCallNode[initialNativeSymbol]
96-
: null
111+
initialNativeSymbol
97112
);
98113
const hottestInstructionAddress = mapGetKeyWithMaxValue(addressTimings);
99114

100115
return {
101116
libIndex,
102117
sourceIndex,
103118
nativeSymbols: nativeSymbolInfosForCallNode,
104-
initialNativeSymbol,
119+
initialNativeSymbol:
120+
initialNativeSymbol !== null
121+
? nativeSymbolsForCallNodeArr.indexOf(initialNativeSymbol)
122+
: null,
105123
scrollToLineNumber: hottestLine,
106124
scrollToInstructionAddress: hottestInstructionAddress,
107125
};

src/profile-logic/profile-data.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4045,8 +4045,8 @@ export function calculateFunctionSizeLowerBound(
40454045
export function getNativeSymbolsForCallNode(
40464046
callNodeFramePerStack: Int32Array,
40474047
frameTable: FrameTable
4048-
): IndexIntoNativeSymbolTable[] {
4049-
const set: Set<IndexIntoNativeSymbolTable> = new Set();
4048+
): Set<IndexIntoNativeSymbolTable> {
4049+
const set = new Set<IndexIntoNativeSymbolTable>();
40504050
for (
40514051
let stackIndex = 0;
40524052
stackIndex < callNodeFramePerStack.length;
@@ -4060,7 +4060,39 @@ export function getNativeSymbolsForCallNode(
40604060
}
40614061
}
40624062
}
4063-
return [...set];
4063+
return set;
4064+
}
4065+
4066+
export function getNativeSymbolTimingsForCallNode(
4067+
samples: SamplesLikeTable,
4068+
callNodeFramePerStack: Int32Array,
4069+
frameTable: FrameTable
4070+
): Map<IndexIntoNativeSymbolTable, number> {
4071+
const totalPerNativeSymbol = new Map<Address, number>();
4072+
for (let sampleIndex = 0; sampleIndex < samples.length; sampleIndex++) {
4073+
const stack = samples.stack[sampleIndex];
4074+
if (stack === null) {
4075+
continue;
4076+
}
4077+
const callNodeFrame = callNodeFramePerStack[stack];
4078+
if (callNodeFrame === -1) {
4079+
// This sample does not contribute to the call node's total. Ignore.
4080+
continue;
4081+
}
4082+
4083+
const sampleWeight =
4084+
samples.weight !== null ? samples.weight[sampleIndex] : 1;
4085+
4086+
const nativeSymbol = frameTable.nativeSymbol[callNodeFrame];
4087+
if (nativeSymbol !== null) {
4088+
totalPerNativeSymbol.set(
4089+
nativeSymbol,
4090+
(totalPerNativeSymbol.get(nativeSymbol) ?? 0) + sampleWeight
4091+
);
4092+
}
4093+
}
4094+
4095+
return totalPerNativeSymbol;
40644096
}
40654097

40664098
/**

src/test/unit/profile-data.test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,7 @@ describe('getNativeSymbolsForCallNode', function () {
14811481
);
14821482
expect(
14831483
getNativeSymbolsForCallNode(callNodeFramePerStackAB, thread.frameTable)
1484-
).toEqual([symB]);
1484+
).toEqual(new Set([symB]));
14851485

14861486
const callNodeFramePerStackABC = getCallNodeFramePerStack(
14871487
ensureExists(abc),
@@ -1490,7 +1490,7 @@ describe('getNativeSymbolsForCallNode', function () {
14901490
);
14911491
expect(
14921492
getNativeSymbolsForCallNode(callNodeFramePerStackABC, thread.frameTable)
1493-
).toEqual([symB]);
1493+
).toEqual(new Set([symB]));
14941494
});
14951495

14961496
it('finds multiple symbols', function () {
@@ -1531,9 +1531,7 @@ describe('getNativeSymbolsForCallNode', function () {
15311531
thread.stackTable
15321532
);
15331533
expect(
1534-
new Set(
1535-
getNativeSymbolsForCallNode(callNodeFramePerStackC, thread.frameTable)
1536-
)
1534+
getNativeSymbolsForCallNode(callNodeFramePerStackC, thread.frameTable)
15371535
).toEqual(new Set([symB, symD]));
15381536
});
15391537
});

0 commit comments

Comments
 (0)