Skip to content

Commit d0ab0bd

Browse files
ui: Tooltip descriptions for gpu SASS and stall frames (#6359)
* Tooltip descriptions for gpu SASS and stall frames * [pre-commit.ci lite] apply automatic fixes * Improved design with more details * [pre-commit.ci lite] apply automatic fixes * Rephrasing the content --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent 408bc28 commit d0ab0bd

6 files changed

Lines changed: 786 additions & 8 deletions

File tree

ui/packages/shared/profile/src/GraphTooltipArrow/Content.tsx

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {formatDateTimeDownToMS, getLastItem} from '@parca/utilities';
2222

2323
import {hexifyAddress, truncateString, truncateStringReverse} from '../utils';
2424
import {ExpandOnHover} from './ExpandOnHoverValue';
25+
import {gpuFrameInfo, type GpuFrameInfo} from './gpuFrameDescriptions';
26+
import {openInNewTab} from './openInNewTab';
2527
import {useGraphTooltip} from './useGraphTooltip';
2628
import {useGraphTooltipMetaInfo} from './useGraphTooltipMetaInfo';
2729

@@ -34,6 +36,7 @@ interface GraphTooltipArrowContentProps {
3436
row: number | null;
3537
isFixed: boolean;
3638
compareAbsolute: boolean;
39+
frozen?: boolean;
3740
}
3841

3942
const NoData = (): React.JSX.Element => {
@@ -49,6 +52,7 @@ const GraphTooltipArrowContent = ({
4952
row,
5053
isFixed,
5154
compareAbsolute,
55+
frozen = false,
5256
}: GraphTooltipArrowContentProps): React.JSX.Element => {
5357
const graphTooltipData = useGraphTooltip({
5458
table,
@@ -74,10 +78,21 @@ const GraphTooltipArrowContent = ({
7478
row: rowNumber,
7579
} = graphTooltipData;
7680

81+
const info = gpuFrameInfo(name);
82+
83+
// Outer card gains a subtle ring when frozen, matching the design's
84+
// `.is-frozen` treatment.
85+
const cardClassName = [
86+
'flex w-auto max-w-[600px] min-w-[300px] flex-col justify-start rounded-lg border bg-gray-50 p-3 shadow-lg dark:bg-gray-900',
87+
frozen
88+
? 'border-indigo-400/60 ring-2 ring-indigo-400/20 dark:border-indigo-400/40'
89+
: 'border-gray-300 dark:border-gray-500',
90+
].join(' ');
91+
7792
return (
7893
<div className={`flex text-sm ${isFixed ? 'w-full' : ''}`}>
7994
<div className={`m-auto w-full ${isFixed ? 'w-full' : ''}`}>
80-
<div className="flex w-auto max-w-[600px] min-w-[300px] flex-col justify-start rounded-lg border border-gray-300 bg-gray-50 p-3 shadow-lg dark:border-gray-500 dark:bg-gray-900">
95+
<div className={cardClassName}>
8196
<div className="flex flex-row">
8297
<div className="mx-2">
8398
<div className="flex min-h-10 items-start justify-between gap-4 break-all font-semibold mb-2">
@@ -120,16 +135,82 @@ const GraphTooltipArrowContent = ({
120135
</table>
121136
</div>
122137
</div>
123-
<div className="flex w-full items-center gap-1 text-xs text-gray-500">
124-
<Icon icon="iconoir:mouse-button-right" />
125-
<div>Right click to show context menu</div>
126-
</div>
138+
{info !== undefined && <GpuDescriptionBlock info={info} />}
139+
<ShortcutFooter frozen={frozen} />
127140
</div>
128141
</div>
129142
</div>
130143
);
131144
};
132145

146+
const GpuDescriptionBlock = ({info}: {info: GpuFrameInfo}): React.JSX.Element => {
147+
const chipPrefix = info.kind === 'stall' ? 'Stall reason' : 'SASS instruction';
148+
149+
return (
150+
<div className="mx-2 mt-3 border-t border-gray-200 pt-3 dark:border-gray-700">
151+
<div className="mb-2 text-xs font-semibold text-gray-700 dark:text-gray-200">
152+
{chipPrefix} · {info.entry.reasonLabel}
153+
</div>
154+
<div className="font-mono text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400">
155+
Description
156+
</div>
157+
<p className="mt-1 text-xs leading-relaxed text-gray-600 dark:text-gray-300">
158+
{info.entry.description}
159+
</p>
160+
<button
161+
type="button"
162+
onClick={e => {
163+
e.preventDefault();
164+
e.stopPropagation();
165+
openInNewTab(info.sourceUrl);
166+
}}
167+
title={info.sourceLabel}
168+
className="mt-2 inline-flex cursor-pointer items-center gap-1 self-start text-[11px] text-indigo-600 hover:underline dark:text-indigo-400"
169+
>
170+
Docs
171+
<Icon icon="iconoir:open-new-window" className="opacity-80" width={11} height={11} />
172+
</button>
173+
</div>
174+
);
175+
};
176+
177+
const ShortcutFooter = ({frozen}: {frozen: boolean}): React.JSX.Element => (
178+
<div className="mx-2 mt-3 flex flex-wrap items-center gap-x-3 gap-y-1 border-t border-gray-200 pt-2 text-[11px] text-gray-500 dark:border-gray-700 dark:text-gray-400">
179+
<span
180+
className={`inline-flex items-center gap-1.5 ${
181+
frozen ? 'text-gray-600 dark:text-gray-300' : ''
182+
}`}
183+
>
184+
<kbd
185+
className={[
186+
'inline-flex min-w-[18px] justify-center rounded border border-b-2 px-1 font-mono text-[10px] leading-4',
187+
frozen
188+
? 'border-gray-300 bg-gray-200 text-gray-600 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300'
189+
: 'border-gray-300 bg-white text-gray-600 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-300',
190+
].join(' ')}
191+
>
192+
193+
</kbd>
194+
{frozen ? (
195+
<span>
196+
<b className="font-semibold">Frozen</b> · release to resume hover
197+
</span>
198+
) : (
199+
<span>
200+
Hold <b className="font-semibold">Shift</b> to freeze · interact
201+
</span>
202+
)}
203+
</span>
204+
<span className="inline-block h-3 w-px bg-gray-200 dark:bg-gray-700" />
205+
<span className="inline-flex items-center gap-1.5">
206+
<Icon icon="iconoir:mouse-button-right" width={12} height={14} />
207+
<span>
208+
<b className="font-semibold">Right-click</b> for context menu
209+
</span>
210+
</span>
211+
</div>
212+
);
213+
133214
const TooltipMetaInfo = ({table, row}: {table: Table; row: number}): React.JSX.Element => {
134215
const {
135216
labelPairs,
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2022 The Parca Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
import {describe, expect, test} from 'vitest';
15+
16+
import {SASS_SOURCE_URL, STALL_SOURCE_URL, gpuFrameInfo} from './gpuFrameDescriptions';
17+
18+
describe('gpuFrameInfo', () => {
19+
test.each([
20+
['STS', 'Store to Shared Memory'],
21+
['ISETP', 'Integer Compare And Set Predicate'],
22+
['IMAD', 'Integer Multiply And Add'],
23+
['MOV', 'Move'],
24+
['FFMA', 'FP32 Fused Multiply and Add'],
25+
['LDG', 'Load from Global Memory'],
26+
])('returns SASS info for %s with verbatim description %j', (mnemonic, description) => {
27+
const info = gpuFrameInfo(mnemonic);
28+
expect(info?.kind).toBe('sass');
29+
expect(info?.entry.description).toBe(description);
30+
expect(info?.entry.reasonLabel.length).toBeGreaterThan(0);
31+
expect(info?.sourceUrl).toBe(SASS_SOURCE_URL);
32+
});
33+
34+
test.each([
35+
['smsp__pcsamp_warps_issue_stalled_long_scoreboard', 'Long Scoreboard'],
36+
['smsp__pcsamp_warps_issue_stalled_short_scoreboard', 'Short Scoreboard'],
37+
['smsp__pcsamp_warps_issue_stalled_barrier', 'Barrier'],
38+
['smsp__pcsamp_warps_issue_stalled_drain', 'Drain'],
39+
])('returns stall info for %s with reasonLabel %j and per-frame deep link', (reason, label) => {
40+
const info = gpuFrameInfo(reason);
41+
expect(info?.kind).toBe('stall');
42+
expect(info?.entry.description.length).toBeGreaterThan(0);
43+
expect(info?.entry.reasonLabel).toBe(label);
44+
expect(info?.sourceUrl).toBe(`${STALL_SOURCE_URL}:~:text=${reason}`);
45+
});
46+
47+
test.each([['main'], ['at::native::add'], ['<unknown>'], ['']])(
48+
'returns undefined for non-GPU frame name %j',
49+
name => {
50+
expect(gpuFrameInfo(name)).toBeUndefined();
51+
}
52+
);
53+
});

0 commit comments

Comments
 (0)