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
47 changes: 40 additions & 7 deletions src/actions/profile-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -1875,23 +1875,49 @@ export function changeTableViewOptions(
};
}

function _findIndexOfMaxValue(arr: number[]): number {
if (arr.length === 0) {
return -1;
}

let indexOfMaxValue = 0;
let maxValue = arr[0];
for (let i = 1; i < arr.length; i++) {
const val = arr[i];
if (val > maxValue) {
indexOfMaxValue = i;
maxValue = val;
}
}
return indexOfMaxValue;
}

export function updateBottomBoxContentsAndMaybeOpen(
currentTab: TabSlug,
{ libIndex, sourceFile, nativeSymbols }: BottomBoxInfo
bottomBoxInfo: BottomBoxInfo
): Action {
// TODO: If the set has more than one element, pick the native symbol with
// the highest total sample count
const nativeSymbol = nativeSymbols.length !== 0 ? nativeSymbols[0] : null;
const {
libIndex,
sourceFile,
nativeSymbols,
nativeSymbolWeightsAtOpeningTime,
} = bottomBoxInfo;
const haveSourceFile = sourceFile !== null;
const haveNativeSymbol = nativeSymbols.length !== 0;

return {
type: 'UPDATE_BOTTOM_BOX',
libIndex,
sourceFile,
nativeSymbol,
initialNativeSymbolEntryIndex: haveNativeSymbol
? _findIndexOfMaxValue(nativeSymbolWeightsAtOpeningTime)
: null,
allNativeSymbolsForInitiatingCallNode: nativeSymbols,
allNativeSymbolWeightsForInitiatingCallNode:
nativeSymbolWeightsAtOpeningTime,
currentTab,
shouldOpenBottomBox: sourceFile !== null || nativeSymbol !== null,
shouldOpenAssemblyView: sourceFile === null && nativeSymbol !== null,
shouldOpenBottomBox: haveSourceFile || haveNativeSymbol,
shouldOpenAssemblyView: !haveSourceFile && haveNativeSymbol,
};
}

Expand All @@ -1901,6 +1927,13 @@ export function openAssemblyView(): Action {
};
}

export function changeAssemblyViewNativeSymbolEntryIndex(entryIndex: number): Action {
return {
type: 'CHANGE_ASSEMBLY_VIEW_NATIVE_SYMBOL_ENTRY_INDEX',
entryIndex,
}
}

