Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions locales/en-US/app.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,7 @@ StackSettings--panel-search =
## Tab Bar for the bottom half of the analysis UI.

TabBar--calltree-tab = Call Tree
TabBar--function-list-tab = Function List
TabBar--flame-graph-tab = Flame Graph
TabBar--stack-chart-tab = Stack Chart
TabBar--marker-chart-tab = Marker Chart
Expand Down
3 changes: 2 additions & 1 deletion res/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ body {
flex-shrink: 1;
}

.treeAndSidebarWrapper {
.treeAndSidebarWrapper,
.functionTableAndSidebarWrapper {
display: flex;
flex: 1;
flex-flow: column nowrap;
Expand Down
248 changes: 245 additions & 3 deletions src/actions/profile-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import type {
TableViewOptions,
SelectionContext,
BottomBoxInfo,
IndexIntoFuncTable,
} from 'firefox-profiler/types';
import {
funcHasDirectRecursiveCall,
Expand Down Expand Up @@ -120,7 +121,7 @@ export function changeSelectedCallNode(
const isInverted = getInvertCallstack(getState());
dispatch({
type: 'CHANGE_SELECTED_CALL_NODE',
isInverted,
area: isInverted ? 'INVERTED_TREE' : 'NON_INVERTED_TREE',
selectedCallNodePath,
optionalExpandedToCallNodePath,
threadsKey,
Expand All @@ -129,6 +130,52 @@ export function changeSelectedCallNode(
};
}

export function changeLowerWingSelectedCallNode(
threadsKey: ThreadsKey,
selectedCallNodePath: CallNodePath,
context: SelectionContext = { source: 'auto' }
): Action {
return {
type: 'CHANGE_SELECTED_CALL_NODE',
area: 'LOWER_WING',
selectedCallNodePath,
optionalExpandedToCallNodePath: [],
threadsKey,
context,
};
}

export function changeUpperWingSelectedCallNode(
threadsKey: ThreadsKey,
selectedCallNodePath: CallNodePath,
context: SelectionContext = { source: 'auto' }
): Action {
return {
type: 'CHANGE_SELECTED_CALL_NODE',
area: 'UPPER_WING',
selectedCallNodePath,
optionalExpandedToCallNodePath: [],
threadsKey,
context,
};
}

/**
* Select a function for a given thread in the function list.
*/
export function changeSelectedFunctionIndex(
threadsKey: ThreadsKey,
selectedFunctionIndex: IndexIntoFuncTable | null,
context: SelectionContext = { source: 'auto' }
): Action {
return {
type: 'CHANGE_SELECTED_FUNCTION',
selectedFunctionIndex,
threadsKey,
context,
};
}

/**
* This action is used when the user right clicks on a call node (in panels such
* as the call tree, the flame chart, or the stack chart). It's especially used
Expand All @@ -137,10 +184,49 @@ export function changeSelectedCallNode(
export function changeRightClickedCallNode(
threadsKey: ThreadsKey,
callNodePath: CallNodePath | null
): ThunkAction<void> {
return (dispatch, getState) => {
const isInverted = getInvertCallstack(getState());
dispatch({
type: 'CHANGE_RIGHT_CLICKED_CALL_NODE',
threadsKey,
area: isInverted ? 'INVERTED_TREE' : 'NON_INVERTED_TREE',
callNodePath,
});
};
}

export function changeRightClickedFunctionIndex(
threadsKey: ThreadsKey,
functionIndex: IndexIntoFuncTable | null
): Action {
return {
type: 'CHANGE_RIGHT_CLICKED_FUNCTION',
threadsKey,
functionIndex,
};
}

export function changeLowerWingRightClickedCallNode(
threadsKey: ThreadsKey,
callNodePath: CallNodePath | null
): Action {
return {
type: 'CHANGE_RIGHT_CLICKED_CALL_NODE',
threadsKey,
area: 'LOWER_WING',
callNodePath,
};
}

export function changeUpperWingRightClickedCallNode(
threadsKey: ThreadsKey,
callNodePath: CallNodePath | null
) {
return {
type: 'CHANGE_RIGHT_CLICKED_CALL_NODE',
threadsKey,
area: 'UPPER_WING',
callNodePath,
};
}
Expand Down Expand Up @@ -207,6 +293,40 @@ export function selectSelfCallNode(
};
}

/**
* Like selectSelfCallNode, but selects the function of the self call node
* instead. Used when the function list tab is active.
*/
export function selectSelfFunction(
threadsKey: ThreadsKey,
sampleIndex: IndexIntoSamplesTable | null
): ThunkAction<void> {
return (dispatch, getState) => {
if (sampleIndex === null || sampleIndex < 0) {
dispatch(changeSelectedFunctionIndex(threadsKey, null));
return;
}
const threadSelectors = getThreadSelectorsFromThreadsKey(threadsKey);
const sampleCallNodes =
threadSelectors.getSampleIndexToNonInvertedCallNodeIndexForFilteredThread(
getState()
);
if (sampleIndex >= sampleCallNodes.length) {
dispatch(changeSelectedFunctionIndex(threadsKey, null));
return;
}
const nonInvertedSelfCallNode = sampleCallNodes[sampleIndex];
if (nonInvertedSelfCallNode === null) {
dispatch(changeSelectedFunctionIndex(threadsKey, null));
return;
}
const callNodeInfo = threadSelectors.getCallNodeInfo(getState());
const funcIndex =
callNodeInfo.getCallNodeTable().func[nonInvertedSelfCallNode];
dispatch(changeSelectedFunctionIndex(threadsKey, funcIndex));
};
}

/**
* This selects a set of thread from thread indexes.
* Please use it in tests only.
Expand Down Expand Up @@ -1548,12 +1668,37 @@ export function changeExpandedCallNodes(
const isInverted = getInvertCallstack(getState());
dispatch({
type: 'CHANGE_EXPANDED_CALL_NODES',
isInverted,
area: isInverted ? 'INVERTED_TREE' : 'NON_INVERTED_TREE',
threadsKey,
expandedCallNodePaths,
});
};
}

export function changeLowerWingExpandedCallNodes(
threadsKey: ThreadsKey,
expandedCallNodePaths: Array<CallNodePath>
): Action {
return {
type: 'CHANGE_EXPANDED_CALL_NODES',
area: 'LOWER_WING',
threadsKey,
expandedCallNodePaths,
};
}

export function changeUpperWingExpandedCallNodes(
threadsKey: ThreadsKey,
expandedCallNodePaths: Array<CallNodePath>
): Action {
return {
type: 'CHANGE_EXPANDED_CALL_NODES',
area: 'UPPER_WING',
threadsKey,
expandedCallNodePaths,
};
}

export function changeSelectedMarker(
threadsKey: ThreadsKey,
selectedMarker: MarkerIndex | null,
Expand Down Expand Up @@ -1990,6 +2135,7 @@ export function closeBottomBox(): ThunkAction<void> {
export function handleCallNodeTransformShortcut(
event: React.KeyboardEvent<HTMLElement>,
threadsKey: ThreadsKey,
callNodeInfo: CallNodeInfo,
callNodeIndex: IndexIntoCallNodeTable
): ThunkAction<void> {
return (dispatch, getState) => {
Expand All @@ -1998,7 +2144,6 @@ export function handleCallNodeTransformShortcut(
}
const threadSelectors = getThreadSelectorsFromThreadsKey(threadsKey);
const unfilteredThread = threadSelectors.getThread(getState());
const callNodeInfo = threadSelectors.getCallNodeInfo(getState());
const implementation = getImplementationFilter(getState());
const inverted = getInvertCallstack(getState());
const callNodePath = callNodeInfo.getCallNodePathFromIndex(callNodeIndex);
Expand Down Expand Up @@ -2108,3 +2253,100 @@ export function handleCallNodeTransformShortcut(
}
};
}

export function handleFunctionTransformShortcut(
event: React.KeyboardEvent<HTMLElement>,
threadsKey: ThreadsKey,
funcIndex: IndexIntoFuncTable
): ThunkAction<void> {
return (dispatch, getState) => {
if (event.metaKey || event.ctrlKey || event.altKey) {
return;
}
const threadSelectors = getThreadSelectorsFromThreadsKey(threadsKey);
const callNodeInfo = threadSelectors.getCallNodeInfo(getState());
const implementation = getImplementationFilter(getState());
const callNodeTable = callNodeInfo.getCallNodeTable();
const unfilteredThread = threadSelectors.getThread(getState());

switch (event.key) {
case 'f':
dispatch(
addTransformToStack(threadsKey, {
type: 'focus-function',
funcIndex,
})
);
break;
case 'S':
dispatch(
addTransformToStack(threadsKey, {
type: 'focus-self',
funcIndex,
implementation,
})
);
break;
case 'm':
dispatch(
addTransformToStack(threadsKey, {
type: 'merge-function',
funcIndex,
})
);
break;
case 'd':
dispatch(
addTransformToStack(threadsKey, {
type: 'drop-function',
funcIndex,
})
);
break;
case 'C': {
const resourceIndex = unfilteredThread.funcTable.resource[funcIndex];
dispatch(
addCollapseResourceTransformToStack(
threadsKey,
resourceIndex,
implementation
)
);
break;
}
case 'r': {
if (funcHasRecursiveCall(callNodeTable, funcIndex)) {
dispatch(
addTransformToStack(threadsKey, {
type: 'collapse-recursion',
funcIndex,
})
);
}
break;
}
case 'R': {
if (funcHasDirectRecursiveCall(callNodeTable, funcIndex)) {
dispatch(
addTransformToStack(threadsKey, {
type: 'collapse-direct-recursion',
funcIndex,
implementation,
})
);
}
break;
}
case 'c':
dispatch(
addTransformToStack(threadsKey, {
type: 'collapse-function-subtree',
funcIndex,
})
);
break;
default:
// This did not match a function transform.
}
};
}
2 changes: 2 additions & 0 deletions src/app-logic/tabs-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
export const tabsWithTitleL10nId = {
calltree: 'TabBar--calltree-tab',
'function-list': 'TabBar--function-list-tab',
'flame-graph': 'TabBar--flame-graph-tab',
'stack-chart': 'TabBar--stack-chart-tab',
'marker-chart': 'TabBar--marker-chart-tab',
Expand Down Expand Up @@ -41,6 +42,7 @@ export const tabsWithTitleL10nIdArray: readonly TabsWithTitleL10nId[] =

export const tabsShowingSampleData: readonly TabSlug[] = [
'calltree',
'function-list',
'flame-graph',
'stack-chart',
];
1 change: 1 addition & 0 deletions src/app-logic/url-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ export function getQueryStringFromUrlState(urlState: UrlState): string {
: undefined;
/* fallsthrough */
case 'flame-graph':
case 'function-list':
case 'calltree': {
query = baseQuery as CallTreeQueryShape;

Expand Down
6 changes: 6 additions & 0 deletions src/components/app/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import explicitConnect from 'firefox-profiler/utils/connect';
import { TabBar } from './TabBar';
import { LocalizedErrorBoundary } from './ErrorBoundary';
import { ProfileCallTreeView } from 'firefox-profiler/components/calltree/ProfileCallTreeView';
import { ProfileFunctionListView } from 'firefox-profiler/components/calltree/ProfileFunctionListView';
import { MarkerTable } from 'firefox-profiler/components/marker-table';
import { StackChart } from 'firefox-profiler/components/stack-chart/';
import { MarkerChart } from 'firefox-profiler/components/marker-chart/';
Expand All @@ -26,6 +27,8 @@ import { getSelectedTab } from 'firefox-profiler/selectors/url-state';
import { getIsSidebarOpen } from 'firefox-profiler/selectors/app';
import { selectedThreadSelectors } from 'firefox-profiler/selectors/per-thread';
import { CallNodeContextMenu } from 'firefox-profiler/components/shared/CallNodeContextMenu';
import { FunctionListContextMenu } from 'firefox-profiler/components/shared/FunctionListContextMenu';
import { LowerWingContextMenu } from 'firefox-profiler/components/shared/LowerWingContextMenu';
import { MaybeMarkerContextMenu } from 'firefox-profiler/components/shared/MarkerContextMenu';
import { toValidTabSlug } from 'firefox-profiler/utils/types';

Expand Down Expand Up @@ -122,6 +125,7 @@ class ProfileViewerImpl extends PureComponent<Props> {
{
{
calltree: <ProfileCallTreeView />,
'function-list': <ProfileFunctionListView />,
'flame-graph': <FlameGraph />,
'stack-chart': <StackChart />,
'marker-chart': <MarkerChart />,
Expand All @@ -133,6 +137,8 @@ class ProfileViewerImpl extends PureComponent<Props> {
</LocalizedErrorBoundary>
</Localized>
<CallNodeContextMenu />
<FunctionListContextMenu />
<LowerWingContextMenu />
<MaybeMarkerContextMenu />
</div>
);
Expand Down
Loading
Loading