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

ui: Flamegraph tooltip performance fix #2265

Merged
merged 8 commits into from
Dec 12, 2022
17 changes: 12 additions & 5 deletions ui/packages/shared/profile/src/IcicleGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import React, {MouseEvent, useEffect, useRef, useState} from 'react';
import React, {MouseEvent, useEffect, useMemo, useRef, useState} from 'react';

import {throttle} from 'lodash';
import {pointer} from 'd3-selection';
Expand Down Expand Up @@ -385,7 +385,17 @@ export default function IcicleGraph({
}
}, [width]);

if (graph.root === undefined || width === undefined) return <></>;
const total = useMemo(() => parseFloat(graph.total), [graph.total]);
const xScale = useMemo(() => {
if (width === undefined) {
return () => 0;
}
return scaleLinear().domain([0, total]).range([0, width]);
}, [total, width]);

if (graph.root === undefined || width === undefined) {
return <></>;
}

const throttledSetPos = throttle(setPos, 20);
const onMouseMove = (e: React.MouseEvent<SVGSVGElement | HTMLDivElement>): void => {
Expand All @@ -395,9 +405,6 @@ export default function IcicleGraph({
throttledSetPos([rel[0], rel[1]]);
};

const total = parseFloat(graph.total);
const xScale = scaleLinear().domain([0, total]).range([0, width]);

return (
<div onMouseLeave={() => setHoveringNode(undefined)}>
<GraphTooltip
Expand Down
98 changes: 50 additions & 48 deletions ui/packages/shared/profile/src/ProfileView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,6 @@ export const ProfileView = ({

const isLoaderVisible = useDelayedLoader(isLoading);

if (isLoaderVisible) {
return <>{loader}</>;
}

if (flamegraphData?.error != null) {
console.error('Error: ', flamegraphData?.error);
return (
Expand Down Expand Up @@ -228,6 +224,7 @@ export const ProfileView = ({
<ProfileShareButton
queryRequest={profileSource.QueryRequest()}
queryClient={queryClient}
disabled={isLoading}
/>
) : null}

Expand All @@ -237,6 +234,7 @@ export const ProfileView = ({
e.preventDefault();
onDownloadPProf();
}}
disabled={isLoading}
>
Download pprof
</Button>
Expand Down Expand Up @@ -292,58 +290,62 @@ export const ProfileView = ({
</div>
</div>

<div ref={ref} className="flex space-x-4 justify-between w-full">
{currentView === 'icicle' && flamegraphData?.data != null && (
<div className="w-full">
<Profiler
id="icicleGraph"
onRender={perf?.onRender as React.ProfilerOnRenderCallback}
>
<ProfileIcicleGraph
curPath={curPath}
setNewCurPath={setNewCurPath}
graph={flamegraphData.data}
sampleUnit={sampleUnit}
/>
</Profiler>
</div>
)}
{currentView === 'callgraph' && callgraphData?.data != null && (
<div className="w-full">
{dimensions?.width !== undefined && (
<Callgraph
graph={callgraphData.data}
sampleUnit={sampleUnit}
width={dimensions?.width}
colorRange={colorRange}
/>
)}
</div>
)}
{currentView === 'table' && topTableData != null && (
<div className="w-full">
<TopTable data={topTableData.data} sampleUnit={sampleUnit} />
</div>
)}
{currentView === 'both' && (
<>
<div className="w-1/2">
<TopTable data={topTableData?.data} sampleUnit={sampleUnit} />
</div>

<div className="w-1/2">
{flamegraphData != null && (
{isLoaderVisible ? (
<>{loader}</>
) : (
<div ref={ref} className="flex space-x-4 justify-between w-full">
{currentView === 'icicle' && flamegraphData?.data != null && (
<div className="w-full">
<Profiler
id="icicleGraph"
onRender={perf?.onRender as React.ProfilerOnRenderCallback}
>
<ProfileIcicleGraph
curPath={curPath}
setNewCurPath={setNewCurPath}
graph={flamegraphData.data}
sampleUnit={sampleUnit}
/>
</Profiler>
</div>
)}
{currentView === 'callgraph' && callgraphData?.data != null && (
<div className="w-full">
{dimensions?.width !== undefined && (
<Callgraph
graph={callgraphData.data}
sampleUnit={sampleUnit}
width={dimensions?.width}
colorRange={colorRange}
/>
)}
</div>
</>
)}
</div>
)}
{currentView === 'table' && topTableData != null && (
<div className="w-full">
<TopTable data={topTableData.data} sampleUnit={sampleUnit} />
</div>
)}
{currentView === 'both' && (
<>
<div className="w-1/2">
<TopTable data={topTableData?.data} sampleUnit={sampleUnit} />
</div>

<div className="w-1/2">
{flamegraphData != null && (
<ProfileIcicleGraph
curPath={curPath}
setNewCurPath={setNewCurPath}
graph={flamegraphData.data}
sampleUnit={sampleUnit}
/>
)}
</div>
</>
)}
</div>
)}
</Card.Body>
</Card>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import ResultBox from './ResultBox';
interface Props {
queryRequest: QueryRequest;
queryClient: QueryServiceClient;
disabled?: boolean;
}

interface ProfileShareModalProps {
Expand Down Expand Up @@ -117,12 +118,12 @@ const ProfileShareModal = ({
);
};

const ProfileShareButton = ({queryRequest, queryClient}: Props): JSX.Element => {
const ProfileShareButton = ({queryRequest, queryClient, disabled = false}: Props): JSX.Element => {
const [isOpen, setIsOpen] = useState<boolean>(false);

return (
<>
<Button color="neutral" className="w-fit" onClick={() => setIsOpen(true)}>
<Button color="neutral" className="w-fit" onClick={() => setIsOpen(true)} disabled={disabled}>
<Icon icon="ei:share-apple" width={20} />
</Button>
<ProfileShareModal
Expand Down