Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Deploy preview] Inline callstacks demo #2556

Closed
wants to merge 13 commits into from
Closed
83 changes: 83 additions & 0 deletions res/img/svg/inlined-icon.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 40 additions & 6 deletions src/actions/receive-profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { SymbolStore } from 'firefox-profiler/profile-logic/symbol-store';
import {
symbolicateProfile,
applySymbolicationStep,
StackMapper,
} from 'firefox-profiler/profile-logic/symbolication';
import * as MozillaSymbolicationAPI from 'firefox-profiler/profile-logic/mozilla-symbolication-api';
import { mergeProfilesForDiffing } from 'firefox-profiler/profile-logic/merge-compare';
Expand Down Expand Up @@ -718,27 +719,29 @@ export function bulkProcessSymbolicationSteps(
): ThunkAction<void> {
return (dispatch, getState) => {
const { threads } = getProfile(getState());
const oldFuncToNewFuncMaps = new Map();
const oldFuncToNewFuncsMaps = new Map();
const symbolicatedThreads = threads.map((oldThread, threadIndex) => {
const symbolicationSteps = symbolicationStepsPerThread.get(threadIndex);
if (symbolicationSteps === undefined) {
return oldThread;
}
const oldFuncToNewFuncMap = new Map();
const oldFuncToNewFuncsMap = new Map();
let thread = oldThread;
const stackMapper = new StackMapper();
for (const symbolicationStep of symbolicationSteps) {
thread = applySymbolicationStep(
thread,
symbolicationStep,
oldFuncToNewFuncMap
oldFuncToNewFuncsMap,
stackMapper
);
}
oldFuncToNewFuncMaps.set(threadIndex, oldFuncToNewFuncMap);
return thread;
oldFuncToNewFuncsMaps.set(threadIndex, oldFuncToNewFuncsMap);
return stackMapper.applyToThread(thread);
});
dispatch({
type: 'BULK_SYMBOLICATION',
oldFuncToNewFuncMaps,
oldFuncToNewFuncsMaps,
symbolicatedThreads,
});
};
Expand Down Expand Up @@ -874,6 +877,37 @@ function getSymbolStore(
}
});
},
requestSymbolsFromAPI: requests => {
if (!geckoProfiler) {
throw new Error("There's no connection to the gecko profiler add-on.");
}
if (!geckoProfiler.queryAPI) {
throw new Error('queryAPI endpoint not available');
}
for (const { lib } of requests) {
dispatch(requestingSymbolTable(lib));
}
async function queryAPI(url, json) {
if (!geckoProfiler || !geckoProfiler.queryAPI) {
throw new Error('queryAPI endpoint not available');
}
return JSON.parse(await geckoProfiler.queryAPI(url, json));
}
return MozillaSymbolicationAPI.requestSymbols(
requests,
symbolServerUrl,
queryAPI
).map(async (libPromise, i) => {
try {
const result = libPromise;
dispatch(receivedSymbolTableReply(requests[i].lib));
return result;
} catch (error) {
dispatch(receivedSymbolTableReply(requests[i].lib));
throw error;
}
});
},
requestSymbolTableFromAddon: async lib => {
if (!geckoProfiler) {
throw new Error("There's no connection to the gecko profiler add-on.");
Expand Down
2 changes: 1 addition & 1 deletion src/app-logic/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { MarkerPhase } from 'firefox-profiler/types';
export const GECKO_PROFILE_VERSION = 23;

// The current version of the "processed" profile format.
export const PROCESSED_PROFILE_VERSION = 35;
export const PROCESSED_PROFILE_VERSION = 36;

// The following are the margin sizes for the left and right of the timeline. Independent
// components need to share these values.
Expand Down
14 changes: 14 additions & 0 deletions src/components/shared/TreeView.css
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@
text-align: left;
}

.treeBadge {
display: inline-block;
color: transparent;
overflow: hidden;
width: 12px;
height: 12px;
vertical-align: -2px;
margin-right: 2px;
}

.treeBadge.inlined, .treeBadge.divergent-inlining {
background: url(../../../res/img/svg/inlined-icon.svg)
}

.treeRowIndentSpacer {
flex-shrink: 0;
}
Expand Down
8 changes: 8 additions & 0 deletions src/components/shared/TreeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ class TreeViewRowScrolledColumns<
title={displayData.categoryName}
/>
) : null}
{displayData.badge.type === 'badge' ? (
<span
className={`treeBadge ${displayData.badge.name}`}
title={displayData.badge.title}
>
{displayData.badge.alt}
</span>
) : null}
<span
className={classNames(
'treeViewRowColumn',
Expand Down
41 changes: 38 additions & 3 deletions src/profile-logic/call-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
Thread,
FuncTable,
ResourceTable,
NativeSymbolTable,
IndexIntoFuncTable,
SamplesLikeTable,
WeightType,
Expand All @@ -28,13 +29,13 @@ import type {
Milliseconds,
TracedTiming,
SamplesTable,
ExtraBadgeInfo,
} from 'firefox-profiler/types';

import type { CallTreeSummaryStrategy } from '../types/actions';
import ExtensionIcon from '../../res/img/svg/extension.svg';
import { formatCallNodeNumber, formatPercent } from '../utils/format-numbers';
import { assertExhaustiveCheck, ensureExists } from '../utils/flow';
import * as ProfileData from './profile-data';
import type { CallTreeSummaryStrategy } from '../types/actions';

type CallNodeChildren = IndexIntoCallNodeTable[];
type CallNodeSummary = {
Expand Down Expand Up @@ -72,6 +73,7 @@ export class CallTree {
_callNodeChildCount: Uint32Array; // A table column matching the callNodeTable
_funcTable: FuncTable;
_resourceTable: ResourceTable;
_nativeSymbols: NativeSymbolTable;
_stringTable: UniqueStringArray;
_rootTotalSummary: number;
_rootCount: number;
Expand All @@ -85,7 +87,7 @@ export class CallTree {
_weightType: WeightType;

constructor(
{ funcTable, resourceTable, stringTable }: Thread,
{ funcTable, resourceTable, nativeSymbols, stringTable }: Thread,
categories: CategoryList,
callNodeTable: CallNodeTable,
callNodeSummary: CallNodeSummary,
Expand All @@ -103,6 +105,7 @@ export class CallTree {
this._callNodeChildCount = callNodeChildCount;
this._funcTable = funcTable;
this._resourceTable = resourceTable;
this._nativeSymbols = nativeSymbols;
this._stringTable = stringTable;
this._rootTotalSummary = rootTotalSummary;
this._rootCount = rootCount;
Expand Down Expand Up @@ -210,6 +213,36 @@ export class CallTree {
};
}

_getInliningBadge(
callNodeIndex: IndexIntoCallNodeTable,
funcName: string
): ExtraBadgeInfo {
const inlinedIntoNativeSymbol = this._callNodeTable
.sourceFramesInlinedIntoSymbol[callNodeIndex];
if (inlinedIntoNativeSymbol === null) {
return { type: 'none' };
}

if (inlinedIntoNativeSymbol === -1) {
return {
type: 'badge',
name: 'divergent-inlining',
alt: '',
title: `Some calls to ${funcName} were inlined by the compiler.`,
};
}

const symbolName = this._stringTable.getString(
this._nativeSymbols.name[inlinedIntoNativeSymbol]
);
return {
type: 'badge',
name: 'inlined',
alt: '(inlined)',
title: `Calls to ${funcName} were inlined into ${symbolName} by the compiler.`,
};
}

getDisplayData(callNodeIndex: IndexIntoCallNodeTable): CallNodeDisplayData {
let displayData: CallNodeDisplayData | void = this._displayDataByIndex.get(
callNodeIndex
Expand All @@ -221,6 +254,7 @@ export class CallTree {
const funcIndex = this._callNodeTable.func[callNodeIndex];
const categoryIndex = this._callNodeTable.category[callNodeIndex];
const subcategoryIndex = this._callNodeTable.subcategory[callNodeIndex];
const badge = this._getInliningBadge(callNodeIndex, funcName);
const resourceIndex = this._funcTable.resource[funcIndex];
const resourceType = this._resourceTable.type[resourceIndex];
const isFrameLabel = resourceIndex === -1;
Expand Down Expand Up @@ -307,6 +341,7 @@ export class CallTree {
lib: libName.slice(0, 1000),
// Dim platform pseudo-stacks.
isFrameLabel,
badge,
categoryName: getCategoryPairLabel(
this._categories,
categoryIndex,
Expand Down