export function closeAssemblyView(): Action {
return {
type: 'CLOSE_ASSEMBLY_VIEW',
Expand Down
16 changes: 12 additions & 4 deletions src/app-logic/url-handling.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,9 +343,16 @@ export function getQueryStringFromUrlState(urlState: UrlState): string {
if (sourceView.sourceFile !== null) {
query.sourceView = sourceView.sourceFile;
}
if (assemblyView.isOpen && assemblyView.nativeSymbol !== null) {
if (
assemblyView.isOpen &&
assemblyView.currentNativeSymbolEntryIndex !== null
) {
const {
currentNativeSymbolEntryIndex,
allNativeSymbolsForInitiatingCallNode,
} = assemblyView;
query.assemblyView = stringifyAssemblyViewSymbol(
assemblyView.nativeSymbol
allNativeSymbolsForInitiatingCallNode[currentNativeSymbolEntryIndex]
);
}
}
Expand Down Expand Up @@ -504,8 +511,9 @@ export function stateFromLocation(
const assemblyView: AssemblyViewState = {
isOpen: false,
scrollGeneration: 0,
nativeSymbol: null,
currentNativeSymbolEntryIndex: null,
allNativeSymbolsForInitiatingCallNode: [],
allNativeSymbolWeightsForInitiatingCallNode: [],
};
const isBottomBoxOpenPerPanel = {};
tabSlugs.forEach((tabSlug) => (isBottomBoxOpenPerPanel[tabSlug] = false));
Expand All @@ -516,7 +524,7 @@ export function stateFromLocation(
if (query.assemblyView) {
const symbol = parseAssemblyViewSymbol(query.assemblyView);
if (symbol !== null) {
assemblyView.nativeSymbol = symbol;
assemblyView.currentNativeSymbolEntryIndex = 0;
assemblyView.allNativeSymbolsForInitiatingCallNode = [symbol];
assemblyView.isOpen = true;
isBottomBoxOpenPerPanel[selectedTab] = true;
Expand Down
117 changes: 117 additions & 0 deletions src/components/app/AssemblyViewNativeSymbolNavigator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// @flow

import React from 'react';
import classNames from 'classnames';

import {
getAssemblyViewCurrentNativeSymbolEntryIndex,
getAssemblyViewNativeSymbolEntryCount,
} from 'firefox-profiler/selectors/url-state';
import { changeAssemblyViewNativeSymbolEntryIndex } from 'firefox-profiler/actions/profile-view';
import explicitConnect from 'firefox-profiler/utils/connect';

import type { ConnectedProps } from 'firefox-profiler/utils/connect';

import { Localized } from '@fluent/react';

type StateProps = {|
+assemblyViewCurrentNativeSymbolEntryIndex: number | null,
+assemblyViewNativeSymbolEntryCount: number,
|};

type DispatchProps = {|
+changeAssemblyViewNativeSymbolEntryIndex: typeof changeAssemblyViewNativeSymbolEntryIndex,
|};

type Props = ConnectedProps<{||}, StateProps, DispatchProps>;

class AssemblyViewNativeSymbolNavigatorImpl extends React.PureComponent<Props> {
_onPreviousClick = () => {
this._changeIndexBy(-1);
};

_onNextClick = () => {
this._changeIndexBy(1);
};

_changeIndexBy(delta: number) {
const {
assemblyViewCurrentNativeSymbolEntryIndex: index,
assemblyViewNativeSymbolEntryCount: count,
changeAssemblyViewNativeSymbolEntryIndex,
} = this.props;
const newIndex = index + delta;
if (newIndex >= 0 && newIndex < count) {
changeAssemblyViewNativeSymbolEntryIndex(newIndex);
}
}

render() {
const {
assemblyViewCurrentNativeSymbolEntryIndex: index,
assemblyViewNativeSymbolEntryCount: count,
} = this.props;

if (index === null || count <= 1) {
return null;
}

return (
<>
<h3 className="bottom-box-title-trailer">
{index !== null && count > 1 ? `${index + 1} of ${count}` : ''}
</h3>
<Localized id="AssemblyView--prev-button" attrs={{ title: true }}>
<button
className={classNames(
'bottom-prev-button',
'photon-button',
'photon-button-ghost'
)}
title="Previous"
type="button"
disabled={index === null || index <= 0}
onClick={this._onPreviousClick}
>
</button>
</Localized>
<Localized id="AssemblyView--next-button" attrs={{ title: true }}>
<button
className={classNames(
'bottom-next-button',
'photon-button',
'photon-button-ghost'
)}
title="Next"
type="button"
disabled={index === null || index >= count - 1}
onClick={this._onNextClick}
>
</button>
</Localized>
</>
);
}
}

export const AssemblyViewNativeSymbolNavigator = explicitConnect<
{||},
StateProps,
DispatchProps,
>({
mapStateToProps: (state) => ({
assemblyViewCurrentNativeSymbolEntryIndex:
getAssemblyViewCurrentNativeSymbolEntryIndex(state),
assemblyViewNativeSymbolEntryCount:
getAssemblyViewNativeSymbolEntryCount(state),
}),
mapDispatchToProps: {
changeAssemblyViewNativeSymbolEntryIndex,
},
component: AssemblyViewNativeSymbolNavigatorImpl,
});
20 changes: 18 additions & 2 deletions src/components/app/BottomBox.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,18 @@
line-height: 18px;
}

.bottom-box-title {
.bottom-box-title, .bottom-box-title-trailer {
overflow: hidden;
margin: 0 8px;
font: inherit;
text-overflow: ellipsis;
white-space: nowrap;
}

.bottom-box-title-trailer {
margin: 0;
}

.bottom-box-header-trailing-buttons {
display: flex;
height: 100%;
Expand All @@ -62,7 +66,9 @@
}

.bottom-close-button,
.bottom-assembly-button {
.bottom-assembly-button,
.bottom-prev-button,
.bottom-next-button {
width: 24px;
height: 24px;
flex-shrink: 0;
Expand All @@ -71,6 +77,16 @@
background-size: 16px 16px;
}

.bottom-prev-button,
.bottom-next-button {
font-size: 9px;
width: 16px;
}

.bottom-next-button {
margin-right: 8px;
}

.bottom-close-button {
background-image: url(/res/img/svg/close-dark.svg);
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/app/BottomBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import classNames from 'classnames';
import { SourceView } from '../shared/SourceView';
import { AssemblyView } from '../shared/AssemblyView';
import { AssemblyViewToggleButton } from './AssemblyViewToggleButton';
import { AssemblyViewNativeSymbolNavigator } from './AssemblyViewNativeSymbolNavigator';
import { CodeLoadingOverlay } from './CodeLoadingOverlay';
import { CodeErrorOverlay } from './CodeErrorOverlay';
import {
Expand Down Expand Up @@ -187,6 +188,7 @@ class BottomBoxImpl extends React.PureComponent<Props> {
// These trailing header buttons go into the bottom-box-bar of the last pane.
const trailingHeaderButtons = (
<div className="bottom-box-header-trailing-buttons">
{assemblyViewIsOpen ? <AssemblyViewNativeSymbolNavigator /> : null}
<AssemblyViewToggleButton />
<Localized id="SourceView--close-button" attrs={{ title: true }}>
<button
Expand Down
16 changes: 14 additions & 2 deletions src/components/shared/CallNodeContextMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import type {
CategoryList,
InnerWindowID,
Page,
SamplesLikeTable,
} from 'firefox-profiler/types';

import type { TabSlug } from 'firefox-profiler/app-logic/tabs-handling';
Expand All @@ -69,6 +70,7 @@ import type { BrowserConnectionStatus } from 'firefox-profiler/app-logic/browser
type StateProps = {|
+thread: Thread | null,
+threadsKey: ThreadsKey | null,
+previewFilteredCtssSamples: SamplesLikeTable | null,
+categories: CategoryList,
+callNodeInfo: CallNodeInfo | null,
+rightClickedCallNodePath: CallNodePath | null,
Expand Down Expand Up @@ -224,11 +226,13 @@ class CallNodeContextMenuImpl extends React.PureComponent<Props> {
);
}

const { callNodeIndex, thread, callNodeInfo } = rightClickedCallNodeInfo;
const { callNodeIndex, thread, callNodeInfo, previewFilteredCtssSamples } =
rightClickedCallNodeInfo;
const bottomBoxInfo = getBottomBoxInfoForCallNode(
callNodeIndex,
callNodeInfo,
thread
thread,
previewFilteredCtssSamples
);
updateBottomBoxContentsAndMaybeOpen(selectedTab, bottomBoxInfo);
}
Expand Down Expand Up @@ -524,13 +528,15 @@ class CallNodeContextMenuImpl extends React.PureComponent<Props> {
getRightClickedCallNodeInfo(): null | {|
+thread: Thread,
+threadsKey: ThreadsKey,
+previewFilteredCtssSamples: SamplesLikeTable,
+callNodeInfo: CallNodeInfo,
+callNodePath: CallNodePath,
+callNodeIndex: IndexIntoCallNodeTable,
|} {
const {
thread,
threadsKey,
previewFilteredCtssSamples,
callNodeInfo,
rightClickedCallNodePath,
rightClickedCallNodeIndex,
Expand All @@ -539,13 +545,15 @@ class CallNodeContextMenuImpl extends React.PureComponent<Props> {
if (
thread &&
threadsKey !== null &&
previewFilteredCtssSamples !== null &&
callNodeInfo &&
rightClickedCallNodePath &&
typeof rightClickedCallNodeIndex === 'number'
) {
return {
thread,
threadsKey,
previewFilteredCtssSamples,
callNodeInfo,
callNodePath: rightClickedCallNodePath,
callNodeIndex: rightClickedCallNodeIndex,
Expand Down Expand Up @@ -882,6 +890,7 @@ export const CallNodeContextMenu = explicitConnect<

let thread = null;
let threadsKey = null;
let previewFilteredCtssSamples = null;
let callNodeInfo = null;
let rightClickedCallNodePath = null;
let rightClickedCallNodeIndex = null;
Expand All @@ -893,6 +902,8 @@ export const CallNodeContextMenu = explicitConnect<

thread = selectors.getFilteredThread(state);
threadsKey = rightClickedCallNodeInfo.threadsKey;
previewFilteredCtssSamples =
selectors.getPreviewFilteredCtssSamples(state);
callNodeInfo = selectors.getCallNodeInfo(state);
rightClickedCallNodePath = rightClickedCallNodeInfo.callNodePath;
rightClickedCallNodeIndex = selectors.getRightClickedCallNodeIndex(state);
Expand All @@ -901,6 +912,7 @@ export const CallNodeContextMenu = explicitConnect<
return {
thread,
threadsKey,
previewFilteredCtssSamples,
categories: getCategories(state),
callNodeInfo,
rightClickedCallNodePath,
Expand Down
3 changes: 2 additions & 1 deletion src/components/stack-chart/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ class StackChartImpl extends React.PureComponent<Props> {
const bottomBoxInfo = getBottomBoxInfoForCallNode(
nodeIndex,
callNodeInfo,
thread
thread,
thread.samples
);
updateBottomBoxContentsAndMaybeOpen('stack-chart', bottomBoxInfo);
return;
Expand Down
Loading