@parca/profile 0.16.63 → 0.16.65

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.16.65 (2022-11-09)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.64](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.63...@parca/profile@0.16.64) (2022-11-08)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.16.63](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.62...@parca/profile@0.16.63) (2022-11-08)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -74,20 +74,29 @@ var TooltipMetaInfo = function (_a) {
74
74
  if (hoveringNode.meta === undefined)
75
75
  return _jsx(_Fragment, {});
76
76
  // populate meta from the flamegraph metadata tables
77
- if (locations !== undefined) {
78
- var location_1 = locations[hoveringNode.meta.locationIndex];
77
+ if (locations !== undefined &&
78
+ hoveringNode.meta.locationIndex !== undefined &&
79
+ hoveringNode.meta.locationIndex !== 0) {
80
+ var location_1 = locations[hoveringNode.meta.locationIndex - 1];
79
81
  hoveringNode.meta.location = location_1;
80
- if (mappings !== undefined) {
81
- var mapping = mappings[location_1.mappingIndex];
82
- if (strings !== undefined) {
83
- mapping.file = strings[mapping.fileStringIndex];
84
- mapping.buildId = strings[mapping.buildIdStringIndex];
82
+ if (location_1 !== undefined) {
83
+ if (mappings !== undefined &&
84
+ location_1.mappingIndex !== undefined &&
85
+ location_1.mappingIndex !== 0) {
86
+ var mapping = mappings[location_1.mappingIndex - 1];
87
+ if (strings !== undefined && mapping !== undefined) {
88
+ mapping.file =
89
+ (mapping === null || mapping === void 0 ? void 0 : mapping.fileStringIndex) !== undefined ? strings[mapping.fileStringIndex] : '';
90
+ mapping.buildId =
91
+ (mapping === null || mapping === void 0 ? void 0 : mapping.buildIdStringIndex) !== undefined ? strings[mapping.buildIdStringIndex] : '';
92
+ }
93
+ hoveringNode.meta.mapping = mapping;
85
94
  }
86
- hoveringNode.meta.mapping = mapping;
87
- }
88
- location_1.lines.forEach(function (line) {
89
- if (functions !== undefined && hoveringNode.meta !== undefined) {
90
- var func = functions[line.functionIndex];
95
+ if (functions !== undefined &&
96
+ location_1.lines !== undefined &&
97
+ hoveringNode.meta.lineIndex !== undefined &&
98
+ hoveringNode.meta.lineIndex < location_1.lines.length) {
99
+ var func = functions[location_1.lines[hoveringNode.meta.lineIndex].functionIndex - 1];
91
100
  if (strings !== undefined) {
92
101
  func.name = strings[func.nameStringIndex];
93
102
  func.systemName = strings[func.systemNameStringIndex];
@@ -95,7 +104,7 @@ var TooltipMetaInfo = function (_a) {
95
104
  }
96
105
  hoveringNode.meta.function = func;
97
106
  }
98
- });
107
+ }
99
108
  }
100
109
  var getTextForFile = function (hoveringNode) {
101
110
  var _a, _b, _c, _d;
@@ -56,14 +56,19 @@ function IcicleRect(_a) {
56
56
  } }), width > 5 && (_jsx("svg", __assign({ width: width - 5, height: height }, { children: _jsx("text", __assign({ x: 5, y: 15, style: { fontSize: '12px' } }, { children: name })) })))] })));
57
57
  }
