Skip to content
Merged
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
10 changes: 9 additions & 1 deletion ui/packages/shared/components/src/hooks/URLState/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export const useURLStateCustom = <T extends object | undefined>(
const [urlValue, setURLValue] = useURLState<string>(param, _options);

const val = useMemo<T>(() => {
return parse(urlValue);
return parse(decodeURIComponent(urlValue));
}, [parse, urlValue]);

const setVal = useCallback(
Expand All @@ -157,4 +157,12 @@ export const useURLStateCustom = <T extends object | undefined>(
return [val, setVal];
};

export const JSONSerializer = (val: object): string => {
return JSON.stringify(val, (_, v) => (typeof v === 'bigint' ? v.toString() : v));
};

export const JSONParser = <T extends object>(val: ParamValue): T => {
return JSON.parse(val as string);
};

export default URLStateContext;
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {getLastItem} from '@parca/utilities';
import {useGraphTooltip} from '../../GraphTooltipArrow/useGraphTooltip';
import {useGraphTooltipMetaInfo} from '../../GraphTooltipArrow/useGraphTooltipMetaInfo';
import {hexifyAddress, truncateString} from '../../utils';
import {CurrentPathFrame} from './utils';

interface ContextMenuProps {
menuId: string;
Expand All @@ -36,8 +37,8 @@ interface ContextMenuProps {
level: number;
compareAbsolute: boolean;
trackVisibility: (isVisible: boolean) => void;
curPath: string[];
setCurPath: (path: string[]) => void;
curPath: CurrentPathFrame[];
setCurPath: (path: CurrentPathFrame[]) => void;
hideMenu: () => void;
hideBinary: (binaryToRemove: string) => void;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ import {
FIELD_MAPPING_FILE,
} from './index';
import useNodeColor from './useNodeColor';
import {arrowToString, nodeLabel} from './utils';
import {
CurrentPathFrame,
arrowToString,
getCurrentPathFrameData,
isCurrentPathFrameMatch,
nodeLabel,
} from './utils';

export const RowHeight = 26;

Expand All @@ -48,11 +54,11 @@ interface IcicleGraphNodesProps {
total: bigint;
totalWidth: number;
level: number;
curPath: string[];
setCurPath: (path: string[]) => void;
curPath: CurrentPathFrame[];
setCurPath: (path: CurrentPathFrame[]) => void;
setHoveringRow: (row: number | null) => void;
setHoveringLevel: (level: number | null) => void;
path: string[];
path: CurrentPathFrame[];
xScale: (value: bigint) => number;
searchString?: string;
sortBy: string;
Expand Down Expand Up @@ -104,7 +110,7 @@ export const IcicleGraphNodes = React.memo(function IcicleGraphNodesNoMemo({
childRows =
curPath.length === 0
? childRows
: childRows.filter(c => nodeLabel(table, c, level, false) === curPath[0]);
: childRows.filter(c => isCurrentPathFrameMatch(table, c, level, curPath[0]));

let childrenCumulative = BigInt(0);
const childrenElements: ReactNode[] = [];
Expand Down Expand Up @@ -159,15 +165,15 @@ export interface IcicleNodeProps {
y: number;
height: number;
totalWidth: number;
curPath: string[];
curPath: CurrentPathFrame[];
level: number;
table: Table<any>;
row: number;
colors: colorByColors;
colorBy: string;
path: string[];
path: CurrentPathFrame[];
total: bigint;
setCurPath: (path: string[]) => void;
setCurPath: (path: CurrentPathFrame[]) => void;
setHoveringRow: (row: number | null) => void;
setHoveringLevel: (level: number | null) => void;
xScale: (value: bigint) => number;
Expand Down Expand Up @@ -343,8 +349,10 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
const name = useMemo(() => {
return isRoot ? 'root' : nodeLabel(table, row, level, binaries.length > 1);
}, [table, row, level, isRoot, binaries]);
const nextPath = path.concat([name]);
const isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
const currentPathFrame: CurrentPathFrame = getCurrentPathFrameData(table, row, level);
const nextPath = path.concat([currentPathFrame]);
const isFaded =
curPath.length > 0 && !isCurrentPathFrameMatch(table, row, level, curPath[curPath.length - 1]);
const styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
const nextLevel = level + 1;
const nextCurPath = curPath.length === 0 ? [] : curPath.slice(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import ContextMenu from './ContextMenu';
import {IcicleChartRootNode} from './IcicleChartRootNode';
import {IcicleNode, RowHeight, colorByColors} from './IcicleGraphNodes';
import {useFilenamesList} from './useMappingList';
import {arrowToString, extractFeature, extractFilenameFeature} from './utils';
import {CurrentPathFrame, arrowToString, extractFeature, extractFilenameFeature} from './utils';

export const FIELD_LABELS_ONLY = 'labels_only';
export const FIELD_MAPPING_FILE = 'mapping_file';
Expand Down Expand Up @@ -66,8 +66,8 @@ interface IcicleGraphArrowProps {
profileType?: ProfileType;
profileSource?: ProfileSource;
width?: number;
curPath: string[];
setCurPath: (path: string[]) => void;
curPath: CurrentPathFrame[];
setCurPath: (path: CurrentPathFrame[]) => void;
sortBy: string;
flamegraphLoading: boolean;
isHalfScreen: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {MergedProfileSource, ProfileSource} from '../../ProfileSource';
import {BigIntDuo, hexifyAddress} from '../../utils';
import {
FIELD_FUNCTION_NAME,
FIELD_FUNCTION_START_LINE,
FIELD_INLINED,
FIELD_LABELS_ONLY,
FIELD_LOCATION_ADDRESS,
FIELD_MAPPING_FILE,
Expand Down Expand Up @@ -149,3 +151,52 @@ export const boundsFromProfileSource = (profileSource?: ProfileSource): BigIntDu

return [start, end];
};

export interface CurrentPathFrame {
functionName: string;
systemName: string;
fileName: string;
lineNumber: number;
address: string;
inlined: boolean;
}

export const getCurrentPathFrameData = (
table: Table<any>,
row: number,
_level: number
): CurrentPathFrame => {
const functionName: string | null = arrowToString(table.getChild(FIELD_FUNCTION_NAME)?.get(row));
const systemName: string | null = arrowToString(table.getChild(FIELD_FUNCTION_NAME)?.get(row));
const fileName: string | null = arrowToString(table.getChild(FIELD_MAPPING_FILE)?.get(row));
const lineNumber: bigint = table.getChild(FIELD_FUNCTION_START_LINE)?.get(row) ?? 0n;
const addressBigInt: bigint = table.getChild(FIELD_LOCATION_ADDRESS)?.get(row);
const address = hexifyAddress(addressBigInt);
const inlined: boolean | null = table.getChild(FIELD_INLINED)?.get(row);

return {
functionName: functionName ?? '',
systemName: systemName ?? '',
fileName: fileName ?? '',
lineNumber: Number(lineNumber),
address: address,
inlined: inlined ?? false,
};
};

export function isCurrentPathFrameMatch(
table: Table<any>,
row: number,
level: number,
b: CurrentPathFrame
): boolean {
const a = getCurrentPathFrameData(table, row, level);
return (
a.functionName === b.functionName &&
a.systemName === b.systemName &&
a.fileName === b.fileName &&
a.lineNumber === b.lineNumber &&
a.address === b.address &&
a.inlined === b.inlined
);
}
12 changes: 9 additions & 3 deletions ui/packages/shared/profile/src/ProfileIcicleGraph/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {TimelineGuide} from '../TimelineGuide';
import {IcicleGraph} from './IcicleGraph';
import {FIELD_FUNCTION_NAME, IcicleGraphArrow} from './IcicleGraphArrow';
import useMappingList from './IcicleGraphArrow/useMappingList';
import {boundsFromProfileSource} from './IcicleGraphArrow/utils';
import {CurrentPathFrame, boundsFromProfileSource} from './IcicleGraphArrow/utils';

const numberFormatter = new Intl.NumberFormat('en-US');

Expand All @@ -44,6 +44,8 @@ interface ProfileIcicleGraphProps {
profileSource?: ProfileSource;
curPath: string[] | [];
setNewCurPath: (path: string[]) => void;
curPathArrow: CurrentPathFrame[] | [];
setNewCurPathArrow: (path: CurrentPathFrame[]) => void;
loading: boolean;
setActionButtons?: (buttons: React.JSX.Element) => void;
error?: any;
Expand All @@ -64,6 +66,8 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
filtered,
curPath,
setNewCurPath,
curPathArrow,
setNewCurPathArrow,
profileType,
loading,
error,
Expand Down Expand Up @@ -191,8 +195,8 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
arrow={arrow}
total={total}
filtered={filtered}
curPath={curPath}
setCurPath={setNewCurPath}
curPath={curPathArrow}
setCurPath={setNewCurPathArrow}
profileType={profileType}
sortBy={storeSortBy as string}
flamegraphLoading={isLoading}
Expand All @@ -216,6 +220,8 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
filtered,
curPath,
setNewCurPath,
curPathArrow,
setNewCurPathArrow,
profileType,
storeSortBy,
isHalfScreen,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {ConditionalWrapper} from '@parca/components';

import Callgraph from '../../../Callgraph';
import ProfileIcicleGraph from '../../../ProfileIcicleGraph';
import {CurrentPathFrame} from '../../../ProfileIcicleGraph/IcicleGraphArrow/utils';
import {ProfileSource} from '../../../ProfileSource';
import {SourceView} from '../../../SourceView';
import {Table} from '../../../Table';
Expand All @@ -42,6 +43,8 @@ interface GetDashboardItemProps {
filtered: bigint;
curPath: string[];
setNewCurPath: (path: string[]) => void;
curPathArrow: CurrentPathFrame[];
setNewCurPathArrow: (path: CurrentPathFrame[]) => void;
currentSearchString?: string;
setSearchString?: (value: string) => void;
callgraphSVG?: string;
Expand All @@ -64,6 +67,8 @@ export const getDashboardItem = ({
filtered,
curPath,
setNewCurPath,
curPathArrow,
setNewCurPathArrow,
currentSearchString,
setSearchString,
callgraphSVG,
Expand All @@ -83,6 +88,8 @@ export const getDashboardItem = ({
<ProfileIcicleGraph
curPath={curPath}
setNewCurPath={setNewCurPath}
curPathArrow={curPathArrow}
setNewCurPathArrow={setNewCurPathArrow}
arrow={flamegraphData?.arrow}
graph={flamegraphData?.data}
total={total}
Expand All @@ -106,8 +113,10 @@ export const getDashboardItem = ({
case 'iciclechart':
return (
<ProfileIcicleGraph
curPath={curPath}
curPath={[]}
setNewCurPath={() => {}}
curPathArrow={[]}
setNewCurPathArrow={() => {}}
arrow={flamechartData?.arrow}
total={total}
filtered={filtered}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {QueryServiceClient} from '@parca/client';
import {Button, UserPreferencesModal} from '@parca/components';
import {ProfileType} from '@parca/parser';

import {CurrentPathFrame} from '../../../ProfileIcicleGraph/IcicleGraphArrow/utils';
import {ProfileSource} from '../../../ProfileSource';
import {useDashboard} from '../../context/DashboardContext';
import GroupByDropdown from '../ActionButtons/GroupByDropdown';
Expand All @@ -37,8 +38,8 @@ export interface VisualisationToolbarProps {
profileSource?: ProfileSource;
queryClient?: QueryServiceClient;
onDownloadPProf: () => void;
curPath: string[];
setNewCurPath: (path: string[]) => void;
curPath: CurrentPathFrame[];
setNewCurPath: (path: CurrentPathFrame[]) => void;
profileType?: ProfileType;
total: bigint;
filtered: bigint;
Expand All @@ -61,8 +62,8 @@ export interface TableToolbarProps {
}

export interface IcicleGraphToolbarProps {
curPath: string[];
setNewCurPath: (path: string[]) => void;
curPath: CurrentPathFrame[];
setNewCurPath: (path: CurrentPathFrame[]) => void;
}

export const TableToolbar: FC<TableToolbarProps> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@

import {useCallback, useState} from 'react';

import {useURLState} from '@parca/components';
import {JSONParser, JSONSerializer, useURLState, useURLStateCustom} from '@parca/components';

import {FIELD_FUNCTION_NAME, FIELD_LABELS} from '../../ProfileIcicleGraph/IcicleGraphArrow';
import {CurrentPathFrame} from '../../ProfileIcicleGraph/IcicleGraphArrow/utils';

export const useVisualizationState = (): {
curPath: string[];
setCurPath: (path: string[]) => void;
curPathArrow: CurrentPathFrame[];
setCurPathArrow: (path: CurrentPathFrame[]) => void;
currentSearchString: string | undefined;
setSearchString: (searchString: string | undefined) => void;
colorStackLegend: string | undefined;
Expand All @@ -31,6 +34,11 @@ export const useVisualizationState = (): {
setGroupByLabels: (labels: string[]) => void;
} => {
const [curPath, setCurPath] = useState<string[]>([]);
const [curPathArrow, setCurPathArrow] = useURLStateCustom<CurrentPathFrame[]>('cur_path', {
parse: JSONParser<CurrentPathFrame[]>,
stringify: JSONSerializer,
defaultValue: '[]',
});
const [currentSearchString, setSearchString] = useURLState<string | undefined>('search_string');
const [colorStackLegend] = useURLState<string | undefined>('color_stack_legend');
const [colorBy] = useURLState('color_by');
Expand Down Expand Up @@ -69,6 +77,8 @@ export const useVisualizationState = (): {
return {
curPath,
setCurPath,
curPathArrow,
setCurPathArrow,
currentSearchString,
setSearchString,
colorStackLegend,
Expand Down
10 changes: 7 additions & 3 deletions ui/packages/shared/profile/src/ProfileView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export const ProfileView = ({
const {
curPath,
setCurPath,
curPathArrow,
setCurPathArrow,
currentSearchString,
setSearchString,
colorStackLegend,
Expand Down Expand Up @@ -107,6 +109,8 @@ export const ProfileView = ({
filtered,
curPath,
setNewCurPath: setCurPath,
curPathArrow,
setNewCurPathArrow: setCurPathArrow,
currentSearchString,
setSearchString,
callgraphSVG,
Expand All @@ -115,7 +119,7 @@ export const ProfileView = ({
};

const actionButtons = {
icicle: <IcicleGraphToolbar curPath={curPath} setNewCurPath={setCurPath} />,
icicle: <IcicleGraphToolbar curPath={curPathArrow} setNewCurPath={setCurPathArrow} />,
table: (
<TableToolbar
profileType={profileSource?.ProfileType()}
Expand Down Expand Up @@ -146,8 +150,8 @@ export const ProfileView = ({
profileSource={profileSource}
queryClient={queryClient}
onDownloadPProf={onDownloadPProf}
curPath={curPath}
setNewCurPath={setCurPath}
curPath={curPathArrow}
setNewCurPath={setCurPathArrow}
profileType={profileSource?.ProfileType()}
total={total}
filtered={filtered}
Expand Down