@parca/profile 0.19.153 → 0.19.155

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.19.155](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.154...@parca/profile@0.19.155) (2026-06-09)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.19.154](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.153...@parca/profile@0.19.154) (2026-05-28)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.19.153](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.152...@parca/profile@0.19.153) (2026-05-21)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -1 +1 @@
1
- {"version":3,"file":"Content.d.ts","sourceRoot":"","sources":["../../src/GraphTooltipArrow/Content.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAGxC,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAU1C,UAAU,6BAA6B;IACrC,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAMD,QAAA,MAAM,wBAAwB,GAAI,8FAU/B,6BAA6B,KAAG,KAAK,CAAC,GAAG,CAAC,OAwF5C,CAAC;AAyJF,eAAe,wBAAwB,CAAC"}
1
+ {"version":3,"file":"Content.d.ts","sourceRoot":"","sources":["../../src/GraphTooltipArrow/Content.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAGxC,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAW1C,UAAU,6BAA6B;IACrC,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAMD,QAAA,MAAM,wBAAwB,GAAI,8FAU/B,6BAA6B,KAAG,KAAK,CAAC,GAAG,CAAC,OAgG5C,CAAC;AAyKF,eAAe,wBAAwB,CAAC"}
@@ -16,9 +16,10 @@ import React from 'react';
16
16
  import { Icon } from '@iconify/react';
17
17
  import { useParcaContext } from '@parca/components';
18
18
  import { formatDateTimeDownToMS, getLastItem } from '@parca/utilities';
19
+ import { getLabelPairs } from '../ProfileFlameGraph/FlameGraphArrow/utils';
19
20
  import { hexifyAddress, truncateString, truncateStringReverse } from '../utils';
20
21
  import { ExpandOnHover } from './ExpandOnHoverValue';
21
- import { gpuFrameInfo } from './gpuFrameDescriptions';
22
+ import { gpuFrameInfosFromLabels } from './gpuFrameDescriptions';
22
23
  import { openInNewTab } from './openInNewTab';
23
24
  import { useGraphTooltip } from './useGraphTooltip';
24
25
  import { useGraphTooltipMetaInfo } from './useGraphTooltipMetaInfo';
@@ -67,7 +68,7 @@ var GraphTooltipArrowContent = function GraphTooltipArrowContent(_ref) {
67
68
  diffText = graphTooltipData.diffText,
68
69
  diff = graphTooltipData.diff,
69
70
  rowNumber = graphTooltipData.row;
70
- var info = gpuFrameInfo(name);
71
+ var gpuInfos = gpuFrameInfosFromLabels(getLabelPairs(table, rowNumber));
71
72
 
72
73
  // Outer card gains a subtle ring when frozen, matching the design's
73
74
  // `.is-frozen` treatment.
@@ -129,8 +130,14 @@ var GraphTooltipArrowContent = function GraphTooltipArrowContent(_ref) {
129
130
  })
130
131
  })]
131
132
  })
132
- }), info !== undefined && /*#__PURE__*/_jsx(GpuDescriptionBlock, {
133
- info: info
133
+ }), gpuInfos.map(function (info, i) {
134
+ return /*#__PURE__*/_jsx(GpuDescriptionBlock, {
135
+ info: info
136
+ // When both a SASS and a stall block are shown, keep the tooltip
137
+ // compact by trimming the (typically longer) stall description.
138
+ ,
139
+ maxSentences: gpuInfos.length > 1 && info.kind === 'stall' ? 2 : undefined
140
+ }, i);
134
141
  }), /*#__PURE__*/_jsx(ShortcutFooter, {
135
142
  frozen: frozen
136
143
  })]
@@ -138,96 +145,115 @@ var GraphTooltipArrowContent = function GraphTooltipArrowContent(_ref) {
138
145
  })
139
146
  });
140
147
  };