58
58
  export function nodeLabel(node, strings, mappings, locations, functions) {
59
- var _a, _b;
59
+ var _a, _b, _c;
60
60
  if (((_a = node.meta) === null || _a === void 0 ? void 0 : _a.locationIndex) === undefined)
61
61
  return '<unknown>';
62
- var location = locations[node.meta.locationIndex];
63
- var mappingFile = strings[mappings[location.mappingIndex].fileStringIndex];
64
- var mappingString = "".concat(mappingFile !== '' ? '[' + ((_b = getLastItem(mappingFile)) !== null && _b !== void 0 ? _b : '') + '] ' : '');
62
+ if (((_b = node.meta) === null || _b === void 0 ? void 0 : _b.locationIndex) === 0)
63
+ return '<unknown>';
64
+ var location = locations[node.meta.locationIndex - 1];
65
+ var mapping = location.mappingIndex !== undefined || location.mappingIndex !== 0
66
+ ? mappings[location.mappingIndex - 1]
67
+ : undefined;
68
+ var mappingFile = (mapping === null || mapping === void 0 ? void 0 : mapping.fileStringIndex) !== undefined ? strings[mapping.fileStringIndex] : '';
69
+ var mappingString = "".concat(mappingFile !== '' ? '[' + ((_c = getLastItem(mappingFile)) !== null && _c !== void 0 ? _c : '') + '] ' : '');
65
70
  if (location.lines.length > 0) {
66
- var funcName = strings[functions[location.lines[0].functionIndex].nameStringIndex];
71
+ var funcName = strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
67
72
  return "".concat(mappingString, " ").concat(funcName);
68
73
  }
69
74
  var address = hexifyAddress(location.address);
@@ -27,7 +27,7 @@ import { Transition } from '@headlessui/react';
27
27
  import { Query } from '@parca/parser';
28
28
  import { usePopper } from 'react-popper';
29
29
  import cx from 'classnames';
30
- import { useParcaTheme, useGrpcMetadata } from '@parca/components';
30
+ import { useParcaContext, useGrpcMetadata } from '@parca/components';
31
31
  export var useLabelNames = function (client) {
32
32
  var _a = useState(true), loading = _a[0], setLoading = _a[1];
33
33
  var _b = useState({}), result = _b[0], setResult = _b[1];
@@ -73,7 +73,7 @@ var MatchersInput = function (_a) {
73
73
  placement: 'bottom-start',
74
74
  }), styles = _l.styles, attributes = _l.attributes;
75
75
  var metadata = useGrpcMetadata();
76
- var Spinner = useParcaTheme().loader;
76
+ var Spinner = useParcaContext().loader;
77
77
  var _m = useLabelNames(queryClient), labelNamesLoading = _m.loading, result = _m.result;
78
78
  var labelNamesResponse = result.response, labelNamesError = result.error;
79
79
  var LoadingSpinner = function () {
@@ -62,7 +62,7 @@ import { useState, useEffect } from 'react';
62
62
  import MetricsGraph from '../MetricsGraph';
63
63
  import { SingleProfileSelection } from '..';
64
64
  import { Timestamp } from '@parca/client';
65
- import { useGrpcMetadata, useParcaTheme } from '@parca/components';
65
+ import { useGrpcMetadata, useParcaContext } from '@parca/components';
66
66
  import { Query } from '@parca/parser';
67
67
  import useDelayedLoader from '../useDelayedLoader';
68
68
  export var useQueryRange = function (client, queryExpression, start, end) {
@@ -100,7 +100,7 @@ var ProfileMetricsGraph = function (_a) {
100
100
  var queryClient = _a.queryClient, queryExpression = _a.queryExpression, profile = _a.profile, from = _a.from, to = _a.to, select = _a.select, setTimeRange = _a.setTimeRange, addLabelMatcher = _a.addLabelMatcher;
101
101
  var _b = useQueryRange(queryClient, queryExpression, from, to), isLoading = _b.isLoading, response = _b.response, error = _b.error;
102
102
  var isLoaderVisible = useDelayedLoader(isLoading);
103
- var loader = useParcaTheme().loader;
103
+ var loader = useParcaContext().loader;
104
104
  if (isLoaderVisible) {
105
105
  return _jsx(_Fragment, { children: loader });
106
106
  }
@@ -22,18 +22,18 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
22
22
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
23
  // See the License for the specific language governing permissions and
24
24
  // limitations under the License.
25
- import { useEffect, useMemo, useState } from 'react';
25
+ import { Profiler, useEffect, useMemo, useState } from 'react';
26
+ import { scaleLinear } from 'd3';
26
27
  import { getNewSpanColor, parseParams } from '@parca/functions';
27
28
  import useUIFeatureFlag from '@parca/functions/useUIFeatureFlag';
28
- import { Button, Card, SearchNodes, useParcaTheme } from '@parca/components';
29
- import { Callgraph } from './';
29
+ import { Button, Card, SearchNodes, useParcaContext } from '@parca/components';
30
30
  import { useContainerDimensions } from '@parca/dynamicsize';
31
31
  import { useAppSelector, selectDarkMode, selectSearchNodeString } from '@parca/store';
32
+ import { Callgraph } from './';
32
33
  import ProfileShareButton from './components/ProfileShareButton';
33
34
  import ProfileIcicleGraph from './ProfileIcicleGraph';
34
35
  import TopTable from './TopTable';
35
36
  import useDelayedLoader from './useDelayedLoader';
36
- import { scaleLinear } from 'd3';
37
37
  import './ProfileView.styles.css';
38
38
  function arrayEquals(a, b) {
39
39
  return (Array.isArray(a) &&
@@ -63,7 +63,7 @@ export var ProfileView = function (_a) {
63
63
  var isDarkMode = useAppSelector(selectDarkMode);
64
64
  var currentSearchString = useAppSelector(selectSearchNodeString);
65
65
  var callgraphEnabled = useUIFeatureFlag('callgraph')[0];
66
- var loader = useParcaTheme().loader;
66
+ var _d = useParcaContext(), loader = _d.loader, perf = _d.perf;
67
67
  useEffect(function () {
68
68
  // Reset the current path when the profile source changes
69
69
  setCurPath([]);
@@ -115,5 +115,5 @@ export var ProfileView = function (_a) {
115
115
  return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "py-3" }, { children: _jsx(Card, { children: _jsxs(Card.Body, { children: [_jsxs("div", __assign({ className: "flex py-3 w-full" }, { children: [_jsxs("div", __assign({ className: "w-2/5 flex space-x-4" }, { children: [_jsxs("div", __assign({ className: "flex space-x-1" }, { children: [profileSource != null && queryClient != null ? (_jsx(ProfileShareButton, { queryRequest: profileSource.QueryRequest(), queryClient: queryClient })) : null, _jsx(Button, __assign({ color: "neutral", onClick: function (e) {
116
116
  e.preventDefault();
117
117
  onDownloadPProf();
118
- } }, { children: "Download pprof" }))] })), _jsx(SearchNodes, {})] })), _jsxs("div", __assign({ className: "flex ml-auto" }, { children: [_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ color: "neutral", onClick: resetIcicleGraph, disabled: curPath.length === 0, className: "whitespace-nowrap text-ellipsis" }, { children: "Reset View" })) })), callgraphEnabled ? (_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ variant: "".concat(currentView === 'callgraph' ? 'primary' : 'neutral'), onClick: function () { return switchProfileView('callgraph'); }, className: "whitespace-nowrap text-ellipsis" }, { children: "Callgraph" })) }))) : null, _jsx(Button, __assign({ variant: "".concat(currentView === 'table' ? 'primary' : 'neutral'), className: "items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('table'); } }, { children: "Table" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'both' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-tr-none rounded-bl-none rounded-br-none border-l-0 border-r-0 w-auto px-8 whitespace-nowrap no-outline-on-buttons text-ellipsis", onClick: function () { return switchProfileView('both'); } }, { children: "Both" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'icicle' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('icicle'); } }, { children: "Icicle Graph" }))] }))] })), _jsxs("div", __assign({ ref: ref, className: "flex space-x-4 justify-between w-full" }, { children: [currentView === 'icicle' && (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit }) }))), currentView === 'callgraph' && (callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== undefined && (_jsx(Callgraph, { graph: callgraphData.data, sampleUnit: sampleUnit, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, colorRange: colorRange })) }))), currentView === 'table' && topTableData != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(TopTable, { data: topTableData.data, sampleUnit: sampleUnit }) }))), currentView === 'both' && (_jsxs(_Fragment, { children: [_jsx("div", __assign({ className: "w-1/2" }, { children: _jsx(TopTable, { data: topTableData === null || topTableData === void 0 ? void 0 : topTableData.data, sampleUnit: sampleUnit }) })), _jsx("div", __assign({ className: "w-1/2" }, { children: flamegraphData != null && (_jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit })) }))] }))] }))] }) }) })) }));
118
+ } }, { children: "Download pprof" }))] })), _jsx(SearchNodes, {})] })), _jsxs("div", __assign({ className: "flex ml-auto" }, { children: [_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ color: "neutral", onClick: resetIcicleGraph, disabled: curPath.length === 0, className: "whitespace-nowrap text-ellipsis" }, { children: "Reset View" })) })), callgraphEnabled ? (_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ variant: "".concat(currentView === 'callgraph' ? 'primary' : 'neutral'), onClick: function () { return switchProfileView('callgraph'); }, className: "whitespace-nowrap text-ellipsis" }, { children: "Callgraph" })) }))) : null, _jsx(Button, __assign({ variant: "".concat(currentView === 'table' ? 'primary' : 'neutral'), className: "items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('table'); } }, { children: "Table" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'both' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-tr-none rounded-bl-none rounded-br-none border-l-0 border-r-0 w-auto px-8 whitespace-nowrap no-outline-on-buttons text-ellipsis", onClick: function () { return switchProfileView('both'); } }, { children: "Both" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'icicle' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('icicle'); } }, { children: "Icicle Graph" }))] }))] })), _jsxs("div", __assign({ ref: ref, className: "flex space-x-4 justify-between w-full" }, { children: [currentView === 'icicle' && (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(Profiler, __assign({ id: "icicleGraph", onRender: perf.onRender }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit }) })) }))), currentView === 'callgraph' && (callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== undefined && (_jsx(Callgraph, { graph: callgraphData.data, sampleUnit: sampleUnit, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, colorRange: colorRange })) }))), currentView === 'table' && topTableData != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(TopTable, { data: topTableData.data, sampleUnit: sampleUnit }) }))), currentView === 'both' && (_jsxs(_Fragment, { children: [_jsx("div", __assign({ className: "w-1/2" }, { children: _jsx(TopTable, { data: topTableData === null || topTableData === void 0 ? void 0 : topTableData.data, sampleUnit: sampleUnit }) })), _jsx("div", __assign({ className: "w-1/2" }, { children: flamegraphData != null && (_jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit })) }))] }))] }))] }) }) })) }));
119
119
  };
