@parca/profile 0.16.0 → 0.16.22
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 +40 -0
- package/dist/Callgraph/Edge/index.d.ts +22 -0
- package/dist/Callgraph/Edge/index.js +30 -0
- package/dist/Callgraph/Node/index.d.ts +19 -0
- package/dist/Callgraph/Node/index.js +37 -0
- package/dist/Callgraph/index.d.ts +8 -0
- package/dist/Callgraph/index.js +137 -0
- package/dist/Callgraph/mockData/index.d.ts +148 -0
- package/dist/Callgraph/mockData/index.js +577 -0
- package/dist/Callgraph/utils.d.ts +19 -0
- package/dist/Callgraph/utils.js +82 -0
- package/dist/GraphTooltip/index.d.ts +19 -0
- package/dist/GraphTooltip/index.js +119 -0
- package/dist/IcicleGraph.d.ts +35 -0
- package/dist/IcicleGraph.js +139 -0
- package/dist/MatchersInput/index.d.ts +23 -0
- package/dist/MatchersInput/index.js +479 -0
- package/dist/MetricsCircle/index.d.ts +7 -0
- package/dist/MetricsCircle/index.js +18 -0
- package/dist/MetricsGraph/index.d.ts +35 -0
- package/dist/MetricsGraph/index.js +349 -0
- package/dist/MetricsSeries/index.d.ts +11 -0
- package/dist/MetricsSeries/index.js +21 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +19 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +38 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +15 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +19 -0
- package/dist/ProfileExplorer/index.d.ts +9 -0
- package/dist/ProfileExplorer/index.js +203 -0
- package/dist/ProfileIcicleGraph.d.ts +10 -0
- package/dist/ProfileIcicleGraph.js +28 -0
- package/dist/ProfileMetricsGraph/index.d.ts +22 -0
- package/dist/ProfileMetricsGraph/index.js +127 -0
- package/dist/ProfileSVG.module.css +3 -0
- package/dist/ProfileSelector/CompareButton.d.ts +5 -0
- package/dist/ProfileSelector/CompareButton.js +41 -0
- package/dist/ProfileSelector/MergeButton.d.ts +5 -0
- package/dist/ProfileSelector/MergeButton.js +41 -0
- package/dist/ProfileSelector/index.d.ts +29 -0
- package/dist/ProfileSelector/index.js +133 -0
- package/dist/ProfileSource.d.ts +88 -0
- package/dist/ProfileSource.js +239 -0
- package/dist/ProfileTypeSelector/index.d.ts +20 -0
- package/dist/ProfileTypeSelector/index.js +138 -0
- package/dist/ProfileView.d.ts +39 -0
- package/dist/ProfileView.js +111 -0
- package/dist/ProfileView.styles.css +3 -0
- package/dist/ProfileViewWithData.d.ts +11 -0
- package/dist/ProfileViewWithData.js +116 -0
- package/dist/TopTable.d.ts +9 -0
- package/dist/TopTable.js +140 -0
- package/dist/TopTable.styles.css +7 -0
- package/dist/components/DiffLegend.d.ts +2 -0
- package/dist/components/DiffLegend.js +62 -0
- package/dist/components/ProfileShareButton/ResultBox.d.ts +6 -0
- package/dist/components/ProfileShareButton/ResultBox.js +46 -0
- package/dist/components/ProfileShareButton/index.d.ts +7 -0
- package/dist/components/ProfileShareButton/index.js +119 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +64 -0
- package/dist/styles.css +1 -0
- package/dist/useDelayedLoader.d.ts +5 -0
- package/dist/useDelayedLoader.js +33 -0
- package/dist/useQuery.d.ts +13 -0
- package/dist/useQuery.js +41 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +83 -0
- package/package.json +12 -8
- package/src/Callgraph/Edge/index.tsx +59 -0
- package/src/Callgraph/Node/index.tsx +66 -0
- package/src/Callgraph/index.tsx +169 -0
- package/src/Callgraph/mockData/index.ts +605 -0
- package/src/Callgraph/utils.ts +116 -0
- package/src/GraphTooltip/index.tsx +245 -0
- package/src/IcicleGraph.tsx +3 -3
- package/src/MatchersInput/index.tsx +698 -0
- package/src/MetricsCircle/index.tsx +28 -0
- package/src/MetricsGraph/index.tsx +614 -0
- package/src/MetricsSeries/index.tsx +38 -0
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +109 -0
- package/src/ProfileExplorer/ProfileExplorerSingle.tsx +72 -0
- package/src/ProfileExplorer/index.tsx +377 -0
- package/src/ProfileMetricsGraph/index.tsx +143 -0
- package/src/ProfileSelector/CompareButton.tsx +72 -0
- package/src/ProfileSelector/MergeButton.tsx +72 -0
- package/src/ProfileSelector/index.tsx +270 -0
- package/src/ProfileTypeSelector/index.tsx +180 -0
- package/src/ProfileView.tsx +2 -7
- package/src/index.tsx +11 -0
- package/src/useQuery.tsx +1 -0
- package/tailwind.config.js +8 -0
- package/tsconfig.json +7 -3
- package/typings.d.ts +14 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
|
+
// Copyright 2022 The Parca Authors
|
|
14
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
// you may not use this file except in compliance with the License.
|
|
16
|
+
// You may obtain a copy of the License at
|
|
17
|
+
//
|
|
18
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
//
|
|
20
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
// See the License for the specific language governing permissions and
|
|
24
|
+
// limitations under the License.
|
|
25
|
+
import { Query } from '@parca/parser';
|
|
26
|
+
import { useEffect, useState } from 'react';
|
|
27
|
+
import ProfileMetricsGraph from '../ProfileMetricsGraph';
|
|
28
|
+
import MatchersInput from '../MatchersInput/index';
|
|
29
|
+
import MergeButton from './MergeButton';
|
|
30
|
+
import CompareButton from './CompareButton';
|
|
31
|
+
import { Card, DateTimeRangePicker, DateTimeRange, Button, ButtonGroup, useGrpcMetadata, } from '@parca/components';
|
|
32
|
+
import { CloseIcon } from '@parca/icons';
|
|
33
|
+
import cx from 'classnames';
|
|
34
|
+
import ProfileTypeSelector from '../ProfileTypeSelector/index';
|
|
35
|
+
export var useProfileTypes = function (client) {
|
|
36
|
+
var _a = useState(undefined), result = _a[0], setResult = _a[1];
|
|
37
|
+
var _b = useState(undefined), error = _b[0], setError = _b[1];
|
|
38
|
+
var _c = useState(true), loading = _c[0], setLoading = _c[1];
|
|
39
|
+
var metadata = useGrpcMetadata();
|
|
40
|
+
useEffect(function () {
|
|
41
|
+
if (!loading) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
var call = client.profileTypes({}, { meta: metadata });
|
|
45
|
+
call.response
|
|
46
|
+
.then(function (response) { return setResult(response); })
|
|
47
|
+
.catch(function (error) { return setError(error); })
|
|
48
|
+
.finally(function () { return setLoading(false); });
|
|
49
|
+
}, [client, metadata, loading]);
|
|
50
|
+
return { loading: loading, data: result, error: error };
|
|
51
|
+
};
|
|
52
|
+
var ProfileSelector = function (_a) {
|
|
53
|
+
var queryClient = _a.queryClient, querySelection = _a.querySelection, selectProfile = _a.selectProfile, selectQuery = _a.selectQuery, closeProfile = _a.closeProfile, enforcedProfileName = _a.enforcedProfileName, profileSelection = _a.profileSelection, comparing = _a.comparing, onCompareProfile = _a.onCompareProfile;
|
|
54
|
+
var _b = useProfileTypes(queryClient), profileTypesLoading = _b.loading, profileTypesData = _b.data, error = _b.error;
|
|
55
|
+
var _c = useState(DateTimeRange.fromRangeKey(querySelection.timeSelection)), timeRangeSelection = _c[0], setTimeRangeSelection = _c[1];
|
|
56
|
+
var _d = useState(querySelection.expression), queryExpressionString = _d[0], setQueryExpressionString = _d[1];
|
|
57
|
+
useEffect(function () {
|
|
58
|
+
if (enforcedProfileName !== '') {
|
|
59
|
+
var _a = Query.parse(querySelection.expression).setProfileName(enforcedProfileName), q = _a[0], changed = _a[1];
|
|
60
|
+
if (changed) {
|
|
61
|
+
setQueryExpressionString(q.toString());
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
setQueryExpressionString(querySelection.expression);
|
|
66
|
+
}, [enforcedProfileName, querySelection.expression]);
|
|
67
|
+
var enforcedProfileNameQuery = function () {
|
|
68
|
+
var pq = Query.parse(queryExpressionString);
|
|
69
|
+
var q = pq.setProfileName(enforcedProfileName)[0];
|
|
70
|
+
return q;
|
|
71
|
+
};
|
|
72
|
+
var query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(queryExpressionString);
|
|
73
|
+
var selectedProfileName = query.profileName();
|
|
74
|
+
var setNewQueryExpression = function (expr, merge) {
|
|
75
|
+
selectQuery({
|
|
76
|
+
expression: expr,
|
|
77
|
+
from: timeRangeSelection.getFromMs(),
|
|
78
|
+
to: timeRangeSelection.getToMs(),
|
|
79
|
+
merge: merge,
|
|
80
|
+
timeSelection: timeRangeSelection.getRangeKey(),
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
var setQueryExpression = function () {
|
|
84
|
+
setNewQueryExpression(query.toString(), false);
|
|
85
|
+
};
|
|
86
|
+
var addLabelMatcher = function (key, value) {
|
|
87
|
+
var _a = Query.parse(queryExpressionString).setMatcher(key, value), newQuery = _a[0], changed = _a[1];
|
|
88
|
+
if (changed) {
|
|
89
|
+
setNewQueryExpression(newQuery.toString(), false);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
var setMergedSelection = function () {
|
|
93
|
+
setNewQueryExpression(queryExpressionString, true);
|
|
94
|
+
};
|
|
95
|
+
var setMatchersString = function (matchers) {
|
|
96
|
+
var newExpressionString = "".concat(selectedProfileName, "{").concat(matchers, "}");
|
|
97
|
+
setQueryExpressionString(newExpressionString);
|
|
98
|
+
};
|
|
99
|
+
var setProfileName = function (profileName) {
|
|
100
|
+
if (profileName === undefined) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
var _a = query.setProfileName(profileName), newQuery = _a[0], changed = _a[1];
|
|
104
|
+
if (changed) {
|
|
105
|
+
var q = newQuery.toString();
|
|
106
|
+
setQueryExpressionString(q);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
var handleCompareClick = function () { return onCompareProfile(); };
|
|
110
|
+
var searchDisabled = queryExpressionString === undefined ||
|
|
111
|
+
queryExpressionString === '' ||
|
|
112
|
+
queryExpressionString === '{}';
|
|
113
|
+
var mergeDisabled = selectedProfileName === '' || querySelection.expression === undefined;
|
|
114
|
+
var compareDisabled = selectedProfileName === '' || querySelection.expression === undefined;
|
|
115
|
+
return (_jsxs(Card, { children: [_jsx(Card.Header, __assign({ className: cx(comparing && 'overflow-x-scroll') }, { children: _jsxs("div", __assign({ className: "flex space-x-4" }, { children: [comparing && (_jsx("button", __assign({ type: "button", onClick: function () { return closeProfile(); } }, { children: _jsx(CloseIcon, {}) }))), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: error }), _jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query }), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), searchDisabled ? (_jsx("div", { children: _jsx(Button, __assign({ disabled: true }, { children: "Search" })) })) : (_jsxs(_Fragment, { children: [_jsxs(ButtonGroup, __assign({ style: { marginRight: 5 } }, { children: [_jsx(MergeButton, { disabled: mergeDisabled, onClick: setMergedSelection }), !comparing && (_jsx(CompareButton, { disabled: compareDisabled, onClick: handleCompareClick }))] })), _jsx("div", { children: _jsx(Button, __assign({ onClick: function (e) {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
setQueryExpression();
|
|
118
|
+
} }, { children: "Search" })) })] }))] })) })), !querySelection.merge && (_jsx(Card.Body, { children: querySelection.expression !== undefined &&
|
|
119
|
+
querySelection.expression.length > 0 &&
|
|
120
|
+
querySelection.from !== undefined &&
|
|
121
|
+
querySelection.to !== undefined &&
|
|
122
|
+
(profileSelection == null || profileSelection.Type() !== 'merge') ? (_jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, select: selectProfile, profile: profileSelection, setTimeRange: function (range) {
|
|
123
|
+
setTimeRangeSelection(range);
|
|
124
|
+
selectQuery({
|
|
125
|
+
expression: queryExpressionString,
|
|
126
|
+
from: range.getFromMs(),
|
|
127
|
+
to: range.getToMs(),
|
|
128
|
+
merge: false,
|
|
129
|
+
timeSelection: range.getRangeKey(),
|
|
130
|
+
});
|
|
131
|
+
}, addLabelMatcher: addLabelMatcher })) : (_jsx(_Fragment, { children: (profileSelection == null || profileSelection.Type() !== 'merge') && (_jsx("div", __assign({ className: "my-20 text-center" }, { children: _jsx("p", { children: "Run a query, and the result will be displayed here." }) }))) })) }))] }));
|
|
132
|
+
};
|
|
133
|
+
export default ProfileSelector;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ProfileType } from '@parca/parser';
|
|
2
|
+
import { Label, QueryRequest, ProfileDiffSelection } from '@parca/client';
|
|
3
|
+
export interface ProfileSource {
|
|
4
|
+
QueryRequest: () => QueryRequest;
|
|
5
|
+
ProfileType: () => ProfileType;
|
|
6
|
+
DiffSelection: () => ProfileDiffSelection;
|
|
7
|
+
Describe: () => JSX.Element;
|
|
8
|
+
toString: () => string;
|
|
9
|
+
}
|
|
10
|
+
export interface ProfileSelection {
|
|
11
|
+
ProfileName: () => string;
|
|
12
|
+
HistoryParams: () => {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
};
|
|
15
|
+
ProfileSource: () => ProfileSource;
|
|
16
|
+
Type: () => string;
|
|
17
|
+
}
|
|
18
|
+
export declare const timeFormat = "MMM d, 'at' h:mm:s a '(UTC)'";
|
|
19
|
+
export declare const timeFormatShort = "MMM d, h:mma";
|
|
20
|
+
export declare function ParamsString(params: {
|
|
21
|
+
[key: string]: string;
|
|
22
|
+
}): string;
|
|
23
|
+
export declare function SuffixParams(params: {
|
|
24
|
+
[key: string]: any;
|
|
25
|
+
}, suffix: string): {
|
|
26
|
+
[key: string]: any;
|
|
27
|
+
};
|
|
28
|
+
export declare function ParseLabels(labels: string[]): Label[];
|
|
29
|
+
export declare function ProfileSelectionFromParams(expression: string | undefined, from: string | undefined, to: string | undefined, merge: string | undefined, labels: string[] | undefined, profileName: string | undefined, time: string | undefined): ProfileSelection | null;
|
|
30
|
+
export declare class SingleProfileSelection implements ProfileSelection {
|
|
31
|
+
profileName: string;
|
|
32
|
+
labels: Label[];
|
|
33
|
+
time: number;
|
|
34
|
+
constructor(profileName: string, labels: Label[], time: number);
|
|
35
|
+
ProfileName(): string;
|
|
36
|
+
HistoryParams(): {
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
};
|
|
39
|
+
Type(): string;
|
|
40
|
+
ProfileSource(): ProfileSource;
|
|
41
|
+
}
|
|
42
|
+
export declare class MergedProfileSelection implements ProfileSelection {
|
|
43
|
+
from: number;
|
|
44
|
+
to: number;
|
|
45
|
+
query: string;
|
|
46
|
+
constructor(from: number, to: number, query: string);
|
|
47
|
+
ProfileName(): string;
|
|
48
|
+
HistoryParams(): {
|
|
49
|
+
[key: string]: string;
|
|
50
|
+
};
|
|
51
|
+
Type(): string;
|
|
52
|
+
ProfileSource(): ProfileSource;
|
|
53
|
+
}
|
|
54
|
+
export declare class SingleProfileSource implements ProfileSource {
|
|
55
|
+
profName: string;
|
|
56
|
+
labels: Label[];
|
|
57
|
+
time: number;
|
|
58
|
+
constructor(profileName: string, labels: Label[], time: number);
|
|
59
|
+
query(): string;
|
|
60
|
+
DiffSelection(): ProfileDiffSelection;
|
|
61
|
+
QueryRequest(): QueryRequest;
|
|
62
|
+
ProfileType(): ProfileType;
|
|
63
|
+
profileName(): string;
|
|
64
|
+
Describe(): JSX.Element;
|
|
65
|
+
stringLabels(): string[];
|
|
66
|
+
toString(): string;
|
|
67
|
+
}
|
|
68
|
+
export declare class ProfileDiffSource implements ProfileSource {
|
|
69
|
+
a: ProfileSource;
|
|
70
|
+
b: ProfileSource;
|
|
71
|
+
constructor(a: ProfileSource, b: ProfileSource);
|
|
72
|
+
DiffSelection(): ProfileDiffSelection;
|
|
73
|
+
QueryRequest(): QueryRequest;
|
|
74
|
+
ProfileType(): ProfileType;
|
|
75
|
+
Describe(): JSX.Element;
|
|
76
|
+
toString(): string;
|
|
77
|
+
}
|
|
78
|
+
export declare class MergedProfileSource implements ProfileSource {
|
|
79
|
+
from: number;
|
|
80
|
+
to: number;
|
|
81
|
+
query: string;
|
|
82
|
+
constructor(from: number, to: number, query: string);
|
|
83
|
+
DiffSelection(): ProfileDiffSelection;
|
|
84
|
+
QueryRequest(): QueryRequest;
|
|
85
|
+
ProfileType(): ProfileType;
|
|
86
|
+
Describe(): JSX.Element;
|
|
87
|
+
toString(): string;
|
|
88
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
|
+
import { formatDate } from '@parca/functions';
|
|
14
|
+
import { Query, ProfileType } from '@parca/parser';
|
|
15
|
+
import { QueryRequest_Mode, QueryRequest_ReportType, ProfileDiffSelection_Mode, Timestamp, } from '@parca/client';
|
|
16
|
+
export var timeFormat = "MMM d, 'at' h:mm:s a '(UTC)'";
|
|
17
|
+
export var timeFormatShort = 'MMM d, h:mma';
|
|
18
|
+
export function ParamsString(params) {
|
|
19
|
+
return Object.keys(params)
|
|
20
|
+
.map(function (key) {
|
|
21
|
+
return "".concat(key, "=").concat(params[key]);
|
|
22
|
+
})
|
|
23
|
+
.join('&');
|
|
24
|
+
}
|
|
25
|
+
export function SuffixParams(params, suffix) {
|
|
26
|
+
return Object.fromEntries(Object.entries(params).map(function (_a) {
|
|
27
|
+
var key = _a[0], value = _a[1];
|
|
28
|
+
return ["".concat(key).concat(suffix), value];
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
export function ParseLabels(labels) {
|
|
32
|
+
return labels.map(function (labelString) {
|
|
33
|
+
var parts = labelString.split('=', 2);
|
|
34
|
+
return { name: parts[0], value: parts[1] };
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export function ProfileSelectionFromParams(expression, from, to, merge, labels, profileName, time) {
|
|
38
|
+
if (merge !== undefined &&
|
|
39
|
+
merge === 'true' &&
|
|
40
|
+
from !== undefined &&
|
|
41
|
+
to !== undefined &&
|
|
42
|
+
expression !== undefined) {
|
|
43
|
+
return new MergedProfileSelection(parseInt(from), parseInt(to), expression);
|
|
44
|
+
}
|
|
45
|
+
if (labels !== undefined && time !== undefined && profileName !== undefined) {
|
|
46
|
+
return new SingleProfileSelection(profileName, ParseLabels(labels), parseInt(time));
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
var SingleProfileSelection = /** @class */ (function () {
|
|
51
|
+
function SingleProfileSelection(profileName, labels, time) {
|
|
52
|
+
this.profileName = profileName;
|
|
53
|
+
this.labels = labels;
|
|
54
|
+
this.time = time;
|
|
55
|
+
}
|
|
56
|
+
SingleProfileSelection.prototype.ProfileName = function () {
|
|
57
|
+
return this.profileName;
|
|
58
|
+
};
|
|
59
|
+
SingleProfileSelection.prototype.HistoryParams = function () {
|
|
60
|
+
return {
|
|
61
|
+
profile_name: this.profileName,
|
|
62
|
+
labels: this.labels.map(function (label) { return "".concat(label.name, "=").concat(label.value); }),
|
|
63
|
+
time: this.time,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
SingleProfileSelection.prototype.Type = function () {
|
|
67
|
+
return 'single';
|
|
68
|
+
};
|
|
69
|
+
SingleProfileSelection.prototype.ProfileSource = function () {
|
|
70
|
+
return new SingleProfileSource(this.profileName, this.labels, this.time);
|
|
71
|
+
};
|
|
72
|
+
return SingleProfileSelection;
|
|
73
|
+
}());
|
|
74
|
+
export { SingleProfileSelection };
|
|
75
|
+
var MergedProfileSelection = /** @class */ (function () {
|
|
76
|
+
function MergedProfileSelection(from, to, query) {
|
|
77
|
+
this.from = from;
|
|
78
|
+
this.to = to;
|
|
79
|
+
this.query = query;
|
|
80
|
+
}
|
|
81
|
+
MergedProfileSelection.prototype.ProfileName = function () {
|
|
82
|
+
return Query.parse(this.query).profileName();
|
|
83
|
+
};
|
|
84
|
+
MergedProfileSelection.prototype.HistoryParams = function () {
|
|
85
|
+
return {
|
|
86
|
+
mode: 'merge',
|
|
87
|
+
from: this.from.toString(),
|
|
88
|
+
to: this.to.toString(),
|
|
89
|
+
query: this.query,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
MergedProfileSelection.prototype.Type = function () {
|
|
93
|
+
return 'merge';
|
|
94
|
+
};
|
|
95
|
+
MergedProfileSelection.prototype.ProfileSource = function () {
|
|
96
|
+
return new MergedProfileSource(this.from, this.to, this.query);
|
|
97
|
+
};
|
|
98
|
+
return MergedProfileSelection;
|
|
99
|
+
}());
|
|
100
|
+
export { MergedProfileSelection };
|
|
101
|
+
var SingleProfileSource = /** @class */ (function () {
|
|
102
|
+
function SingleProfileSource(profileName, labels, time) {
|
|
103
|
+
this.profName = profileName;
|
|
104
|
+
this.labels = labels;
|
|
105
|
+
this.time = time;
|
|
106
|
+
}
|
|
107
|
+
SingleProfileSource.prototype.query = function () {
|
|
108
|
+
var seriesQuery = this.profName +
|
|
109
|
+
this.labels.reduce(function (agg, label) {
|
|
110
|
+
return agg + "".concat(label.name, "=\"").concat(label.value, "\",");
|
|
111
|
+
}, '{');
|
|
112
|
+
return seriesQuery + '}';
|
|
113
|
+
};
|
|
114
|
+
SingleProfileSource.prototype.DiffSelection = function () {
|
|
115
|
+
return {
|
|
116
|
+
options: {
|
|
117
|
+
oneofKind: 'single',
|
|
118
|
+
single: {
|
|
119
|
+
time: Timestamp.fromDate(new Date(this.time)),
|
|
120
|
+
query: this.query(),
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
mode: ProfileDiffSelection_Mode.SINGLE_UNSPECIFIED,
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
SingleProfileSource.prototype.QueryRequest = function () {
|
|
127
|
+
return {
|
|
128
|
+
options: {
|
|
129
|
+
oneofKind: 'single',
|
|
130
|
+
single: {
|
|
131
|
+
time: Timestamp.fromDate(new Date(this.time)),
|
|
132
|
+
query: this.query(),
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
reportType: QueryRequest_ReportType.FLAMEGRAPH_UNSPECIFIED,
|
|
136
|
+
mode: QueryRequest_Mode.SINGLE_UNSPECIFIED,
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
SingleProfileSource.prototype.ProfileType = function () {
|
|
140
|
+
return ProfileType.fromString(this.profName);
|
|
141
|
+
};
|
|
142
|
+
SingleProfileSource.prototype.profileName = function () {
|
|
143
|
+
return this.profName;
|
|
144
|
+
};
|
|
145
|
+
SingleProfileSource.prototype.Describe = function () {
|
|
146
|
+
var profileName = this.profileName();
|
|
147
|
+
return (_jsxs(_Fragment, { children: [_jsxs("p", { children: [profileName !== '' ? _jsxs("a", { children: [profileName, " profile of "] }) : '', ' ', this.labels
|
|
148
|
+
.filter(function (label) { return label.name !== '__name__'; })
|
|
149
|
+
.map(function (label) { return (_jsx("button", __assign({ type: "button", className: "inline-block rounded-lg text-gray-700 bg-gray-200 dark:bg-gray-700 dark:text-gray-400 px-2 py-1 text-xs font-bold mr-3" }, { children: "".concat(label.name, "=\"").concat(label.value, "\"") }), label.name)); })] }), _jsx("p", { children: formatDate(this.time, timeFormat) })] }));
|
|
150
|
+
};
|
|
151
|
+
SingleProfileSource.prototype.stringLabels = function () {
|
|
152
|
+
return this.labels
|
|
153
|
+
.filter(function (label) { return label.name !== '__name__'; })
|
|
154
|
+
.map(function (label) { return "".concat(label.name, "=").concat(label.value); });
|
|
155
|
+
};
|
|
156
|
+
SingleProfileSource.prototype.toString = function () {
|
|
157
|
+
return "single profile of type ".concat(this.profileName(), " with labels ").concat(this.stringLabels().join(', '), " collected at ").concat(formatDate(this.time, timeFormat));
|
|
158
|
+
};
|
|
159
|
+
return SingleProfileSource;
|
|
160
|
+
}());
|
|
161
|
+
export { SingleProfileSource };
|
|
162
|
+
var ProfileDiffSource = /** @class */ (function () {
|
|
163
|
+
function ProfileDiffSource(a, b) {
|
|
164
|
+
this.a = a;
|
|
165
|
+
this.b = b;
|
|
166
|
+
}
|
|
167
|
+
ProfileDiffSource.prototype.DiffSelection = function () {
|
|
168
|
+
throw new Error('Method not implemented.');
|
|
169
|
+
};
|
|
170
|
+
ProfileDiffSource.prototype.QueryRequest = function () {
|
|
171
|
+
return {
|
|
172
|
+
options: {
|
|
173
|
+
oneofKind: 'diff',
|
|
174
|
+
diff: {
|
|
175
|
+
a: this.a.DiffSelection(),
|
|
176
|
+
b: this.b.DiffSelection(),
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
reportType: QueryRequest_ReportType.FLAMEGRAPH_UNSPECIFIED,
|
|
180
|
+
mode: QueryRequest_Mode.DIFF,
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
ProfileDiffSource.prototype.ProfileType = function () {
|
|
184
|
+
return this.a.ProfileType();
|
|
185
|
+
};
|
|
186
|
+
ProfileDiffSource.prototype.Describe = function () {
|
|
187
|
+
return (_jsx(_Fragment, { children: _jsx("p", { children: "Browse the comparison" }) }));
|
|
188
|
+
};
|
|
189
|
+
ProfileDiffSource.prototype.toString = function () {
|
|
190
|
+
return "".concat(this.a.toString(), " compared with ").concat(this.b.toString());
|
|
191
|
+
};
|
|
192
|
+
return ProfileDiffSource;
|
|
193
|
+
}());
|
|
194
|
+
export { ProfileDiffSource };
|
|
195
|
+
var MergedProfileSource = /** @class */ (function () {
|
|
196
|
+
function MergedProfileSource(from, to, query) {
|
|
197
|
+
this.from = from;
|
|
198
|
+
this.to = to;
|
|
199
|
+
this.query = query;
|
|
200
|
+
}
|
|
201
|
+
MergedProfileSource.prototype.DiffSelection = function () {
|
|
202
|
+
return {
|
|
203
|
+
options: {
|
|
204
|
+
oneofKind: 'merge',
|
|
205
|
+
merge: {
|
|
206
|
+
start: Timestamp.fromDate(new Date(this.from)),
|
|
207
|
+
end: Timestamp.fromDate(new Date(this.to)),
|
|
208
|
+
query: this.query,
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
mode: ProfileDiffSelection_Mode.MERGE,
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
MergedProfileSource.prototype.QueryRequest = function () {
|
|
215
|
+
return {
|
|
216
|
+
options: {
|
|
217
|
+
oneofKind: 'merge',
|
|
218
|
+
merge: {
|
|
219
|
+
start: Timestamp.fromDate(new Date(this.from)),
|
|
220
|
+
end: Timestamp.fromDate(new Date(this.to)),
|
|
221
|
+
query: this.query,
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
reportType: QueryRequest_ReportType.FLAMEGRAPH_UNSPECIFIED,
|
|
225
|
+
mode: QueryRequest_Mode.MERGE,
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
MergedProfileSource.prototype.ProfileType = function () {
|
|
229
|
+
return ProfileType.fromString(Query.parse(this.query).profileName());
|
|
230
|
+
};
|
|
231
|
+
MergedProfileSource.prototype.Describe = function () {
|
|
232
|
+
return (_jsxs("a", { children: ["Merge of \"", this.query, "\" from ", formatDate(this.from, timeFormat), " to", ' ', formatDate(this.to, timeFormat)] }));
|
|
233
|
+
};
|
|
234
|
+
MergedProfileSource.prototype.toString = function () {
|
|
235
|
+
return "merged profiles of query \"".concat(this.query, "\" from ").concat(formatDate(this.from, timeFormat), " to ").concat(formatDate(this.to, timeFormat));
|
|
236
|
+
};
|
|
237
|
+
return MergedProfileSource;
|
|
238
|
+
}());
|
|
239
|
+
export { MergedProfileSource };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ProfileTypesResponse } from '@parca/client';
|
|
2
|
+
import { RpcError } from '@protobuf-ts/runtime-rpc';
|
|
3
|
+
interface WellKnownProfile {
|
|
4
|
+
name: string;
|
|
5
|
+
help: string;
|
|
6
|
+
}
|
|
7
|
+
interface WellKnownProfiles {
|
|
8
|
+
[key: string]: WellKnownProfile;
|
|
9
|
+
}
|
|
10
|
+
export declare const wellKnownProfiles: WellKnownProfiles;
|
|
11
|
+
interface Props {
|
|
12
|
+
profileTypesData?: ProfileTypesResponse;
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
error: RpcError | undefined;
|
|
15
|
+
selectedKey: string | undefined;
|
|
16
|
+
flexibleKnownProfilesDetection?: boolean;
|
|
17
|
+
onSelection: (value: string | undefined) => void;
|
|
18
|
+
}
|
|
19
|
+
declare const ProfileTypeSelector: ({ profileTypesData, loading, error, selectedKey, onSelection, flexibleKnownProfilesDetection, }: Props) => JSX.Element;
|
|
20
|
+
export default ProfileTypeSelector;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
// Copyright 2022 The Parca Authors
|
|
14
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
// you may not use this file except in compliance with the License.
|
|
16
|
+
// You may obtain a copy of the License at
|
|
17
|
+
//
|
|
18
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
//
|
|
20
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
// See the License for the specific language governing permissions and
|
|
24
|
+
// limitations under the License.
|
|
25
|
+
import { useMemo } from 'react';
|
|
26
|
+
import { Select } from '@parca/components';
|
|
27
|
+
export var wellKnownProfiles = {
|
|
28
|
+
'block:contentions:count:contentions:count': {
|
|
29
|
+
name: 'Block Contentions Total',
|
|
30
|
+
help: 'Stack traces that led to blocking on synchronization primitives.',
|
|
31
|
+
},
|
|
32
|
+
'block:delay:nanoseconds:contentions:count': {
|
|
33
|
+
name: 'Block Contention Time Total',
|
|
34
|
+
help: 'Time delayed stack traces caused by blocking on synchronization primitives.',
|
|
35
|
+
},
|
|
36
|
+
// Unfortunately, fgprof does not set the period type and unit.
|
|
37
|
+
'fgprof:samples:count::': {
|
|
38
|
+
name: 'Fgprof Samples Total',
|
|
39
|
+
help: 'CPU profile samples observed regardless of their current On/Off CPU scheduling status',
|
|
40
|
+
},
|
|
41
|
+
// Unfortunately, fgprof does not set the period type and unit.
|
|
42
|
+
'fgprof:time:nanoseconds::': {
|
|
43
|
+
name: 'Fgprof Samples Time Total',
|
|
44
|
+
help: 'CPU profile measured regardless of their current On/Off CPU scheduling status in nanoseconds',
|
|
45
|
+
},
|
|
46
|
+
'goroutine:goroutine:count:goroutine:count': {
|
|
47
|
+
name: 'Goroutine Created Total',
|
|
48
|
+
help: 'Stack traces that created all current goroutines.',
|
|
49
|
+
},
|
|
50
|
+
'memory:alloc_objects:count:space:bytes': {
|
|
51
|
+
name: 'Memory Allocated Objects Total',
|
|
52
|
+
help: 'A sampling of all past memory allocations by objects.',
|
|
53
|
+
},
|
|
54
|
+
'memory:alloc_space:bytes:space:bytes': {
|
|
55
|
+
name: 'Memory Allocated Bytes Total',
|
|
56
|
+
help: 'A sampling of all past memory allocations in bytes.',
|
|
57
|
+
},
|
|
58
|
+
'memory:alloc_objects:count:space:bytes:delta': {
|
|
59
|
+
name: 'Memory Allocated Objects Delta',
|
|
60
|
+
help: 'A sampling of all memory allocations during the observation by objects.',
|
|
61
|
+
},
|
|
62
|
+
'memory:alloc_space:bytes:space:bytes:delta': {
|
|
63
|
+
name: 'Memory Allocated Bytes Delta',
|
|
64
|
+
help: 'A sampling of all memory allocations during the observation in bytes.',
|
|
65
|
+
},
|
|
66
|
+
'memory:inuse_objects:count:space:bytes': {
|
|
67
|
+
name: 'Memory In-Use Objects',
|
|
68
|
+
help: 'A sampling of memory allocations of live objects by objects.',
|
|
69
|
+
},
|
|
70
|
+
'memory:inuse_space:bytes:space:bytes': {
|
|
71
|
+
name: 'Memory In-Use Bytes',
|
|
72
|
+
help: 'A sampling of memory allocations of live objects by bytes.',
|
|
73
|
+
},
|
|
74
|
+
'mutex:contentions:count:contentions:count': {
|
|
75
|
+
name: 'Mutex Contentions Total',
|
|
76
|
+
help: 'Stack traces of holders of contended mutexes.',
|
|
77
|
+
},
|
|
78
|
+
'mutex:delay:nanoseconds:contentions:count': {
|
|
79
|
+
name: 'Mutex Contention Time Total',
|
|
80
|
+
help: 'Time delayed stack traces caused by contended mutexes.',
|
|
81
|
+
},
|
|
82
|
+
'process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta': {
|
|
83
|
+
name: 'Process CPU Nanoseconds',
|
|
84
|
+
help: 'CPU profile measured by the process itself in nanoseconds.',
|
|
85
|
+
},
|
|
86
|
+
'process_cpu:samples:count:cpu:nanoseconds:delta': {
|
|
87
|
+
name: 'Process CPU Samples',
|
|
88
|
+
help: 'CPU profile samples observed by the process itself.',
|
|
89
|
+
},
|
|
90
|
+
'parca_agent_cpu:samples:count:cpu:nanoseconds:delta': {
|
|
91
|
+
name: 'CPU Samples',
|
|
92
|
+
help: 'CPU profile samples observed by Parca Agent.',
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
function flexibleWellKnownProfileMatching(name) {
|
|
96
|
+
var prefixExcludedName = name.split(':').slice(1).join(':');
|
|
97
|
+
var requiredKey = Object.keys(wellKnownProfiles).find(function (key) {
|
|
98
|
+
if (key.endsWith(prefixExcludedName)) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
});
|
|
103
|
+
return requiredKey != null ? wellKnownProfiles[requiredKey] : undefined;
|
|
104
|
+
}
|
|
105
|
+
function profileSelectElement(name, flexibleKnownProfilesDetection) {
|
|
106
|
+
var wellKnown = !flexibleKnownProfilesDetection
|
|
107
|
+
? wellKnownProfiles[name]
|
|
108
|
+
: flexibleWellKnownProfileMatching(name);
|
|
109
|
+
if (wellKnown === undefined)
|
|
110
|
+
return { active: _jsx(_Fragment, { children: name }), expanded: _jsx(_Fragment, { children: name }) };
|
|
111
|
+
var title = wellKnown.name.replace(/ /g, '\u00a0');
|
|
112
|
+
return {
|
|
113
|
+
active: _jsx(_Fragment, { children: title }),
|
|
114
|
+
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: title }), _jsx("br", {}), _jsx("span", __assign({ className: "text-xs" }, { children: wellKnown.help }))] })),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
var ProfileTypeSelector = function (_a) {
|
|
118
|
+
var profileTypesData = _a.profileTypesData, _b = _a.loading, loading = _b === void 0 ? false : _b, error = _a.error, selectedKey = _a.selectedKey, onSelection = _a.onSelection, _c = _a.flexibleKnownProfilesDetection, flexibleKnownProfilesDetection = _c === void 0 ? false : _c;
|
|
119
|
+
var profileNames = useMemo(function () {
|
|
120
|
+
return (error === undefined || error == null) &&
|
|
121
|
+
profileTypesData !== undefined &&
|
|
122
|
+
profileTypesData != null
|
|
123
|
+
? profileTypesData.types
|
|
124
|
+
.map(function (type) {
|
|
125
|
+
return "".concat(type.name, ":").concat(type.sampleType, ":").concat(type.sampleUnit, ":").concat(type.periodType, ":").concat(type.periodUnit).concat(type.delta ? ':delta' : '');
|
|
126
|
+
})
|
|
127
|
+
.sort(function (a, b) {
|
|
128
|
+
return a.localeCompare(b);
|
|
129
|
+
})
|
|
130
|
+
: [];
|
|
131
|
+
}, [profileTypesData, error]);
|
|
132
|
+
var profileLabels = profileNames.map(function (name) { return ({
|
|
133
|
+
key: name,
|
|
134
|
+
element: profileSelectElement(name, flexibleKnownProfilesDetection),
|
|
135
|
+
}); });
|
|
136
|
+
return (_jsx(Select, { items: profileLabels, selectedKey: selectedKey, onSelection: onSelection, placeholder: "Select profile...", loading: loading }));
|
|
137
|
+
};
|
|
138
|
+
export default ProfileTypeSelector;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { QueryServiceClient, Flamegraph, Top, Callgraph } from '@parca/client';
|
|
2
|
+
import { ProfileSource } from './ProfileSource';
|
|
3
|
+
import './ProfileView.styles.css';
|
|
4
|
+
declare type NavigateFunction = (path: string, queryParams: any) => void;
|
|
5
|
+
interface FlamegraphData {
|
|
6
|
+
loading: boolean;
|
|
7
|
+
data?: Flamegraph;
|
|
8
|
+
error?: any;
|
|
9
|
+
}
|
|
10
|
+
interface TopTableData {
|
|
11
|
+
loading: boolean;
|
|
12
|
+
data?: Top;
|
|
13
|
+
error?: any;
|
|
14
|
+
}
|
|
15
|
+
interface CallgraphData {
|
|
16
|
+
loading: boolean;
|
|
17
|
+
data?: Callgraph;
|
|
18
|
+
error?: any;
|
|
19
|
+
}
|
|
20
|
+
export declare type VisualizationType = 'icicle' | 'table' | 'callgraph' | 'both';
|
|
21
|
+
interface ProfileVisState {
|
|
22
|
+
currentView: VisualizationType;
|
|
23
|
+
setCurrentView: (view: VisualizationType) => void;
|
|
24
|
+
}
|
|
25
|
+
interface ProfileViewProps {
|
|
26
|
+
flamegraphData?: FlamegraphData;
|
|
27
|
+
topTableData?: TopTableData;
|
|
28
|
+
callgraphData?: CallgraphData;
|
|
29
|
+
sampleUnit: string;
|
|
30
|
+
profileVisState: ProfileVisState;
|
|
31
|
+
profileSource?: ProfileSource;
|
|
32
|
+
queryClient?: QueryServiceClient;
|
|
33
|
+
navigateTo?: NavigateFunction;
|
|
34
|
+
compare?: boolean;
|
|
35
|
+
onDownloadPProf: () => void;
|
|
36
|
+
}
|
|
37
|
+
export declare const useProfileVisState: () => ProfileVisState;
|
|
38
|
+
export declare const ProfileView: ({ flamegraphData, topTableData, callgraphData, sampleUnit, profileSource, queryClient, navigateTo, profileVisState, onDownloadPProf, }: ProfileViewProps) => JSX.Element;
|
|
39
|
+
export {};
|