148
+
149
+ // Trims a description to at most `max` sentences, appending an ellipsis when
150
+ // anything was dropped.
151
+ var truncateToSentences = function truncateToSentences(text, max) {
152
+ var sentences = text.match(/[^.!?]+[.!?]+(\s|$)|[^.!?]+$/g);
153
+ if (sentences === null || sentences.length <= max) return text;
154
+ return "".concat(sentences.slice(0, max).join('').trimEnd(), " \u2026");
155
+ };
141
156
  var GpuDescriptionBlock = function GpuDescriptionBlock(t0) {
142
- var $ = _c(16);
143
- var info = t0.info;
157
+ var $ = _c(19);
158
+ var info = t0.info,
159
+ maxSentences = t0.maxSentences;
144
160
  var chipPrefix = info.kind === "stall" ? "Stall reason" : "SASS instruction";
145
161
  var t1;
146
- if ($[0] !== chipPrefix || $[1] !== info.entry.reasonLabel) {
147
- t1 = /*#__PURE__*/_jsxs("div", {
148
- className: "mb-2 text-xs font-semibold text-gray-700 dark:text-gray-200",
149
- children: [chipPrefix, " \xB7 ", info.entry.reasonLabel]
150
- });
151
- $[0] = chipPrefix;
152
- $[1] = info.entry.reasonLabel;
162
+ if ($[0] !== info.entry.description || $[1] !== maxSentences) {
163
+ t1 = maxSentences === undefined ? info.entry.description : truncateToSentences(info.entry.description, maxSentences);
164
+ $[0] = info.entry.description;
165
+ $[1] = maxSentences;
153
166
  $[2] = t1;
154
167
  } else {
155
168
  t1 = $[2];
156
169
  }
170
+ var description = t1;
157
171
  var t2;
158
- if ($[3] === Symbol["for"]("react.memo_cache_sentinel")) {
159
- t2 = /*#__PURE__*/_jsx("div", {
172
+ if ($[3] !== chipPrefix || $[4] !== info.entry.reasonLabel) {
173
+ t2 = /*#__PURE__*/_jsxs("div", {
174
+ className: "mb-2 text-xs font-semibold text-gray-700 dark:text-gray-200",
175
+ children: [chipPrefix, " \xB7 ", info.entry.reasonLabel]
176
+ });
177
+ $[3] = chipPrefix;
178
+ $[4] = info.entry.reasonLabel;
179
+ $[5] = t2;
180
+ } else {
181
+ t2 = $[5];
182
+ }
183
+ var t3;
184
+ if ($[6] === Symbol["for"]("react.memo_cache_sentinel")) {
185
+ t3 = /*#__PURE__*/_jsx("div", {
160
186
  className: "font-mono text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400",
161
187
  children: "Description"
162
188
  });
163
- $[3] = t2;
189
+ $[6] = t3;
164
190
  } else {
165
- t2 = $[3];
191
+ t3 = $[6];
166
192
  }
167
- var t3;
168
- if ($[4] !== info.entry.description) {
169
- t3 = /*#__PURE__*/_jsx("p", {
193
+ var t4;
194
+ if ($[7] !== description) {
195
+ t4 = /*#__PURE__*/_jsx("p", {
170
196
  className: "mt-1 text-xs leading-relaxed text-gray-600 dark:text-gray-300",
171
- children: info.entry.description
197
+ children: description
172
198
  });
173
- $[4] = info.entry.description;
174
- $[5] = t3;
199
+ $[7] = description;
200
+ $[8] = t4;
175
201
  } else {
176
- t3 = $[5];
202
+ t4 = $[8];
177
203
  }
178
- var t4;
179
- if ($[6] !== info.sourceUrl) {
180
- t4 = function t4(e) {
204
+ var t5;
205
+ if ($[9] !== info.sourceUrl) {
206
+ t5 = function t5(e) {
181
207
  e.preventDefault();
182
208
  e.stopPropagation();
183
209
  openInNewTab(info.sourceUrl);
184
210
  };
185
- $[6] = info.sourceUrl;
186
- $[7] = t4;
211
+ $[9] = info.sourceUrl;
212
+ $[10] = t5;
187
213
  } else {
188
- t4 = $[7];
214
+ t5 = $[10];
189
215
  }
190
- var t5;
191
- if ($[8] === Symbol["for"]("react.memo_cache_sentinel")) {
192
- t5 = /*#__PURE__*/_jsx(Icon, {
216
+ var t6;
217
+ if ($[11] === Symbol["for"]("react.memo_cache_sentinel")) {
218
+ t6 = /*#__PURE__*/_jsx(Icon, {
193
219
  icon: "iconoir:open-new-window",
194
220
  className: "opacity-80",
195
221
  width: 11,
196
222
  height: 11
197
223
  });
198
- $[8] = t5;
224
+ $[11] = t6;
199
225
  } else {
200
- t5 = $[8];
226
+ t6 = $[11];
201
227
  }
202
- var t6;
203
- if ($[9] !== info.sourceLabel || $[10] !== t4) {
204
- t6 = /*#__PURE__*/_jsxs("button", {
228
+ var t7;
229
+ if ($[12] !== info.sourceLabel || $[13] !== t5) {
230
+ t7 = /*#__PURE__*/_jsxs("button", {
205
231
  type: "button",
206
- onClick: t4,
232
+ onClick: t5,
207
233
  title: info.sourceLabel,
208
234
  className: "mt-2 inline-flex cursor-pointer items-center gap-1 self-start text-[11px] text-indigo-600 hover:underline dark:text-indigo-400",
209
- children: ["Docs", t5]
235
+ children: ["Docs", t6]
210
236
  });
211
- $[9] = info.sourceLabel;
212
- $[10] = t4;
213
- $[11] = t6;
237
+ $[12] = info.sourceLabel;
238
+ $[13] = t5;
239
+ $[14] = t7;
214
240
  } else {
215
- t6 = $[11];
241
+ t7 = $[14];
216
242
  }
217
- var t7;
218
- if ($[12] !== t1 || $[13] !== t3 || $[14] !== t6) {
219
- t7 = /*#__PURE__*/_jsxs("div", {
243
+ var t8;
244
+ if ($[15] !== t2 || $[16] !== t4 || $[17] !== t7) {
245
+ t8 = /*#__PURE__*/_jsxs("div", {
220
246
  className: "mx-2 mt-3 border-t border-gray-200 pt-3 dark:border-gray-700",
221
- children: [t1, t2, t3, t6]
247
+ children: [t2, t3, t4, t7]
222
248
  });
223
- $[12] = t1;
224
- $[13] = t3;
225
- $[14] = t6;
226
- $[15] = t7;
249
+ $[15] = t2;
250
+ $[16] = t4;
251
+ $[17] = t7;
252
+ $[18] = t8;
227
253
  } else {
228
- t7 = $[15];
254
+ t8 = $[18];
229
255
  }
230
- return t7;
256
+ return t8;
231
257
  };
232
258
  var ShortcutFooter = function ShortcutFooter(t0) {
233
259
  var $ = _c(14);
@@ -24,5 +24,8 @@ export type GpuFrameInfo = {
24
24
  sourceLabel: string;
25
25
  sourceUrl: string;
26
26
  };
27
+ export declare const CUDA_SASS_INSTRUCTION_LABEL = "cuda_sass_instruction";
28
+ export declare const CUDA_STALL_REASON_LABEL = "cuda_stall_reason";
27
29
  export declare function gpuFrameInfo(name: string): GpuFrameInfo | undefined;
30
+ export declare function gpuFrameInfosFromLabels(labelPairs: Array<[string, string]>): GpuFrameInfo[];
28
31
  //# sourceMappingURL=gpuFrameDescriptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gpuFrameDescriptions.d.ts","sourceRoot":"","sources":["../../src/GraphTooltipArrow/gpuFrameDescriptions.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,gBAAgB,wFAC0D,CAAC;AACxF,eAAO,MAAM,eAAe,sGACyE,CAAC;AAEtG,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAkRnE,CAAC;AAGF,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CA4LhE,CAAC;AAGF,MAAM,MAAM,YAAY,GACpB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,GACxE;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAAC;AAW/E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAqBnE"}
1
+ {"version":3,"file":"gpuFrameDescriptions.d.ts","sourceRoot":"","sources":["../../src/GraphTooltipArrow/gpuFrameDescriptions.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,gBAAgB,wFAC0D,CAAC;AACxF,eAAO,MAAM,eAAe,sGACyE,CAAC;AAEtG,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAkRnE,CAAC;AAGF,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CA4LhE,CAAC;AAGF,MAAM,MAAM,YAAY,GACpB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,GACxE;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAAC;AAY/E,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AACnE,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AA4B3D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEnE;AAKD,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,YAAY,EAAE,CAa3F"}
@@ -1,3 +1,9 @@
1
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
4
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
1
7
  // Copyright 2022 The Parca Authors
2
8
  // Licensed under the Apache License, Version 2.0 (the "License");
3
9
  // you may not use this file except in compliance with the License.
@@ -817,29 +823,66 @@ function stallSourceUrl(name) {
817
823
  return "".concat(STALL_SOURCE_URL, ":~:text=").concat(encodeURIComponent(name));
818
824
  }
819
825
 
826
+ // Node label keys under which GPU PC-sampling values now arrive. The SASS
827
+ // mnemonic and warp stall reason used to be the leaf frame's function name;
828
+ // they are now carried as node labels.
829
+ export var CUDA_SASS_INSTRUCTION_LABEL = 'cuda_sass_instruction';
830
+ export var CUDA_STALL_REASON_LABEL = 'cuda_stall_reason';
831
+ function sassInfo(name) {
832
+ var _sass$sourceUrl;
833
+ if (name === '') return undefined;
834
+ var sass = SASS_INSTRUCTION_DESCRIPTIONS[name];
835
+ if (sass === undefined) return undefined;
836
+ return {
837
+ kind: 'sass',
838
+ entry: sass,
839
+ sourceLabel: NVIDIA_DOCS_LABEL,
840
+ sourceUrl: (_sass$sourceUrl = sass.sourceUrl) !== null && _sass$sourceUrl !== void 0 ? _sass$sourceUrl : SASS_SOURCE_URL
841
+ };
842
+ }
843
+ function stallInfo(name) {
844
+ var _stall$sourceUrl;
845
+ if (name === '') return undefined;
846
+ var stall = STALL_REASON_DESCRIPTIONS[name];
847
+ if (stall === undefined) return undefined;
848
+ return {
849
+ kind: 'stall',
850
+ entry: stall,
851
+ sourceLabel: NVIDIA_DOCS_LABEL,
852
+ sourceUrl: (_stall$sourceUrl = stall.sourceUrl) !== null && _stall$sourceUrl !== void 0 ? _stall$sourceUrl : stallSourceUrl(name)
853
+ };
854
+ }
855
+
820
856
  // Resolves a frame name to its GPU info, or undefined if not a known SASS
821
857
  // mnemonic or PC-sampling reason. Both tables are exact-match lookups.
822
858
  export function gpuFrameInfo(name) {
823
- if (name === '') return undefined;
824
- var sass = SASS_INSTRUCTION_DESCRIPTIONS[name];
825
- if (sass !== undefined) {
826
- var _sass$sourceUrl;
827
- return {
828
- kind: 'sass',
829
- entry: sass,
830
- sourceLabel: NVIDIA_DOCS_LABEL,
831
- sourceUrl: (_sass$sourceUrl = sass.sourceUrl) !== null && _sass$sourceUrl !== void 0 ? _sass$sourceUrl : SASS_SOURCE_URL
832
- };
859
+ var _sassInfo;
860
+ return (_sassInfo = sassInfo(name)) !== null && _sassInfo !== void 0 ? _sassInfo : stallInfo(name);
861
+ }
862
+
863
+ // Resolves GPU info from a node's labels. A node may carry both a SASS
864
+ // instruction and a stall reason label, so this returns an array (SASS first,
865
+ // then stall) of the entries that matched a known description.
866
+ export function gpuFrameInfosFromLabels(labelPairs) {
867
+ var _labelPairs$find, _labelPairs$find2;
868
+ var infos = [];
869
+ var sassValue = (_labelPairs$find = labelPairs.find(function (_ref) {
870
+ var _ref2 = _slicedToArray(_ref, 1),
871
+ key = _ref2[0];
872
+ return key === CUDA_SASS_INSTRUCTION_LABEL;
873
+ })) === null || _labelPairs$find === void 0 ? void 0 : _labelPairs$find[1];
874
+ var stallValue = (_labelPairs$find2 = labelPairs.find(function (_ref3) {
875
+ var _ref4 = _slicedToArray(_ref3, 1),
876
+ key = _ref4[0];
877
+ return key === CUDA_STALL_REASON_LABEL;
878
+ })) === null || _labelPairs$find2 === void 0 ? void 0 : _labelPairs$find2[1];
879
+ if (sassValue !== undefined) {
880
+ var info = sassInfo(sassValue);
881
+ if (info !== undefined) infos.push(info);
833
882
  }
834
- var stall = STALL_REASON_DESCRIPTIONS[name];
835
- if (stall !== undefined) {
836
- var _stall$sourceUrl;
837
- return {
838
- kind: 'stall',
839
- entry: stall,
840
- sourceLabel: NVIDIA_DOCS_LABEL,
841
- sourceUrl: (_stall$sourceUrl = stall.sourceUrl) !== null && _stall$sourceUrl !== void 0 ? _stall$sourceUrl : stallSourceUrl(name)
842
- };
883
+ if (stallValue !== undefined) {
884
+ var _info = stallInfo(stallValue);
885
+ if (_info !== undefined) infos.push(_info);
843
886
  }
844
- return undefined;
887
+ return infos;
845
888
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAwBxC,UAAU,KAAK;IACb,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,UAAU,wBAAwB;IAChC,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,eAAO,MAAM,uBAAuB,GAAI,gBAAc,KAAK,KAAG,wBAyF7D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAwBxC,UAAU,KAAK;IACb,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,UAAU,wBAAwB;IAChC,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,eAAO,MAAM,uBAAuB,GAAI,gBAAc,KAAK,KAAG,wBAkF7D,CAAC"}
@@ -21,7 +21,7 @@ import { useQueryState } from 'nuqs';
21
21
  import { QueryRequest_ReportType } from '@parca/client';
22
22
  import { useParcaContext } from '@parca/components';
23
23
  import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_START_LINE, FIELD_FUNCTION_SYSTEM_NAME, FIELD_INLINED, FIELD_LOCATION_ADDRESS, FIELD_LOCATION_LINE, FIELD_MAPPING_BUILD_ID, FIELD_MAPPING_FILE, FIELD_TIMESTAMP } from '../../ProfileFlameGraph/FlameGraphArrow';
24
- import { arrowToString } from '../../ProfileFlameGraph/FlameGraphArrow/utils';
24
+ import { arrowToString, getLabelPairs } from '../../ProfileFlameGraph/FlameGraphArrow/utils';
25
25
  import { useProfileViewContext } from '../../ProfileView/context/ProfileViewContext';
26
26
  import { stringParam } from '../../hooks/urlParsers';
27
27
  import { useDashboardItems } from '../../hooks/useDashboardItems';
@@ -39,10 +39,6 @@ export var useGraphTooltipMetaInfo = function useGraphTooltipMetaInfo(_ref) {
39
39
  var functionSystemName = (_arrowToString2 = arrowToString((_table$getChild7 = table.getChild(FIELD_FUNCTION_SYSTEM_NAME)) === null || _table$getChild7 === void 0 ? void 0 : _table$getChild7.get(row))) !== null && _arrowToString2 !== void 0 ? _arrowToString2 : '';
40
40
  var functionStartLine = (_table$getChild$get3 = (_table$getChild8 = table.getChild(FIELD_FUNCTION_START_LINE)) === null || _table$getChild8 === void 0 ? void 0 : _table$getChild8.get(row)) !== null && _table$getChild$get3 !== void 0 ? _table$getChild$get3 : 0n;
41
41
  var lineNumber = locationLine !== 0n ? locationLine : functionStartLine !== 0n ? functionStartLine : undefined;
42
- var labelPrefix = 'labels.';
43
- var labelColumnNames = table.schema.fields.filter(function (field) {
44
- return field.name.startsWith(labelPrefix);
45
- });
46
42
  var timestamp = (_table$getChild9 = table.getChild(FIELD_TIMESTAMP)) === null || _table$getChild9 === void 0 ? void 0 : _table$getChild9.get(row);
47
43
  var _useParcaContext = useParcaContext(),
48
44
  queryServiceClient = _useParcaContext.queryServiceClient,
@@ -67,12 +63,7 @@ export var useGraphTooltipMetaInfo = function useGraphTooltipMetaInfo(_ref) {
67
63
  return "".concat(functionFilename, " ").concat(lineNumber !== undefined ? " +".concat(lineNumber.toString()) : '');
68
64
  };
69
65
  var file = getTextForFile();
70
- var labelPairs = labelColumnNames.map(function (field_0, i) {
71
- var _arrowToString3, _table$getChild0;
72
- return [labelColumnNames[i].name.slice(labelPrefix.length), (_arrowToString3 = arrowToString((_table$getChild0 = table.getChild(field_0.name)) === null || _table$getChild0 === void 0 ? void 0 : _table$getChild0.get(row))) !== null && _arrowToString3 !== void 0 ? _arrowToString3 : ''];
73
- }).filter(function (value) {
74
- return value[1] !== '';
75
- });
66
+ var labelPairs = getLabelPairs(table, row);
76
67
  var _useDashboardItems = useDashboardItems(),
77
68
  dashboardItems = _useDashboardItems.dashboardItems,
78
69
  setDashboardItems = _useDashboardItems.setDashboardItems;
@@ -19,6 +19,7 @@ export interface CurrentPathFrame {
19
19
  labels?: string;
20
20
  }
21
21
  export declare const getCurrentPathFrameData: (table: Table, row: number) => CurrentPathFrame;
22
+ export declare function getLabelPairs(table: Table, row: number): Array<[string, string]>;
22
23
  export declare function isCurrentPathFrameMatch(table: Table, row: number, b: CurrentPathFrame): boolean;
23
24
  export declare function getMaxDepth(depthColumn: Column<number> | null): number;
24
25
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/utils.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,MAAM,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAC,aAAa,EAAwB,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAC,SAAS,EAAgB,MAAM,aAAa,CAAC;AAWrD,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,CAuBpF;AAED,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,aAMhD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,eAMzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,wBAAwB,MAAM,EAC9B,iBAAiB,MAAM,EACvB,OAAO,MAAM,EACb,MAAM,MAAM,KACX,MAOF,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,wBAAwB,MAAM,EAC9B,MAAM,MAAM,KACX,MAMF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,KAAG,MAAM,GAAG,IAQpD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,gBAAgB,aAAa,KAAG,SAyBvE,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,uBAAuB,GAAI,OAAO,KAAK,EAAE,KAAK,MAAM,KAAG,gBAwBnE,CAAC;AAgBF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAW/F;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,MAAM,CAStE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/utils.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,MAAM,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAC,aAAa,EAAwB,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAC,SAAS,EAAgB,MAAM,aAAa,CAAC;AAWrD,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,CAuBpF;AAED,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,aAMhD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,eAMzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,wBAAwB,MAAM,EAC9B,iBAAiB,MAAM,EACvB,OAAO,MAAM,EACb,MAAM,MAAM,KACX,MAOF,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,wBAAwB,MAAM,EAC9B,MAAM,MAAM,KACX,MAMF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,KAAG,MAAM,GAAG,IAQpD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,gBAAgB,aAAa,KAAG,SAyBvE,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,uBAAuB,GAAI,OAAO,KAAK,EAAE,KAAK,MAAM,KAAG,gBAwBnE,CAAC;AAEF,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAUhF;AAQD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAW/F;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,MAAM,CAStE"}
@@ -126,7 +126,7 @@ export var getCurrentPathFrameData = function getCurrentPathFrameData(table, row
126
126
  labels: labels !== null && labels !== void 0 ? labels : undefined
127
127
  };
128
128
  };
129
- function getLabelSet(table, row) {
129
+ export function getLabelPairs(table, row) {
130
130
  var labelPrefix = 'labels.';
131
131
  var labelColumnNames = table.schema.fields.filter(function (field) {
132
132
  return field.name.startsWith(labelPrefix);
@@ -136,7 +136,10 @@ function getLabelSet(table, row) {
136
136
  return [labelColumnNames[i].name.slice(labelPrefix.length), (_arrowToString = arrowToString((_table$getChild12 = table.getChild(field.name)) === null || _table$getChild12 === void 0 ? void 0 : _table$getChild12.get(row))) !== null && _arrowToString !== void 0 ? _arrowToString : ''];
137
137
  }).filter(function (value) {
138
138
  return value[1] !== '';
139
- }).map(function (_ref) {
139
+ });
140
+ }
141
+ function getLabelSet(table, row) {
142
+ return getLabelPairs(table, row).map(function (_ref) {
140
143
  var _ref2 = _slicedToArray(_ref, 2),
141
144
  k = _ref2[0],
142
145
  v = _ref2[1];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileTypeSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAChE,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAG7D,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iBAAiB;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACjC;AAED,eAAO,MAAM,iBAAiB,EAAE,iBAiG/B,CAAC;AAEF,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAU3F;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,8BAA8B,EAAE,OAAO,GACtC,aAAa,CAiBf;AAED,eAAO,MAAM,oBAAoB,GAAI,MAAM,WAAW,KAAG,MAIxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,OAAO,WAAW,EAAE,KAAG,MAAM,EAItE,CAAC;AAEF,UAAU,KAAK;IACb,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,2GAQ1B,KAAK,KAAG,GAAG,CAAC,OA2Bd,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileTypeSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAChE,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAG7D,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iBAAiB;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACjC;AAED,eAAO,MAAM,iBAAiB,EAAE,iBAmG/B,CAAC;AAEF,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAU3F;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,8BAA8B,EAAE,OAAO,GACtC,aAAa,CAiBf;AAED,eAAO,MAAM,oBAAoB,GAAI,MAAM,WAAW,KAAG,MAIxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,OAAO,WAAW,EAAE,KAAG,MAAM,EAItE,CAAC;AAEF,UAAU,KAAK;IACb,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,2GAQ1B,KAAK,KAAG,GAAG,CAAC,OA2Bd,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -100,21 +100,23 @@ export var wellKnownProfiles = {
100
100
  name: 'Off-CPU',
101
101
  help: 'Time spent off the CPU as observed by the Parca Agent.'
102
102
  },
103
+ // deprecated with PC sampling
103
104
  'parca_agent:cuda:nanoseconds:cuda:nanoseconds:delta': {
104
105
  name: 'On-GPU',
105
106
  help: 'Time spent on the GPU.'
106
107
  },
108
+ // use this for combined PC stall and kernel timing, not the default
107
109
  'parca_agent:gpu_time:nanoseconds:gpu_time:nanoseconds:delta': {
108
110
  name: 'On-GPU',
109
111
  help: 'Time spent on the GPU. Combines kernel execution time and PC stall samples; the gpu_view label distinguishes the two views.'
110
112
  },
111
113
  'parca_agent:gpu_kernel_time:nanoseconds:gpu_kernel_time:nanoseconds:delta': {
112
- name: 'On-GPU',
114
+ name: 'GPU Kernels',
113
115
  help: 'GPU kernel execution time measured via CUDA runtime callbacks.'
114
116
  },
115
- 'parca_agent:gpu_stall_time:nanoseconds:gpu_stall_time:nanoseconds:delta': {
116
- name: 'GPU Stalls',
117
- help: 'GPU stall time accumulated from PC samplingshows where threads were waiting on the GPU.'
117
+ 'parca_agent:gpu_pcsample:count:gpu_pcsample:nanoseconds:delta': {
118
+ name: 'GPU Instructions',
119
+ help: 'PC samples from the GPUall PC activity, not just stalls; shows the instruction/stall reason.'
118
120
  }
119
121
  };
120
122
  export function flexibleWellKnownProfileMatching(name) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.19.153",
3
+ "version": "0.19.155",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "^0.27.12",
@@ -89,5 +89,5 @@
89
89
  "access": "public",
90
90
  "registry": "https://registry.npmjs.org/"
91
91
  },
92
- "gitHead": "2bab7be553ea2f217a37cc0a307c55e2694839b8"
92
+ "gitHead": "c16730288b7d5f5684ebebfd8f505c7d0fcb99b8"
93
93
  }
@@ -20,9 +20,10 @@ import {useParcaContext} from '@parca/components';
20
20
  import {ProfileType} from '@parca/parser';
21
21
  import {formatDateTimeDownToMS, getLastItem} from '@parca/utilities';
22
22
 
23
+ import {getLabelPairs} from '../ProfileFlameGraph/FlameGraphArrow/utils';
23
24
  import {hexifyAddress, truncateString, truncateStringReverse} from '../utils';
24
25
  import {ExpandOnHover} from './ExpandOnHoverValue';
25
- import {gpuFrameInfo, type GpuFrameInfo} from './gpuFrameDescriptions';
26
+ import {gpuFrameInfosFromLabels, type GpuFrameInfo} from './gpuFrameDescriptions';
26
27
  import {openInNewTab} from './openInNewTab';
27
28
  import {useGraphTooltip} from './useGraphTooltip';
28
29
  import {useGraphTooltipMetaInfo} from './useGraphTooltipMetaInfo';
@@ -78,7 +79,7 @@ const GraphTooltipArrowContent = ({
78
79
  row: rowNumber,
79
80
  } = graphTooltipData;
80
81
 
81
- const info = gpuFrameInfo(name);
82
+ const gpuInfos = gpuFrameInfosFromLabels(getLabelPairs(table, rowNumber));
82
83
 
83
84
  // Outer card gains a subtle ring when frozen, matching the design's
84
85
  // `.is-frozen` treatment.
@@ -135,7 +136,15 @@ const GraphTooltipArrowContent = ({
135
136
  </table>
136
137
  </div>
137
138
  </div>
138
- {info !== undefined && <GpuDescriptionBlock info={info} />}
139
+ {gpuInfos.map((info, i) => (
140
+ <GpuDescriptionBlock
141
+ key={i}
142
+ info={info}
143
+ // When both a SASS and a stall block are shown, keep the tooltip
144
+ // compact by trimming the (typically longer) stall description.
145
+ maxSentences={gpuInfos.length > 1 && info.kind === 'stall' ? 2 : undefined}
146
+ />
147
+ ))}
139
148
  <ShortcutFooter frozen={frozen} />
140
149
  </div>
141
150
  </div>
@@ -143,8 +152,26 @@ const GraphTooltipArrowContent = ({
143
152
  );
144
153
  };
145
154
 
146
- const GpuDescriptionBlock = ({info}: {info: GpuFrameInfo}): React.JSX.Element => {
155
+ // Trims a description to at most `max` sentences, appending an ellipsis when
156
+ // anything was dropped.
157
+ const truncateToSentences = (text: string, max: number): string => {
158
+ const sentences = text.match(/[^.!?]+[.!?]+(\s|$)|[^.!?]+$/g);
159
+ if (sentences === null || sentences.length <= max) return text;
160
+ return `${sentences.slice(0, max).join('').trimEnd()} …`;
161
+ };
162
+
163
+ const GpuDescriptionBlock = ({
164
+ info,
165
+ maxSentences,
166
+ }: {
167
+ info: GpuFrameInfo;
168
+ maxSentences?: number;
169
+ }): React.JSX.Element => {
147
170
  const chipPrefix = info.kind === 'stall' ? 'Stall reason' : 'SASS instruction';
171
+ const description =
172
+ maxSentences === undefined
173
+ ? info.entry.description
174
+ : truncateToSentences(info.entry.description, maxSentences);
148
175
 
149
176
  return (
150
177
  <div className="mx-2 mt-3 border-t border-gray-200 pt-3 dark:border-gray-700">
@@ -154,9 +181,7 @@ const GpuDescriptionBlock = ({info}: {info: GpuFrameInfo}): React.JSX.Element =>
154
181
  <div className="font-mono text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400">
155
182
  Description
156
183
  </div>
157
- <p className="mt-1 text-xs leading-relaxed text-gray-600 dark:text-gray-300">
158
- {info.entry.description}
159
- </p>
184
+ <p className="mt-1 text-xs leading-relaxed text-gray-600 dark:text-gray-300">{description}</p>
160
185
  <button
161
186
  type="button"
162
187
  onClick={e => {
@@ -13,7 +13,14 @@
13
13
 
14
14
  import {describe, expect, test} from 'vitest';
15
15
 
16
- import {SASS_SOURCE_URL, STALL_SOURCE_URL, gpuFrameInfo} from './gpuFrameDescriptions';
16
+ import {
17
+ CUDA_SASS_INSTRUCTION_LABEL,
18
+ CUDA_STALL_REASON_LABEL,
19
+ SASS_SOURCE_URL,
20
+ STALL_SOURCE_URL,
21
+ gpuFrameInfo,
22
+ gpuFrameInfosFromLabels,
23
+ } from './gpuFrameDescriptions';
17
24
 
18
25
  describe('gpuFrameInfo', () => {
19
26
  test.each([
@@ -51,3 +58,37 @@ describe('gpuFrameInfo', () => {
51
58
  }
52
59
  );
53
60
  });
61
+
62
+ describe('gpuFrameInfosFromLabels', () => {
63
+ test('returns a single SASS info for the cuda_sass_instruction label', () => {
64
+ const infos = gpuFrameInfosFromLabels([[CUDA_SASS_INSTRUCTION_LABEL, 'STS']]);
65
+ expect(infos).toHaveLength(1);
66
+ expect(infos[0].kind).toBe('sass');
67
+ expect(infos[0].entry.description).toBe('Store to Shared Memory');
68
+ });
69
+
70
+ test('returns a single stall info for the cuda_stall_reason label', () => {
71
+ const infos = gpuFrameInfosFromLabels([
72
+ [CUDA_STALL_REASON_LABEL, 'smsp__pcsamp_warps_issue_stalled_long_scoreboard'],
73
+ ]);
74
+ expect(infos).toHaveLength(1);
75
+ expect(infos[0].kind).toBe('stall');
76
+ expect(infos[0].entry.reasonLabel).toBe('Long Scoreboard');
77
+ });
78
+
79
+ test('returns SASS first then stall when both labels are present', () => {
80
+ const infos = gpuFrameInfosFromLabels([
81
+ [CUDA_STALL_REASON_LABEL, 'smsp__pcsamp_warps_issue_stalled_long_scoreboard'],
82
+ [CUDA_SASS_INSTRUCTION_LABEL, 'STS'],
83
+ ]);
84
+ expect(infos.map(i => i.kind)).toEqual(['sass', 'stall']);
85
+ });
86
+
87
+ test('ignores non-cuda labels and unknown values', () => {
88
+ expect(gpuFrameInfosFromLabels([['service', 'api']])).toEqual([]);
89
+ expect(gpuFrameInfosFromLabels([[CUDA_SASS_INSTRUCTION_LABEL, 'NOT_A_REAL_OPCODE']])).toEqual(
90
+ []
91
+ );
92
+ expect(gpuFrameInfosFromLabels([])).toEqual([]);
93
+ });
94
+ });
@@ -530,27 +530,56 @@ function stallSourceUrl(name: string): string {
530
530
  return `${STALL_SOURCE_URL}:~:text=${encodeURIComponent(name)}`;
531
531
  }
532
532
 
533
+ // Node label keys under which GPU PC-sampling values now arrive. The SASS
534
+ // mnemonic and warp stall reason used to be the leaf frame's function name;
535
+ // they are now carried as node labels.
536
+ export const CUDA_SASS_INSTRUCTION_LABEL = 'cuda_sass_instruction';
537
+ export const CUDA_STALL_REASON_LABEL = 'cuda_stall_reason';
538
+
539
+ function sassInfo(name: string): GpuFrameInfo | undefined {
540
+ if (name === '') return undefined;
541
+ const sass = SASS_INSTRUCTION_DESCRIPTIONS[name];
542
+ if (sass === undefined) return undefined;
543
+ return {
544
+ kind: 'sass',
545
+ entry: sass,
546
+ sourceLabel: NVIDIA_DOCS_LABEL,
547
+ sourceUrl: sass.sourceUrl ?? SASS_SOURCE_URL,
548
+ };
549
+ }
550
+
551
+ function stallInfo(name: string): GpuFrameInfo | undefined {
552
+ if (name === '') return undefined;
553
+ const stall = STALL_REASON_DESCRIPTIONS[name];
554
+ if (stall === undefined) return undefined;
555
+ return {
556
+ kind: 'stall',
557
+ entry: stall,
558
+ sourceLabel: NVIDIA_DOCS_LABEL,
559
+ sourceUrl: stall.sourceUrl ?? stallSourceUrl(name),
560
+ };
561
+ }
562
+
533
563
  // Resolves a frame name to its GPU info, or undefined if not a known SASS
534
564
  // mnemonic or PC-sampling reason. Both tables are exact-match lookups.
535
565
  export function gpuFrameInfo(name: string): GpuFrameInfo | undefined {
536
- if (name === '') return undefined;
537
- const sass = SASS_INSTRUCTION_DESCRIPTIONS[name];
538
- if (sass !== undefined) {
539
- return {
540
- kind: 'sass',
541
- entry: sass,
542
- sourceLabel: NVIDIA_DOCS_LABEL,
543
- sourceUrl: sass.sourceUrl ?? SASS_SOURCE_URL,
544
- };
566
+ return sassInfo(name) ?? stallInfo(name);
567
+ }
568
+
569
+ // Resolves GPU info from a node's labels. A node may carry both a SASS
570
+ // instruction and a stall reason label, so this returns an array (SASS first,
571
+ // then stall) of the entries that matched a known description.
572
+ export function gpuFrameInfosFromLabels(labelPairs: Array<[string, string]>): GpuFrameInfo[] {
573
+ const infos: GpuFrameInfo[] = [];
574
+ const sassValue = labelPairs.find(([key]) => key === CUDA_SASS_INSTRUCTION_LABEL)?.[1];
575
+ const stallValue = labelPairs.find(([key]) => key === CUDA_STALL_REASON_LABEL)?.[1];
576
+ if (sassValue !== undefined) {
577
+ const info = sassInfo(sassValue);
578
+ if (info !== undefined) infos.push(info);
545
579
  }
546
- const stall = STALL_REASON_DESCRIPTIONS[name];
547
- if (stall !== undefined) {
548
- return {
549
- kind: 'stall',
550
- entry: stall,
551
- sourceLabel: NVIDIA_DOCS_LABEL,
552
- sourceUrl: stall.sourceUrl ?? stallSourceUrl(name),
553
- };
580
+ if (stallValue !== undefined) {
581
+ const info = stallInfo(stallValue);
582
+ if (info !== undefined) infos.push(info);
554
583
  }
555
- return undefined;
584
+ return infos;
556
585
  }
@@ -28,7 +28,7 @@ import {
28
28
  FIELD_MAPPING_FILE,
29
29
  FIELD_TIMESTAMP,
30
30
  } from '../../ProfileFlameGraph/FlameGraphArrow';
31
- import {arrowToString} from '../../ProfileFlameGraph/FlameGraphArrow/utils';
31
+ import {arrowToString, getLabelPairs} from '../../ProfileFlameGraph/FlameGraphArrow/utils';
32
32
  import {ProfileSource} from '../../ProfileSource';
33
33
  import {useProfileViewContext} from '../../ProfileView/context/ProfileViewContext';
34
34
  import {stringParam} from '../../hooks/urlParsers';
@@ -69,8 +69,6 @@ export const useGraphTooltipMetaInfo = ({table, row}: Props): GraphTooltipMetaIn
69
69
  const functionStartLine: bigint = table.getChild(FIELD_FUNCTION_START_LINE)?.get(row) ?? 0n;
70
70
  const lineNumber =
71
71
  locationLine !== 0n ? locationLine : functionStartLine !== 0n ? functionStartLine : undefined;
72
- const labelPrefix = 'labels.';
73
- const labelColumnNames = table.schema.fields.filter(field => field.name.startsWith(labelPrefix));
74
72
  const timestamp = table.getChild(FIELD_TIMESTAMP)?.get(row);
75
73
 
76
74
  const {queryServiceClient, enableSourcesView} = useParcaContext();
@@ -103,12 +101,7 @@ export const useGraphTooltipMetaInfo = ({table, row}: Props): GraphTooltipMetaIn
103
101
  };
104
102
  const file = getTextForFile();
105
103
 
106
- const labelPairs: Array<[string, string]> = labelColumnNames
107
- .map((field, i) => [
108
- labelColumnNames[i].name.slice(labelPrefix.length),
109
- arrowToString(table.getChild(field.name)?.get(row)) ?? '',
110
- ])
111
- .filter(value => value[1] !== '') as Array<[string, string]>;
104
+ const labelPairs: Array<[string, string]> = getLabelPairs(table, row);
112
105
 
113
106
  const {dashboardItems, setDashboardItems} = useDashboardItems();
114
107
 
@@ -173,7 +173,7 @@ export const getCurrentPathFrameData = (table: Table, row: number): CurrentPathF
173
173
  };
174
174
  };
175
175
 
176
- function getLabelSet(table: Table, row: number): string {
176
+ export function getLabelPairs(table: Table, row: number): Array<[string, string]> {
177
177
  const labelPrefix = 'labels.';
178
178
  const labelColumnNames = table.schema.fields.filter(field => field.name.startsWith(labelPrefix));
179
179
 
@@ -182,7 +182,11 @@ function getLabelSet(table: Table, row: number): string {
182
182
  labelColumnNames[i].name.slice(labelPrefix.length),
183
183
  arrowToString(table.getChild(field.name)?.get(row)) ?? '',
184
184
  ])
185
- .filter(value => value[1] !== '')
185
+ .filter(value => value[1] !== '') as Array<[string, string]>;
186
+ }
187
+
188
+ function getLabelSet(table: Table, row: number): string {
189
+ return getLabelPairs(table, row)
186
190
  .map(([k, v]) => `${k}="${v}"`)
187
191
  .join(', ');
188
192
  }
@@ -107,21 +107,23 @@ export const wellKnownProfiles: WellKnownProfiles = {
107
107
  name: 'Off-CPU',
108
108
  help: 'Time spent off the CPU as observed by the Parca Agent.',
109
109
  },
110
+ // deprecated with PC sampling
110
111
  'parca_agent:cuda:nanoseconds:cuda:nanoseconds:delta': {
111
112
  name: 'On-GPU',
112
113
  help: 'Time spent on the GPU.',
113
114
  },
115
+ // use this for combined PC stall and kernel timing, not the default
114
116
  'parca_agent:gpu_time:nanoseconds:gpu_time:nanoseconds:delta': {
115
117
  name: 'On-GPU',
116
118
  help: 'Time spent on the GPU. Combines kernel execution time and PC stall samples; the gpu_view label distinguishes the two views.',
117
119
  },
118
120
  'parca_agent:gpu_kernel_time:nanoseconds:gpu_kernel_time:nanoseconds:delta': {
119
- name: 'On-GPU',
121
+ name: 'GPU Kernels',
120
122
  help: 'GPU kernel execution time measured via CUDA runtime callbacks.',
121
123
  },
122
- 'parca_agent:gpu_stall_time:nanoseconds:gpu_stall_time:nanoseconds:delta': {
123
- name: 'GPU Stalls',
124
- help: 'GPU stall time accumulated from PC samplingshows where threads were waiting on the GPU.',
124
+ 'parca_agent:gpu_pcsample:count:gpu_pcsample:nanoseconds:delta': {
125
+ name: 'GPU Instructions',
126
+ help: 'PC samples from the GPUall PC activity, not just stalls; shows the instruction/stall reason.',
125
127
  },
126
128
  };
127
129