@@ -51,8 +51,9 @@ import { QueryRequest_ReportType } from '@parca/client';
51
51
  import { useQuery } from './useQuery';
52
52
  import { ProfileView, useProfileVisState } from './ProfileView';
53
53
  import { downloadPprof } from './utils';
54
- import { useGrpcMetadata } from '@parca/components';
54
+ import { useGrpcMetadata, useParcaContext } from '@parca/components';
55
55
  import { saveAsBlob } from '@parca/functions';
56
+ import { useEffect } from 'react';
56
57
  export var ProfileViewWithData = function (_a) {
57
58
  var _b, _c;
58
59
  var queryClient = _a.queryClient, profileSource = _a.profileSource, navigateTo = _a.navigateTo;
@@ -62,6 +63,13 @@ export var ProfileViewWithData = function (_a) {
62
63
  var _d = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_TABLE, {
63
64
  skip: currentView !== 'icicle' && currentView !== 'both',
64
65
  }), flamegraphLoading = _d.isLoading, flamegraphResponse = _d.response, flamegraphError = _d.error;
66
+ var perf = useParcaContext().perf;
67
+ useEffect(function () {
68
+ if (flamegraphLoading) {
69
+ return;
70
+ }
71
+ perf.markInteraction('Flamegraph Render');
72
+ }, [flamegraphLoading, flamegraphResponse, perf]);
65
73
  var _e = useQuery(queryClient, profileSource, QueryRequest_ReportType.TOP, {
66
74
  skip: currentView !== 'table' && currentView !== 'both',
67
75
  }), topTableLoading = _e.isLoading, topTableResponse = _e.response, topTableError = _e.error;
package/dist/useQuery.js CHANGED
@@ -30,7 +30,6 @@ export var useQuery = function (client, profileSource, reportType, options) {
30
30
  isLoading: true,
31
31
  });
