@parca/profile 0.16.198 → 0.16.199
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 +4 -0
- package/dist/Callgraph/index.d.ts +0 -1
- package/dist/GraphTooltip/ExpandOnHoverValue.d.ts +0 -1
- package/dist/GraphTooltip/index.d.ts +0 -1
- package/dist/GraphTooltipArrow/ExpandOnHoverValue.d.ts +6 -0
- package/dist/GraphTooltipArrow/ExpandOnHoverValue.js +4 -0
- package/dist/GraphTooltipArrow/index.d.ts +43 -0
- package/dist/GraphTooltipArrow/index.js +244 -0
- package/dist/MatchersInput/SuggestionItem.d.ts +0 -1
- package/dist/MatchersInput/SuggestionsList.d.ts +0 -1
- package/dist/MatchersInput/index.d.ts +0 -1
- package/dist/MetricsCircle/index.d.ts +0 -1
- package/dist/MetricsGraph/MetricsTooltip/index.d.ts +0 -1
- package/dist/MetricsGraph/index.d.ts +0 -1
- package/dist/MetricsSeries/index.d.ts +0 -1
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +0 -1
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +0 -1
- package/dist/ProfileExplorer/index.d.ts +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts +10 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.js +64 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +48 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +150 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +23 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +110 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.d.ts +14 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.js +26 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.d.ts +4 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +42 -0
- package/dist/ProfileIcicleGraph/index.d.ts +4 -3
- package/dist/ProfileIcicleGraph/index.js +7 -5
- package/dist/ProfileMetricsGraph/index.d.ts +0 -1
- package/dist/ProfileSelector/CompareButton.d.ts +0 -1
- package/dist/ProfileSelector/index.d.ts +0 -1
- package/dist/ProfileSource.d.ts +0 -1
- package/dist/ProfileTypeSelector/index.d.ts +0 -1
- package/dist/ProfileView/FilterByFunctionButton.d.ts +0 -1
- package/dist/ProfileView/ViewSelector.d.ts +0 -1
- package/dist/ProfileView/index.d.ts +2 -1
- package/dist/ProfileView/index.js +2 -2
- package/dist/ProfileViewWithData.d.ts +0 -1
- package/dist/ProfileViewWithData.js +15 -6
- package/dist/components/DiffLegend.d.ts +0 -1
- package/dist/components/ProfileShareButton/ResultBox.d.ts +0 -1
- package/dist/components/ProfileShareButton/index.d.ts +0 -1
- package/dist/styles.css +1 -1
- package/package.json +6 -5
- package/src/GraphTooltipArrow/ExpandOnHoverValue.tsx +30 -0
- package/src/GraphTooltipArrow/index.tsx +564 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.tsx +109 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +327 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +212 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.ts +52 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +51 -0
- package/src/ProfileIcicleGraph/index.tsx +34 -14
- package/src/ProfileView/index.tsx +4 -1
- package/src/ProfileViewWithData.tsx +20 -6
|
@@ -0,0 +1,51 @@
|
|
|
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 {Table} from 'apache-arrow';
|
|
15
|
+
|
|
16
|
+
import {EVERYTHING_ELSE, FEATURE_TYPES, type Feature} from '@parca/store';
|
|
17
|
+
import {getLastItem} from '@parca/utilities';
|
|
18
|
+
|
|
19
|
+
import {hexifyAddress} from '../../utils';
|
|
20
|
+
import {FIELD_FUNCTION_NAME, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE} from './index';
|
|
21
|
+
|
|
22
|
+
export function nodeLabel(table: Table<any>, row: number, showBinaryName: boolean): string {
|
|
23
|
+
const functionName: string | null = table.getChild(FIELD_FUNCTION_NAME)?.get(row);
|
|
24
|
+
if (functionName !== null && functionName !== '') {
|
|
25
|
+
return functionName;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let mappingString = '';
|
|
29
|
+
if (showBinaryName) {
|
|
30
|
+
const mappingFile: string | null = table.getChild(FIELD_MAPPING_FILE)?.get(row) ?? '';
|
|
31
|
+
const binary: string | undefined = getLastItem(mappingFile ?? undefined);
|
|
32
|
+
if (binary != null) mappingString = `[${binary}]`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const addressBigInt: bigint = table.getChild(FIELD_LOCATION_ADDRESS)?.get(row);
|
|
36
|
+
const address = hexifyAddress(addressBigInt);
|
|
37
|
+
const fallback = `${mappingString}${address}`;
|
|
38
|
+
return fallback === '' ? '<unknown>' : fallback;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const extractFeature = (mapping: string): Feature => {
|
|
42
|
+
if (mapping.startsWith('runtime') || mapping === 'root') {
|
|
43
|
+
return {name: 'runtime', type: FEATURE_TYPES.Runtime};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (mapping != null && mapping !== '') {
|
|
47
|
+
return {name: mapping, type: FEATURE_TYPES.Binary};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {name: EVERYTHING_ELSE, type: FEATURE_TYPES.Misc};
|
|
51
|
+
};
|
|
@@ -13,13 +13,16 @@
|
|
|
13
13
|
|
|
14
14
|
import {useEffect, useMemo} from 'react';
|
|
15
15
|
|
|
16
|
+
import {Table} from 'apache-arrow';
|
|
17
|
+
|
|
16
18
|
import {Flamegraph} from '@parca/client';
|
|
17
19
|
import {Button} from '@parca/components';
|
|
18
20
|
import {useContainerDimensions} from '@parca/hooks';
|
|
19
21
|
import {divide, selectQueryParam, type NavigateFunction} from '@parca/utilities';
|
|
20
22
|
|
|
21
23
|
import DiffLegend from '../components/DiffLegend';
|
|
22
|
-
import
|
|
24
|
+
import IcicleGraph from './IcicleGraph';
|
|
25
|
+
import IcicleGraphArrow from './IcicleGraphArrow';
|
|
23
26
|
|
|
24
27
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
25
28
|
|
|
@@ -27,7 +30,8 @@ export type ResizeHandler = (width: number, height: number) => void;
|
|
|
27
30
|
|
|
28
31
|
interface ProfileIcicleGraphProps {
|
|
29
32
|
width?: number;
|
|
30
|
-
graph
|
|
33
|
+
graph?: Flamegraph;
|
|
34
|
+
table?: Table<any>;
|
|
31
35
|
total: bigint;
|
|
32
36
|
filtered: bigint;
|
|
33
37
|
sampleUnit: string;
|
|
@@ -40,6 +44,7 @@ interface ProfileIcicleGraphProps {
|
|
|
40
44
|
|
|
41
45
|
const ProfileIcicleGraph = ({
|
|
42
46
|
graph,
|
|
47
|
+
table,
|
|
43
48
|
total,
|
|
44
49
|
filtered,
|
|
45
50
|
curPath,
|
|
@@ -66,7 +71,8 @@ const ProfileIcicleGraph = ({
|
|
|
66
71
|
return ['0', '0', false, '0', '0', false, '0', '0'];
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
const trimmed = graph.trimmed;
|
|
74
|
+
// const trimmed = graph.trimmed;
|
|
75
|
+
const trimmed = 0n;
|
|
70
76
|
|
|
71
77
|
const totalUnfiltered = total + filtered;
|
|
72
78
|
// safeguard against division by zero
|
|
@@ -101,7 +107,7 @@ const ProfileIcicleGraph = ({
|
|
|
101
107
|
);
|
|
102
108
|
}, [setNewCurPath, curPath, setActionButtons]);
|
|
103
109
|
|
|
104
|
-
if (graph === undefined) return <div>no data...</div>;
|
|
110
|
+
if (graph === undefined && table === undefined) return <div>no data...</div>;
|
|
105
111
|
|
|
106
112
|
if (total === 0n && !loading) return <>Profile has no samples</>;
|
|
107
113
|
|
|
@@ -113,16 +119,30 @@ const ProfileIcicleGraph = ({
|
|
|
113
119
|
<div className="relative">
|
|
114
120
|
{compareMode && <DiffLegend />}
|
|
115
121
|
<div ref={ref}>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
{graph !== undefined && (
|
|
123
|
+
<IcicleGraph
|
|
124
|
+
width={dimensions?.width}
|
|
125
|
+
graph={graph}
|
|
126
|
+
total={total}
|
|
127
|
+
filtered={filtered}
|
|
128
|
+
curPath={curPath}
|
|
129
|
+
setCurPath={setNewCurPath}
|
|
130
|
+
sampleUnit={sampleUnit}
|
|
131
|
+
navigateTo={navigateTo}
|
|
132
|
+
/>
|
|
133
|
+
)}
|
|
134
|
+
{table !== undefined && (
|
|
135
|
+
<IcicleGraphArrow
|
|
136
|
+
width={dimensions?.width}
|
|
137
|
+
table={table}
|
|
138
|
+
total={total}
|
|
139
|
+
filtered={filtered}
|
|
140
|
+
curPath={curPath}
|
|
141
|
+
setCurPath={setNewCurPath}
|
|
142
|
+
sampleUnit={sampleUnit}
|
|
143
|
+
navigateTo={navigateTo}
|
|
144
|
+
/>
|
|
145
|
+
)}
|
|
126
146
|
</div>
|
|
127
147
|
<p className="my-2 text-xs">
|
|
128
148
|
Showing {totalFormatted}{' '}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import {Profiler, ProfilerProps, useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
|
+
import {Table} from 'apache-arrow';
|
|
16
17
|
import cx from 'classnames';
|
|
17
18
|
import {scaleLinear} from 'd3';
|
|
18
19
|
import graphviz from 'graphviz-wasm';
|
|
@@ -53,6 +54,7 @@ type NavigateFunction = (path: string, queryParams: any, options?: {replace?: bo
|
|
|
53
54
|
export interface FlamegraphData {
|
|
54
55
|
loading: boolean;
|
|
55
56
|
data?: Flamegraph;
|
|
57
|
+
table?: Table<any>;
|
|
56
58
|
total?: bigint;
|
|
57
59
|
filtered?: bigint;
|
|
58
60
|
error?: any;
|
|
@@ -230,7 +232,7 @@ export const ProfileView = ({
|
|
|
230
232
|
}): JSX.Element => {
|
|
231
233
|
switch (type) {
|
|
232
234
|
case 'icicle': {
|
|
233
|
-
return flamegraphData?.data
|
|
235
|
+
return flamegraphData?.table !== undefined || flamegraphData.data !== undefined ? (
|
|
234
236
|
<ConditionalWrapper<ProfilerProps>
|
|
235
237
|
condition={perf?.onRender != null}
|
|
236
238
|
WrapperComponent={Profiler}
|
|
@@ -242,6 +244,7 @@ export const ProfileView = ({
|
|
|
242
244
|
<ProfileIcicleGraph
|
|
243
245
|
curPath={curPath}
|
|
244
246
|
setNewCurPath={setNewCurPath}
|
|
247
|
+
table={flamegraphData.table}
|
|
245
248
|
graph={flamegraphData.data}
|
|
246
249
|
total={total}
|
|
247
250
|
filtered={filtered}
|
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
|
|
14
14
|
import {useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
|
+
import {tableFromIPC} from 'apache-arrow';
|
|
17
|
+
|
|
16
18
|
import {QueryRequest_ReportType, QueryServiceClient} from '@parca/client';
|
|
17
19
|
import {useGrpcMetadata, useParcaContext, useURLState} from '@parca/components';
|
|
18
|
-
import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
|
|
20
|
+
import {USER_PREFERENCES, useUIFeatureFlag, useUserPreference} from '@parca/hooks';
|
|
19
21
|
import {saveAsBlob, type NavigateFunction} from '@parca/utilities';
|
|
20
22
|
|
|
21
23
|
import {ProfileSource} from './ProfileSource';
|
|
@@ -38,6 +40,7 @@ export const ProfileViewWithData = ({
|
|
|
38
40
|
const metadata = useGrpcMetadata();
|
|
39
41
|
const [dashboardItems] = useURLState({param: 'dashboard_items', navigateTo});
|
|
40
42
|
const [enableTrimming] = useUserPreference<boolean>(USER_PREFERENCES.ENABLE_GRAPH_TRIMMING.key);
|
|
43
|
+
const [arrowFlamegraphEnabled] = useUIFeatureFlag('flamegraph-arrow');
|
|
41
44
|
const [pprofDownloading, setPprofDownloading] = useState<boolean>(false);
|
|
42
45
|
|
|
43
46
|
const nodeTrimThreshold = useMemo(() => {
|
|
@@ -53,11 +56,15 @@ export const ProfileViewWithData = ({
|
|
|
53
56
|
return (1 / width) * 100;
|
|
54
57
|
}, [enableTrimming]);
|
|
55
58
|
|
|
59
|
+
const reportType = arrowFlamegraphEnabled
|
|
60
|
+
? QueryRequest_ReportType.FLAMEGRAPH_ARROW
|
|
61
|
+
: QueryRequest_ReportType.FLAMEGRAPH_TABLE;
|
|
62
|
+
|
|
56
63
|
const {
|
|
57
64
|
isLoading: flamegraphLoading,
|
|
58
65
|
response: flamegraphResponse,
|
|
59
66
|
error: flamegraphError,
|
|
60
|
-
} = useQuery(queryClient, profileSource,
|
|
67
|
+
} = useQuery(queryClient, profileSource, reportType, {
|
|
61
68
|
skip: !dashboardItems.includes('icicle'),
|
|
62
69
|
nodeTrimThreshold,
|
|
63
70
|
});
|
|
@@ -80,16 +87,19 @@ export const ProfileViewWithData = ({
|
|
|
80
87
|
});
|
|
81
88
|
|
|
82
89
|
useEffect(() => {
|
|
83
|
-
if (
|
|
84
|
-
|
|
90
|
+
if (
|
|
91
|
+
(!flamegraphLoading && flamegraphResponse?.report.oneofKind === 'flamegraph') ||
|
|
92
|
+
flamegraphResponse?.report.oneofKind === 'flamegraphArrow'
|
|
93
|
+
) {
|
|
94
|
+
perf?.markInteraction('Flamegraph render', flamegraphResponse.total);
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
if (!topTableLoading && topTableResponse?.report.oneofKind === 'top') {
|
|
88
|
-
perf?.markInteraction('Top table render', topTableResponse
|
|
98
|
+
perf?.markInteraction('Top table render', topTableResponse.total);
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
if (!callgraphLoading && callgraphResponse?.report.oneofKind === 'callgraph') {
|
|
92
|
-
perf?.markInteraction('Callgraph render', callgraphResponse
|
|
102
|
+
perf?.markInteraction('Callgraph render', callgraphResponse.total);
|
|
93
103
|
}
|
|
94
104
|
}, [
|
|
95
105
|
flamegraphLoading,
|
|
@@ -144,6 +154,10 @@ export const ProfileViewWithData = ({
|
|
|
144
154
|
flamegraphResponse?.report.oneofKind === 'flamegraph'
|
|
145
155
|
? flamegraphResponse?.report?.flamegraph
|
|
146
156
|
: undefined,
|
|
157
|
+
table:
|
|
158
|
+
flamegraphResponse?.report.oneofKind === 'flamegraphArrow'
|
|
159
|
+
? tableFromIPC(flamegraphResponse?.report?.flamegraphArrow.record)
|
|
160
|
+
: undefined,
|
|
147
161
|
total: BigInt(flamegraphResponse?.total ?? '0'),
|
|
148
162
|
filtered: BigInt(flamegraphResponse?.filtered ?? '0'),
|
|
149
163
|
error: flamegraphError,
|