2019-08-28 01:54:01 +08:00
|
|
|
/**
|
|
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
|
*
|
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
|
*
|
|
|
|
|
* @flow
|
|
|
|
|
*/
|
2019-02-13 09:41:39 +08:00
|
|
|
|
2020-02-22 11:45:20 +08:00
|
|
|
import * as React from 'react';
|
|
|
|
|
import {Fragment, useContext} from 'react';
|
2019-08-14 08:58:03 +08:00
|
|
|
import {ModalDialog} from '../ModalDialog';
|
|
|
|
|
import {ProfilerContext} from './ProfilerContext';
|
2019-03-11 00:01:05 +08:00
|
|
|
import TabBar from '../TabBar';
|
2019-03-31 00:01:52 +08:00
|
|
|
import ClearProfilingDataButton from './ClearProfilingDataButton';
|
2019-03-16 11:05:52 +08:00
|
|
|
import CommitFlamegraph from './CommitFlamegraph';
|
|
|
|
|
import CommitRanked from './CommitRanked';
|
2019-05-22 21:40:04 +08:00
|
|
|
import RootSelector from './RootSelector';
|
2021-11-04 23:40:45 +08:00
|
|
|
import {Timeline} from 'react-devtools-timeline/src/Timeline';
|
2019-03-11 00:01:05 +08:00
|
|
|
import RecordToggle from './RecordToggle';
|
2019-03-21 02:12:46 +08:00
|
|
|
import ReloadAndProfileButton from './ReloadAndProfileButton';
|
2019-04-01 08:02:30 +08:00
|
|
|
import ProfilingImportExportButtons from './ProfilingImportExportButtons';
|
2019-03-11 10:16:34 +08:00
|
|
|
import SnapshotSelector from './SnapshotSelector';
|
2019-03-20 03:41:49 +08:00
|
|
|
import SidebarCommitInfo from './SidebarCommitInfo';
|
2019-04-07 23:36:37 +08:00
|
|
|
import SidebarSelectedFiberInfo from './SidebarSelectedFiberInfo';
|
2019-08-14 06:59:43 +08:00
|
|
|
import SettingsModal from 'react-devtools-shared/src/devtools/views/Settings/SettingsModal';
|
|
|
|
|
import SettingsModalContextToggle from 'react-devtools-shared/src/devtools/views/Settings/SettingsModalContextToggle';
|
2019-08-14 08:58:03 +08:00
|
|
|
import {SettingsModalContextController} from 'react-devtools-shared/src/devtools/views/Settings/SettingsModalContext';
|
2019-04-12 08:19:03 +08:00
|
|
|
import portaledContent from '../portaledContent';
|
2021-07-23 01:58:57 +08:00
|
|
|
import {StoreContext} from '../context';
|
2021-12-04 05:23:48 +08:00
|
|
|
import {TimelineContext} from 'react-devtools-timeline/src/TimelineContext';
|
2019-02-13 09:41:39 +08:00
|
|
|
|
|
|
|
|
import styles from './Profiler.css';
|
|
|
|
|
|
2019-05-23 23:48:51 +08:00
|
|
|
function Profiler(_: {||}) {
|
2019-05-22 21:40:04 +08:00
|
|
|
const {
|
2019-05-23 23:36:34 +08:00
|
|
|
didRecordCommits,
|
2019-05-22 21:40:04 +08:00
|
|
|
isProcessingData,
|
|
|
|
|
isProfiling,
|
2019-08-18 23:34:40 +08:00
|
|
|
selectedCommitIndex,
|
2019-05-22 21:40:04 +08:00
|
|
|
selectedFiberID,
|
|
|
|
|
selectedTabID,
|
|
|
|
|
selectTab,
|
2019-05-23 23:48:51 +08:00
|
|
|
supportsProfiling,
|
2019-05-22 21:40:04 +08:00
|
|
|
} = useContext(ProfilerContext);
|
2019-03-16 01:26:21 +08:00
|
|
|
|
2021-12-04 05:23:48 +08:00
|
|
|
const {searchInputContainerRef} = useContext(TimelineContext);
|
|
|
|
|
|
2021-11-04 23:40:45 +08:00
|
|
|
const {supportsTimeline} = useContext(StoreContext);
|
2021-07-23 01:58:57 +08:00
|
|
|
|
2021-12-04 05:23:48 +08:00
|
|
|
const isLegacyProfilerSelected = selectedTabID !== 'timeline';
|
2021-07-23 01:58:57 +08:00
|
|
|
|
2019-03-16 11:05:52 +08:00
|
|
|
let view = null;
|
2021-11-04 03:10:29 +08:00
|
|
|
if (didRecordCommits || selectedTabID === 'timeline') {
|
2019-05-22 21:40:04 +08:00
|
|
|
switch (selectedTabID) {
|
|
|
|
|
case 'flame-chart':
|
|
|
|
|
view = <CommitFlamegraph />;
|
|
|
|
|
break;
|
|
|
|
|
case 'ranked-chart':
|
|
|
|
|
view = <CommitRanked />;
|
|
|
|
|
break;
|
2021-11-04 03:10:29 +08:00
|
|
|
case 'timeline':
|
2021-11-04 23:40:45 +08:00
|
|
|
view = <Timeline />;
|
2021-07-23 01:58:57 +08:00
|
|
|
break;
|
2019-05-22 21:40:04 +08:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-05-23 11:00:21 +08:00
|
|
|
} else if (isProfiling) {
|
|
|
|
|
view = <RecordingInProgress />;
|
|
|
|
|
} else if (isProcessingData) {
|
|
|
|
|
view = <ProcessingData />;
|
|
|
|
|
} else if (supportsProfiling) {
|
|
|
|
|
view = <NoProfilingData />;
|
|
|
|
|
} else {
|
|
|
|
|
view = <ProfilingNotSupported />;
|
2019-03-16 11:05:52 +08:00
|
|
|
}
|
2019-03-11 00:01:05 +08:00
|
|
|
|
2019-03-20 03:41:49 +08:00
|
|
|
let sidebar = null;
|
2019-05-23 23:36:34 +08:00
|
|
|
if (!isProfiling && !isProcessingData && didRecordCommits) {
|
2019-05-23 00:04:55 +08:00
|
|
|
switch (selectedTabID) {
|
|
|
|
|
case 'flame-chart':
|
|
|
|
|
case 'ranked-chart':
|
2019-08-18 23:34:40 +08:00
|
|
|
// TRICKY
|
|
|
|
|
// Handle edge case where no commit is selected because of a min-duration filter update.
|
|
|
|
|
// In that case, the selected commit index would be null.
|
|
|
|
|
// We could still show a sidebar for the previously selected fiber,
|
|
|
|
|
// but it would be an odd user experience.
|
|
|
|
|
// TODO (ProfilerContext) This check should not be necessary.
|
|
|
|
|
if (selectedCommitIndex !== null) {
|
|
|
|
|
if (selectedFiberID !== null) {
|
|
|
|
|
sidebar = <SidebarSelectedFiberInfo />;
|
|
|
|
|
} else {
|
|
|
|
|
sidebar = <SidebarCommitInfo />;
|
|
|
|
|
}
|
2019-05-23 00:04:55 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-03-20 03:41:49 +08:00
|
|
|
}
|
|
|
|
|
|
2019-03-11 00:01:05 +08:00
|
|
|
return (
|
2019-06-11 05:57:26 +08:00
|
|
|
<SettingsModalContextController>
|
2019-05-22 21:40:04 +08:00
|
|
|
<div className={styles.Profiler}>
|
|
|
|
|
<div className={styles.LeftColumn}>
|
|
|
|
|
<div className={styles.Toolbar}>
|
2021-08-04 01:03:29 +08:00
|
|
|
<RecordToggle
|
2021-11-04 03:10:29 +08:00
|
|
|
disabled={!supportsProfiling || selectedTabID === 'timeline'}
|
2021-08-04 01:03:29 +08:00
|
|
|
/>
|
|
|
|
|
<ReloadAndProfileButton
|
2021-11-04 03:10:29 +08:00
|
|
|
disabled={selectedTabID === 'timeline' || !supportsProfiling}
|
2021-08-04 01:03:29 +08:00
|
|
|
/>
|
2019-05-22 21:40:04 +08:00
|
|
|
<ClearProfilingDataButton />
|
|
|
|
|
<ProfilingImportExportButtons />
|
|
|
|
|
<div className={styles.VRule} />
|
|
|
|
|
<TabBar
|
|
|
|
|
currentTab={selectedTabID}
|
|
|
|
|
id="Profiler"
|
|
|
|
|
selectTab={selectTab}
|
2021-11-04 23:40:45 +08:00
|
|
|
tabs={supportsTimeline ? tabsWithTimeline : tabs}
|
2019-07-25 02:25:11 +08:00
|
|
|
type="profiler"
|
2019-05-22 21:40:04 +08:00
|
|
|
/>
|
|
|
|
|
<RootSelector />
|
|
|
|
|
<div className={styles.Spacer} />
|
2021-12-04 05:23:48 +08:00
|
|
|
{!isLegacyProfilerSelected && (
|
|
|
|
|
<div
|
|
|
|
|
ref={searchInputContainerRef}
|
2022-01-04 23:30:07 +08:00
|
|
|
className={styles.TimelineSearchInputContainer}
|
2021-12-04 05:23:48 +08:00
|
|
|
/>
|
|
|
|
|
)}
|
2019-06-11 05:57:26 +08:00
|
|
|
<SettingsModalContextToggle />
|
2021-08-02 21:23:48 +08:00
|
|
|
{isLegacyProfilerSelected && didRecordCommits && (
|
2019-06-11 02:14:27 +08:00
|
|
|
<Fragment>
|
|
|
|
|
<div className={styles.VRule} />
|
|
|
|
|
<SnapshotSelector />
|
|
|
|
|
</Fragment>
|
|
|
|
|
)}
|
2019-05-22 21:40:04 +08:00
|
|
|
</div>
|
|
|
|
|
<div className={styles.Content}>
|
|
|
|
|
{view}
|
|
|
|
|
<ModalDialog />
|
|
|
|
|
</div>
|
2019-03-12 00:50:20 +08:00
|
|
|
</div>
|
2021-08-02 21:23:48 +08:00
|
|
|
{isLegacyProfilerSelected && (
|
|
|
|
|
<div className={styles.RightColumn}>{sidebar}</div>
|
|
|
|
|
)}
|
2019-06-11 06:03:05 +08:00
|
|
|
<SettingsModal />
|
2019-03-11 01:13:20 +08:00
|
|
|
</div>
|
2019-06-11 05:57:26 +08:00
|
|
|
</SettingsModalContextController>
|
2019-03-11 00:01:05 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const tabs = [
|
2019-03-11 10:16:34 +08:00
|
|
|
{
|
|
|
|
|
id: 'flame-chart',
|
|
|
|
|
icon: 'flame-chart',
|
|
|
|
|
label: 'Flamegraph',
|
|
|
|
|
title: 'Flamegraph chart',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'ranked-chart',
|
|
|
|
|
icon: 'ranked-chart',
|
|
|
|
|
label: 'Ranked',
|
|
|
|
|
title: 'Ranked chart',
|
|
|
|
|
},
|
2019-03-11 00:01:05 +08:00
|
|
|
];
|
|
|
|
|
|
2021-11-04 23:40:45 +08:00
|
|
|
const tabsWithTimeline = [
|
2021-07-23 01:58:57 +08:00
|
|
|
...tabs,
|
|
|
|
|
null, // Divider/separator
|
|
|
|
|
{
|
2021-11-04 03:10:29 +08:00
|
|
|
id: 'timeline',
|
|
|
|
|
icon: 'timeline',
|
|
|
|
|
label: 'Timeline',
|
|
|
|
|
title: 'Timeline',
|
2021-07-23 01:58:57 +08:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
2019-03-11 00:01:05 +08:00
|
|
|
const NoProfilingData = () => (
|
|
|
|
|
<div className={styles.Column}>
|
|
|
|
|
<div className={styles.Header}>No profiling data has been recorded.</div>
|
|
|
|
|
<div className={styles.Row}>
|
|
|
|
|
Click the record button <RecordToggle /> to start recording.
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
2019-03-19 04:37:37 +08:00
|
|
|
const ProfilingNotSupported = () => (
|
|
|
|
|
<div className={styles.Column}>
|
|
|
|
|
<div className={styles.Header}>Profiling not supported.</div>
|
2019-07-14 01:05:04 +08:00
|
|
|
<p className={styles.Paragraph}>
|
|
|
|
|
Profiling support requires either a development or production-profiling
|
|
|
|
|
build of React v16.5+.
|
|
|
|
|
</p>
|
|
|
|
|
<p className={styles.Paragraph}>
|
|
|
|
|
Learn more at{' '}
|
|
|
|
|
<a
|
|
|
|
|
className={styles.Link}
|
2020-08-17 20:25:50 +08:00
|
|
|
href="https://reactjs.org/link/profiling"
|
2019-07-14 01:05:04 +08:00
|
|
|
rel="noopener noreferrer"
|
2019-08-14 08:58:03 +08:00
|
|
|
target="_blank">
|
2020-08-17 20:25:50 +08:00
|
|
|
reactjs.org/link/profiling
|
2019-07-14 01:05:04 +08:00
|
|
|
</a>
|
|
|
|
|
.
|
|
|
|
|
</p>
|
2019-03-19 04:37:37 +08:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
2019-05-22 21:40:04 +08:00
|
|
|
const ProcessingData = () => (
|
|
|
|
|
<div className={styles.Column}>
|
|
|
|
|
<div className={styles.Header}>Processing data...</div>
|
|
|
|
|
<div className={styles.Row}>This should only take a minute.</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const RecordingInProgress = () => (
|
2019-03-11 01:13:20 +08:00
|
|
|
<div className={styles.Column}>
|
|
|
|
|
<div className={styles.Header}>Profiling is in progress...</div>
|
|
|
|
|
<div className={styles.Row}>
|
|
|
|
|
Click the record button <RecordToggle /> to stop recording.
|
2019-03-11 00:01:05 +08:00
|
|
|
</div>
|
2019-03-11 01:13:20 +08:00
|
|
|
</div>
|
|
|
|
|
);
|
2019-04-12 08:19:03 +08:00
|
|
|
|
2021-05-04 22:46:26 +08:00
|
|
|
export default portaledContent(Profiler);
|