32
32
  var req = profileSource.QueryRequest();
33
- console.log('req', req);
34
33
  req.reportType = reportType;
35
34
  var call = client.query(req, { meta: metadata });
36
35
  call.response
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.16.63",
3
+ "version": "0.16.65",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@iconify/react": "^3.2.2",
7
- "@parca/client": "^0.16.53",
8
- "@parca/components": "^0.16.58",
7
+ "@parca/client": "^0.16.54",
8
+ "@parca/components": "^0.16.60",
9
9
  "@parca/dynamicsize": "^0.16.51",
10
10
  "@parca/functions": "^0.16.51",
11
11
  "@parca/parser": "^0.16.50",
@@ -40,5 +40,5 @@
40
40
  "access": "public",
41
41
  "registry": "https://registry.npmjs.org/"
42
42
  },
43
- "gitHead": "a244d1d0c99589df268a4d93a56c9c67cce6236f"
43
+ "gitHead": "0b1285b6be9aee7b2716d230e1d4bdc5a0cea4d2"
44
44
  }
@@ -19,12 +19,7 @@ import {CallgraphNode, FlamegraphNode, FlamegraphNodeMeta, FlamegraphRootNode} f
19
19
  import {getLastItem, valueFormatter} from '@parca/functions';
20
20
  import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
