@parca/profile 0.16.341 → 0.16.342
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/MetricsGraph/MetricsTooltip/index.js +2 -2
- package/dist/MetricsGraph/index.js +4 -2
- package/dist/ProfileMetricsGraph/index.js +8 -1
- package/dist/ProfileViewWithData.js +12 -1
- package/package.json +7 -7
- package/src/MetricsGraph/MetricsTooltip/index.tsx +22 -9
- package/src/MetricsGraph/index.tsx +4 -2
- package/src/ProfileMetricsGraph/index.tsx +9 -1
- package/src/ProfileViewWithData.tsx +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
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.342](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.341...@parca/profile@0.16.342) (2024-02-14)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
6
10
|
## [0.16.341](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.340...@parca/profile@0.16.341) (2024-02-13)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
// Copyright 2022 The Parca Authors
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
// you may not use this file except in compliance with the License.
|
|
@@ -73,7 +73,7 @@ const MetricsTooltip = ({ x, y, highlighted, contextElement, sampleUnit, delta,
|
|
|
73
73
|
}, [x, y, contextElement, update]);
|
|
74
74
|
const nameLabel = highlighted?.labels.find(e => e.name === '__name__');
|
|
75
75
|
const highlightedNameLabel = nameLabel !== undefined ? nameLabel : { name: '', value: '' };
|
|
76
|
-
return (_jsx("div", { ref: setPopperElement, style: styles.popper, ...attributes.popper, className: "z-10", children: _jsx("div", { className: "flex max-w-md", children: _jsx("div", { className: "m-auto", children: _jsx("div", { className: "rounded-lg border-gray-300 bg-gray-50 p-3 opacity-90 shadow-lg dark:border-gray-500 dark:bg-gray-900", style: { borderWidth: 1 }, children: _jsx("div", { className: "flex flex-row", children: _jsxs("div", { className: "ml-2 mr-6", children: [_jsx("span", { className: "font-semibold", children: highlightedNameLabel.value }), _jsx("span", { className: "my-2 block text-gray-700 dark:text-gray-300", children: _jsx("table", { className: "table-auto", children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "
|
|
76
|
+
return (_jsx("div", { ref: setPopperElement, style: styles.popper, ...attributes.popper, className: "z-10", children: _jsx("div", { className: "flex max-w-md", children: _jsx("div", { className: "m-auto", children: _jsx("div", { className: "rounded-lg border-gray-300 bg-gray-50 p-3 opacity-90 shadow-lg dark:border-gray-500 dark:bg-gray-900", style: { borderWidth: 1 }, children: _jsx("div", { className: "flex flex-row", children: _jsxs("div", { className: "ml-2 mr-6", children: [_jsx("span", { className: "font-semibold", children: highlightedNameLabel.value }), _jsx("span", { className: "my-2 block text-gray-700 dark:text-gray-300", children: _jsx("table", { className: "table-auto", children: _jsxs("tbody", { children: [delta ? (_jsxs(_Fragment, { children: [_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Per Second" }), _jsx("td", { className: "w-3/4", children: valueFormatter(highlighted.valuePerSecond, sampleUnit === 'nanoseconds' ? 'CPU Cores' : sampleUnit, 5) })] }), _jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Total" }), _jsx("td", { className: "w-3/4", children: valueFormatter(highlighted.value, sampleUnit, 2) })] })] })) : (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Value" }), _jsx("td", { className: "w-3/4", children: valueFormatter(highlighted.valuePerSecond, sampleUnit, 5) })] })), highlighted.duration > 0 && (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Duration" }), _jsx("td", { className: "w-3/4", children: valueFormatter(highlighted.duration, 'nanoseconds', 2) })] })), _jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "At" }), _jsx("td", { className: "w-3/4", children: formatDate(highlighted.timestamp, timeFormat) })] })] }) }) }), _jsx("span", { className: "my-2 block text-gray-500", children: highlighted.labels
|
|
77
77
|
.filter((label) => label.name !== '__name__')
|
|
78
78
|
.map((label) => (_jsx("div", { className: "mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400", children: _jsx(TextWithTooltip, { text: `${label.name}="${label.value}"`, maxTextLength: 37, id: `tooltip-${label.name}-${label.value}` }) }, label.name))) }), _jsxs("div", { className: "flex w-full items-center gap-1 text-xs text-gray-500", children: [_jsx(Icon, { icon: "iconoir:mouse-button-right" }), _jsx("div", { children: "Right click to add labels to query." })] })] }) }) }) }) }) }));
|
|
79
79
|
};
|
|
@@ -241,9 +241,11 @@ export const RawMetricsGraph = ({ data, from, to, profile, onSampleClick, addLab
|
|
|
241
241
|
};
|
|
242
242
|
const isDeltaType = profile !== null ? profile?.query.profType.delta : false;
|
|
243
243
|
let yAxisLabel = sampleUnit;
|
|
244
|
+
let yAxisUnit = sampleUnit;
|
|
244
245
|
if (isDeltaType) {
|
|
245
|
-
if (
|
|
246
|
+
if (sampleUnit === 'nanoseconds') {
|
|
246
247
|
yAxisLabel = 'CPU Cores';
|
|
248
|
+
yAxisUnit = '';
|
|
247
249
|
}
|
|
248
250
|
if (sampleUnit === 'bytes') {
|
|
249
251
|
yAxisLabel = 'Bytes per Second';
|
|
@@ -260,7 +262,7 @@ export const RawMetricsGraph = ({ data, from, to, profile, onSampleClick, addLab
|
|
|
260
262
|
}
|
|
261
263
|
return (_jsxs(Fragment, { children: [_jsxs("g", { className: "tick",
|
|
262
264
|
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
|
263
|
-
transform: `translate(0, ${yScale(d)})`, children: [_jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x2: -6 }), _jsx("text", { fill: "currentColor", x: -9, dy: '0.32em', children: valueFormatter(d,
|
|
265
|
+
transform: `translate(0, ${yScale(d)})`, children: [_jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x2: -6 }), _jsx("text", { fill: "currentColor", x: -9, dy: '0.32em', children: valueFormatter(d, yAxisUnit, decimals) })] }, `tick-${i}`), _jsx("g", { children: _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(from), x2: xScale(to), y1: yScale(d), y2: yScale(d) }) }, `grid-${i}`)] }, `${i.toString()}-${d.toString()}`));
|
|
264
266
|
}), _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: 0, x2: 0, y1: 0, y2: height - margin }), _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(to), x2: xScale(to), y1: 0, y2: height - margin }), _jsx("g", { transform: `translate(${-margin}, ${(height - margin) / 2}) rotate(270)`, children: _jsx("text", { fill: "currentColor", dy: "-0.7em", className: "text-sm capitalize", textAnchor: "middle", children: yAxisLabel }) })] }), _jsxs("g", { className: "x axis", fill: "none", fontSize: "10", textAnchor: "middle", transform: `translate(0,${height - margin})`, children: [xScale.ticks(5).map((d, i) => (_jsxs(Fragment, { children: [_jsxs("g", { className: "tick",
|
|
265
267
|
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
|
266
268
|
transform: `translate(${xScale(d)}, 0)`, children: [_jsx("line", { y2: 6, className: "stroke-gray-300 dark:stroke-gray-500" }), _jsx("text", { fill: "currentColor", dy: ".71em", y: 9, children: formatDate(d, formatForTimespan(from, to)) })] }, `tick-${i}`), _jsx("g", { children: _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(d), x2: xScale(d), y1: 0, y2: -height + margin }) }, `grid-${i}`)] }, `${i.toString()}-${d.toString()}`))), _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(from), x2: xScale(to), y1: 0, y2: 0 }), _jsx("g", { transform: `translate(${(width - 2.5 * margin) / 2}, ${margin / 2})`, children: _jsx("text", { fill: "currentColor", dy: ".71em", y: 5, className: "text-sm", children: "Time" }) })] }), _jsx("g", { className: "lines fill-transparent", children: series.map((s, i) => (_jsx("g", { className: "line", children: _jsx(MetricsSeries, { data: s, line: l, color: color(i.toString()), strokeWidth: hovering && highlighted != null && i === highlighted.seriesIndex
|
|
@@ -91,7 +91,14 @@ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to,
|
|
|
91
91
|
const handleSampleClick = (timestamp, _value, labels) => {
|
|
92
92
|
onPointClick(timestamp, labels, queryExpression);
|
|
93
93
|
};
|
|
94
|
-
|
|
94
|
+
let sampleUnit = '';
|
|
95
|
+
if (series.every((val, i, arr) => val?.sampleType?.unit === arr[0]?.sampleType?.unit)) {
|
|
96
|
+
sampleUnit = series[0]?.sampleType?.unit ?? '';
|
|
97
|
+
}
|
|
98
|
+
if (sampleUnit === '') {
|
|
99
|
+
sampleUnit = Query.parse(queryExpression).profileType().sampleUnit;
|
|
100
|
+
}
|
|
101
|
+
return (_jsx(AnimatePresence, { children: _jsx(motion.div, { className: "h-full w-full", initial: { display: 'none', opacity: 0 }, animate: { display: 'block', opacity: 1 }, transition: { duration: 0.5 }, children: _jsx(MetricsGraph, { data: series, from: from, to: to, profile: profile, setTimeRange: setTimeRange, onSampleClick: handleSampleClick, addLabelMatcher: addLabelMatcher, sampleUnit: sampleUnit, height: height, width: width, margin: margin }) }, "metrics-graph-loaded") }));
|
|
95
102
|
}
|
|
96
103
|
return _jsx(ProfileMetricsEmptyState, { message: "No data found. Try a different query." });
|
|
97
104
|
};
|
|
@@ -87,7 +87,18 @@ export const ProfileViewWithData = ({ queryClient, profileSource, navigateTo, })
|
|
|
87
87
|
sourceResponse,
|
|
88
88
|
perf,
|
|
89
89
|
]);
|
|
90
|
-
|
|
90
|
+
// Default to the unit of the selected profile type. This is a heuristic, and
|
|
91
|
+
// only a fallback, the unit should be returned by the backend.
|
|
92
|
+
let sampleUnit = profileSource.ProfileType().sampleUnit;
|
|
93
|
+
if (flamegraphResponse?.report.oneofKind === 'flamegraphArrow') {
|
|
94
|
+
sampleUnit = flamegraphResponse.report.flamegraphArrow.unit;
|
|
95
|
+
}
|
|
96
|
+
if (tableResponse?.report.oneofKind === 'tableArrow') {
|
|
97
|
+
sampleUnit = tableResponse.report.tableArrow.unit;
|
|
98
|
+
}
|
|
99
|
+
if (sourceResponse?.report.oneofKind === 'source') {
|
|
100
|
+
sampleUnit = sourceResponse.report.source.unit;
|
|
101
|
+
}
|
|
91
102
|
const downloadPProfClick = async () => {
|
|
92
103
|
if (profileSource == null || queryClient == null) {
|
|
93
104
|
return;
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.342",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@parca/client": "^0.16.
|
|
7
|
-
"@parca/components": "^0.16.
|
|
6
|
+
"@parca/client": "^0.16.103",
|
|
7
|
+
"@parca/components": "^0.16.252",
|
|
8
8
|
"@parca/dynamicsize": "^0.16.60",
|
|
9
|
-
"@parca/hooks": "^0.0.
|
|
9
|
+
"@parca/hooks": "^0.0.41",
|
|
10
10
|
"@parca/parser": "^0.16.68",
|
|
11
|
-
"@parca/store": "^0.16.
|
|
12
|
-
"@parca/utilities": "^0.0.
|
|
11
|
+
"@parca/store": "^0.16.129",
|
|
12
|
+
"@parca/utilities": "^0.0.57",
|
|
13
13
|
"@tanstack/react-query": "^4.0.5",
|
|
14
14
|
"@types/react-beautiful-dnd": "^13.1.3",
|
|
15
15
|
"apache-arrow": "^12.0.0",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"access": "public",
|
|
52
52
|
"registry": "https://registry.npmjs.org/"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "64e853a94dc382feae3481f3f64efa47e8f5709c"
|
|
55
55
|
}
|
|
@@ -117,17 +117,30 @@ const MetricsTooltip = ({
|
|
|
117
117
|
<span className="my-2 block text-gray-700 dark:text-gray-300">
|
|
118
118
|
<table className="table-auto">
|
|
119
119
|
<tbody>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
{delta ? (
|
|
121
|
+
<>
|
|
122
|
+
<tr>
|
|
123
|
+
<td className="w-1/4">Per Second</td>
|
|
124
|
+
<td className="w-3/4">
|
|
125
|
+
{valueFormatter(
|
|
126
|
+
highlighted.valuePerSecond,
|
|
127
|
+
sampleUnit === 'nanoseconds' ? 'CPU Cores' : sampleUnit,
|
|
128
|
+
5
|
|
129
|
+
)}
|
|
130
|
+
</td>
|
|
131
|
+
</tr>
|
|
132
|
+
<tr>
|
|
133
|
+
<td className="w-1/4">Total</td>
|
|
134
|
+
<td className="w-3/4">
|
|
135
|
+
{valueFormatter(highlighted.value, sampleUnit, 2)}
|
|
136
|
+
</td>
|
|
137
|
+
</tr>
|
|
138
|
+
</>
|
|
139
|
+
) : (
|
|
127
140
|
<tr>
|
|
128
|
-
<td className="w-1/4">
|
|
141
|
+
<td className="w-1/4">Value</td>
|
|
129
142
|
<td className="w-3/4">
|
|
130
|
-
{valueFormatter(highlighted.
|
|
143
|
+
{valueFormatter(highlighted.valuePerSecond, sampleUnit, 5)}
|
|
131
144
|
</td>
|
|
132
145
|
</tr>
|
|
133
146
|
)}
|
|
@@ -392,9 +392,11 @@ export const RawMetricsGraph = ({
|
|
|
392
392
|
const isDeltaType = profile !== null ? profile?.query.profType.delta : false;
|
|
393
393
|
|
|
394
394
|
let yAxisLabel = sampleUnit;
|
|
395
|
+
let yAxisUnit = sampleUnit;
|
|
395
396
|
if (isDeltaType) {
|
|
396
|
-
if (
|
|
397
|
+
if (sampleUnit === 'nanoseconds') {
|
|
397
398
|
yAxisLabel = 'CPU Cores';
|
|
399
|
+
yAxisUnit = '';
|
|
398
400
|
}
|
|
399
401
|
if (sampleUnit === 'bytes') {
|
|
400
402
|
yAxisLabel = 'Bytes per Second';
|
|
@@ -477,7 +479,7 @@ export const RawMetricsGraph = ({
|
|
|
477
479
|
>
|
|
478
480
|
<line className="stroke-gray-300 dark:stroke-gray-500" x2={-6} />
|
|
479
481
|
<text fill="currentColor" x={-9} dy={'0.32em'}>
|
|
480
|
-
{valueFormatter(d,
|
|
482
|
+
{valueFormatter(d, yAxisUnit, decimals)}
|
|
481
483
|
</text>
|
|
482
484
|
</g>
|
|
483
485
|
<g key={`grid-${i}`}>
|
|
@@ -172,6 +172,14 @@ const ProfileMetricsGraph = ({
|
|
|
172
172
|
onPointClick(timestamp, labels, queryExpression);
|
|
173
173
|
};
|
|
174
174
|
|
|
175
|
+
let sampleUnit = '';
|
|
176
|
+
if (series.every((val, i, arr) => val?.sampleType?.unit === arr[0]?.sampleType?.unit)) {
|
|
177
|
+
sampleUnit = series[0]?.sampleType?.unit ?? '';
|
|
178
|
+
}
|
|
179
|
+
if (sampleUnit === '') {
|
|
180
|
+
sampleUnit = Query.parse(queryExpression).profileType().sampleUnit;
|
|
181
|
+
}
|
|
182
|
+
|
|
175
183
|
return (
|
|
176
184
|
<AnimatePresence>
|
|
177
185
|
<motion.div
|
|
@@ -189,7 +197,7 @@ const ProfileMetricsGraph = ({
|
|
|
189
197
|
setTimeRange={setTimeRange}
|
|
190
198
|
onSampleClick={handleSampleClick}
|
|
191
199
|
addLabelMatcher={addLabelMatcher}
|
|
192
|
-
sampleUnit={
|
|
200
|
+
sampleUnit={sampleUnit}
|
|
193
201
|
height={height}
|
|
194
202
|
width={width}
|
|
195
203
|
margin={margin}
|
|
@@ -135,7 +135,18 @@ export const ProfileViewWithData = ({
|
|
|
135
135
|
perf,
|
|
136
136
|
]);
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
// Default to the unit of the selected profile type. This is a heuristic, and
|
|
139
|
+
// only a fallback, the unit should be returned by the backend.
|
|
140
|
+
let sampleUnit = profileSource.ProfileType().sampleUnit;
|
|
141
|
+
if (flamegraphResponse?.report.oneofKind === 'flamegraphArrow') {
|
|
142
|
+
sampleUnit = flamegraphResponse.report.flamegraphArrow.unit;
|
|
143
|
+
}
|
|
144
|
+
if (tableResponse?.report.oneofKind === 'tableArrow') {
|
|
145
|
+
sampleUnit = tableResponse.report.tableArrow.unit;
|
|
146
|
+
}
|
|
147
|
+
if (sourceResponse?.report.oneofKind === 'source') {
|
|
148
|
+
sampleUnit = sourceResponse.report.source.unit;
|
|
149
|
+
}
|
|
139
150
|
|
|
140
151
|
const downloadPProfClick = async (): Promise<void> => {
|
|
141
152
|
if (profileSource == null || queryClient == null) {
|