21
21
  import {hexifyAddress, truncateString} from '../';
22
- import {
23
- Function,
24
- Location,
25
- Mapping,
26
- Line,
27
- } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
22
+ import {Function, Location, Mapping} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
28
23
 
29
24
  interface GraphTooltipProps {
30
25
  x: number;
@@ -86,22 +81,37 @@ const TooltipMetaInfo = ({
86
81
  if (hoveringNode.meta === undefined) return <></>;
87
82
 
88
83
  // populate meta from the flamegraph metadata tables
89
- if (locations !== undefined) {
90
- const location = locations[hoveringNode.meta.locationIndex];
84
+ if (
85
+ locations !== undefined &&
86
+ hoveringNode.meta.locationIndex !== undefined &&
87
+ hoveringNode.meta.locationIndex !== 0
88
+ ) {
89
+ const location = locations[hoveringNode.meta.locationIndex - 1];
91
90
  hoveringNode.meta.location = location;
92
91
 
93
- if (mappings !== undefined) {
94
- const mapping = mappings[location.mappingIndex];
95
- if (strings !== undefined) {
96
- mapping.file = strings[mapping.fileStringIndex];
97
- mapping.buildId = strings[mapping.buildIdStringIndex];
92
+ if (location !== undefined) {
93
+ if (
94
+ mappings !== undefined &&
95
+ location.mappingIndex !== undefined &&
96
+ location.mappingIndex !== 0
97
+ ) {
98
+ const mapping = mappings[location.mappingIndex - 1];
99
+ if (strings !== undefined && mapping !== undefined) {
100
+ mapping.file =
101
+ mapping?.fileStringIndex !== undefined ? strings[mapping.fileStringIndex] : '';
102
+ mapping.buildId =
103
+ mapping?.buildIdStringIndex !== undefined ? strings[mapping.buildIdStringIndex] : '';
104
+ }
105
+ hoveringNode.meta.mapping = mapping;
98
106
  }
99
- hoveringNode.meta.mapping = mapping;
100
- }
101
107
 
102
- location.lines.forEach((line: Line) => {
103
- if (functions !== undefined && hoveringNode.meta !== undefined) {
104
- const func = functions[line.functionIndex];
108
+ if (
109
+ functions !== undefined &&
110
+ location.lines !== undefined &&
111
+ hoveringNode.meta.lineIndex !== undefined &&
112
+ hoveringNode.meta.lineIndex < location.lines.length
113
+ ) {
114
+ const func = functions[location.lines[hoveringNode.meta.lineIndex].functionIndex - 1];
105
115
  if (strings !== undefined) {
106
116
  func.name = strings[func.nameStringIndex];
107
117
  func.systemName = strings[func.systemNameStringIndex];
@@ -109,7 +119,7 @@ const TooltipMetaInfo = ({
109
119
  }
110
120
  hoveringNode.meta.function = func;
111
121
  }
112
- });
122
+ }
113
123
  }
114
124
 
115
125
  const getTextForFile = (hoveringNode: FlamegraphNode): string => {
@@ -149,16 +149,24 @@ export function nodeLabel(
149
149
  functions: Function[]
150
150
  ): string {
151
151
  if (node.meta?.locationIndex === undefined) return '<unknown>';
152
+ if (node.meta?.locationIndex === 0) return '<unknown>';
152
153
 
153
- const location = locations[node.meta.locationIndex];
154
- const mappingFile = strings[mappings[location.mappingIndex].fileStringIndex];
154
+ const location = locations[node.meta.locationIndex - 1];
155
+ const mapping =
156
+ location.mappingIndex !== undefined || location.mappingIndex !== 0
157
+ ? mappings[location.mappingIndex - 1]
158
+ : undefined;
159
+
160
+ const mappingFile =
161
+ mapping?.fileStringIndex !== undefined ? strings[mapping.fileStringIndex] : '';
155
162
 
156
163
  const mappingString: string = `${
157
164
  mappingFile !== '' ? '[' + (getLastItem(mappingFile) ?? '') + '] ' : ''
158
165
  }`;
159
166
 
160
167
  if (location.lines.length > 0) {
161
- const funcName = strings[functions[location.lines[0].functionIndex].nameStringIndex];
168
+ const funcName =
169
+ strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
162
170
  return `${mappingString} ${funcName}`;
163
171
  }
164
172
 
@@ -17,7 +17,8 @@ import {Query} from '@parca/parser';
17
17
  import {LabelsResponse, QueryServiceClient} from '@parca/client';
18
18
  import {usePopper} from 'react-popper';
19
19
  import cx from 'classnames';
20
- import {useParcaTheme, useGrpcMetadata} from '@parca/components';
20
+
21
+ import {useParcaContext, useGrpcMetadata} from '@parca/components';
21
22
 
22
23
  interface MatchersInputProps {
23
24
  queryClient: QueryServiceClient;
@@ -97,7 +98,7 @@ const MatchersInput = ({
97
98
  placement: 'bottom-start',
98
99
  });
99
100
  const metadata = useGrpcMetadata();
100
- const {loader: Spinner} = useParcaTheme();
101
+ const {loader: Spinner} = useParcaContext();
101
102
 
102
103
  const {loading: labelNamesLoading, result} = useLabelNames(queryClient);
103
104
  const {response: labelNamesResponse, error: labelNamesError} = result;
@@ -16,7 +16,7 @@ import MetricsGraph from '../MetricsGraph';
16
16
  import {ProfileSelection, SingleProfileSelection} from '..';
17
17
  import {QueryServiceClient, QueryRangeResponse, Label, Timestamp} from '@parca/client';
18
18
  import {RpcError} from '@protobuf-ts/runtime-rpc';
19
- import {DateTimeRange, useGrpcMetadata, useParcaTheme} from '@parca/components';
19
+ import {DateTimeRange, useGrpcMetadata, useParcaContext} from '@parca/components';
20
20
  import {Query} from '@parca/parser';
21
21
  import useDelayedLoader from '../useDelayedLoader';
22
22
 
@@ -89,7 +89,7 @@ const ProfileMetricsGraph = ({
89
89
  }: ProfileMetricsGraphProps): JSX.Element => {
90
90
  const {isLoading, response, error} = useQueryRange(queryClient, queryExpression, from, to);
91
91
  const isLoaderVisible = useDelayedLoader(isLoading);
92
- const {loader} = useParcaTheme();
92
+ const {loader} = useParcaContext();
93
93
 
94
94
  if (isLoaderVisible) {
95
95
  return <>{loader}</>;
@@ -11,22 +11,22 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import React, {useEffect, useMemo, useState} from 'react';
14
+ import {Profiler, useEffect, useMemo, useState} from 'react';
15
+ import {scaleLinear} from 'd3';
15
16
 
16
17
  import {getNewSpanColor, parseParams} from '@parca/functions';
17
18
  import useUIFeatureFlag from '@parca/functions/useUIFeatureFlag';
18
19
  import {QueryServiceClient, Flamegraph, Top, Callgraph as CallgraphType} from '@parca/client';
19
- import {Button, Card, SearchNodes, useParcaTheme} from '@parca/components';
20
- import {Callgraph} from './';
20
+ import {Button, Card, SearchNodes, useParcaContext} from '@parca/components';
21
21
  import {useContainerDimensions} from '@parca/dynamicsize';
22
22
  import {useAppSelector, selectDarkMode, selectSearchNodeString} from '@parca/store';
23
23
 
24
+ import {Callgraph} from './';
24
25
  import ProfileShareButton from './components/ProfileShareButton';
25
26
  import ProfileIcicleGraph from './ProfileIcicleGraph';
26
27
  import {ProfileSource} from './ProfileSource';
27
28
  import TopTable from './TopTable';
28
29
  import useDelayedLoader from './useDelayedLoader';
29
- import {scaleLinear} from 'd3';
30
30
 
31
31
  import './ProfileView.styles.css';
32
32
 
@@ -114,7 +114,7 @@ export const ProfileView = ({
114
114
 
115
115
  const [callgraphEnabled] = useUIFeatureFlag('callgraph');
116
116
 
117
- const {loader} = useParcaTheme();
117
+ const {loader, perf} = useParcaContext();
118
118
 
119
119
  useEffect(() => {
120
120
  // Reset the current path when the profile source changes
@@ -265,12 +265,14 @@ export const ProfileView = ({
265
265
  <div ref={ref} className="flex space-x-4 justify-between w-full">
266
266
  {currentView === 'icicle' && flamegraphData?.data != null && (
267
267
  <div className="w-full">
268
- <ProfileIcicleGraph
269
- curPath={curPath}
270
- setNewCurPath={setNewCurPath}
271
- graph={flamegraphData.data}
272
- sampleUnit={sampleUnit}
273
- />
268
+ <Profiler id="icicleGraph" onRender={perf.onRender}>
269
+ <ProfileIcicleGraph
270
+ curPath={curPath}
271
+ setNewCurPath={setNewCurPath}
272
+ graph={flamegraphData.data}
273
+ sampleUnit={sampleUnit}
274
+ />
275
+ </Profiler>
274
276
  </div>
275
277
  )}
276
278
  {currentView === 'callgraph' && callgraphData?.data != null && (
@@ -17,8 +17,9 @@ import {useQuery} from './useQuery';
17
17
  import {ProfileView, useProfileVisState} from './ProfileView';
18
18
  import {ProfileSource} from './ProfileSource';
19
19
  import {downloadPprof} from './utils';
20
- import {useGrpcMetadata} from '@parca/components';
20
+ import {useGrpcMetadata, useParcaContext} from '@parca/components';
21
21
  import {saveAsBlob} from '@parca/functions';
22
+ import {useEffect} from 'react';
22
23
 
23
24
  type NavigateFunction = (path: string, queryParams: any) => void;
24
25
 
@@ -44,6 +45,14 @@ export const ProfileViewWithData = ({
44
45
  } = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_TABLE, {
45
46
  skip: currentView !== 'icicle' && currentView !== 'both',
46
47
  });
48
+ const {perf} = useParcaContext();
49
+
50
+ useEffect(() => {
51
+ if (flamegraphLoading) {
52
+ return;
53
+ }
54
+ perf.markInteraction('Flamegraph Render');
55
+ }, [flamegraphLoading, flamegraphResponse, perf]);
47
56
 
48
57
  const {
49
58
  isLoading: topTableLoading,
package/src/useQuery.tsx CHANGED
@@ -53,7 +53,6 @@ export const useQuery = (
53
53
  isLoading: true,
54
54
  });
55
55
  const req = profileSource.QueryRequest();
56
- console.log('req', req);
57
56
  req.reportType = reportType;
58
57
 
59
58
  const call = client.query(req, {meta: metadata});