@parca/profile 0.16.184 → 0.16.185

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/Callgraph/constants.js +2 -2
  3. package/dist/Callgraph/index.js +35 -45
  4. package/dist/Callgraph/mockData/index.js +28 -11
  5. package/dist/Callgraph/utils.js +51 -58
  6. package/dist/GraphTooltip/ExpandOnHoverValue.js +2 -14
  7. package/dist/GraphTooltip/index.d.ts +5 -5
  8. package/dist/GraphTooltip/index.js +96 -122
  9. package/dist/MatchersInput/SuggestionItem.js +5 -17
  10. package/dist/MatchersInput/SuggestionsList.js +29 -53
  11. package/dist/MatchersInput/index.js +58 -74
  12. package/dist/MetricsCircle/index.js +2 -16
  13. package/dist/MetricsGraph/MetricsTooltip/index.js +27 -53
  14. package/dist/MetricsGraph/index.js +79 -98
  15. package/dist/MetricsSeries/index.js +4 -19
  16. package/dist/ProfileExplorer/ProfileExplorerCompare.js +4 -16
  17. package/dist/ProfileExplorer/ProfileExplorerSingle.js +2 -14
  18. package/dist/ProfileExplorer/index.js +129 -88
  19. package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.js +15 -31
  20. package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.d.ts +4 -4
  21. package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.js +38 -54
  22. package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts +2 -2
  23. package/dist/ProfileIcicleGraph/IcicleGraph/index.js +15 -31
  24. package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.js +22 -26
  25. package/dist/ProfileIcicleGraph/IcicleGraph/useNodeColor.js +8 -9
  26. package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +18 -20
  27. package/dist/ProfileIcicleGraph/index.d.ts +2 -2
  28. package/dist/ProfileIcicleGraph/index.js +18 -30
  29. package/dist/ProfileMetricsGraph/index.js +36 -88
  30. package/dist/ProfileSelector/CompareButton.js +8 -20
  31. package/dist/ProfileSelector/index.js +69 -69
  32. package/dist/ProfileSource.js +56 -65
  33. package/dist/ProfileTypeSelector/index.js +14 -28
  34. package/dist/ProfileView/FilterByFunctionButton.js +6 -7
  35. package/dist/ProfileView/ViewSelector.js +18 -31
  36. package/dist/ProfileView/VisualizationPanel.js +4 -16
  37. package/dist/ProfileView/index.js +72 -152
  38. package/dist/ProfileViewWithData.js +50 -101
  39. package/dist/TopTable/index.js +55 -63
  40. package/dist/components/DiffLegend.js +16 -28
  41. package/dist/components/ProfileShareButton/ResultBox.js +7 -21
  42. package/dist/components/ProfileShareButton/index.js +31 -90
  43. package/dist/useDelayedLoader.js +7 -8
  44. package/dist/useGrpcQuery/index.js +6 -48
  45. package/dist/useQuery.js +14 -58
  46. package/dist/utils.d.ts +1 -1
  47. package/dist/utils.js +16 -68
  48. package/package.json +6 -6
  49. package/src/Callgraph/index.tsx +3 -3
  50. package/src/Callgraph/utils.ts +1 -1
  51. package/src/GraphTooltip/index.tsx +17 -17
  52. package/src/MetricsGraph/index.tsx +3 -3
  53. package/src/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.tsx +9 -10
  54. package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +4 -8
  55. package/src/ProfileIcicleGraph/IcicleGraph/useNodeColor.ts +2 -2
  56. package/src/ProfileIcicleGraph/index.tsx +8 -8
  57. package/src/ProfileView/index.tsx +2 -2
  58. package/src/TopTable/index.tsx +3 -3
  59. package/src/utils.ts +2 -2
package/dist/useQuery.js CHANGED
@@ -10,68 +10,24 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
- return new (P || (P = Promise))(function (resolve, reject) {
16
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
- step((generator = generator.apply(thisArg, _arguments || [])).next());
20
- });
21
- };
22
- var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
- function verb(n) { return function (v) { return step([n, v]); }; }
26
- function step(op) {
27
- if (f) throw new TypeError("Generator is already executing.");
28
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
- if (y = 0, t) op = [op[0] & 2, t.value];
31
- switch (op[0]) {
32
- case 0: case 1: t = op; break;
33
- case 4: _.label++; return { value: op[1], done: false };
34
- case 5: _.label++; y = op[1]; op = [0]; continue;
35
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
- default:
37
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
- if (t[2]) _.ops.pop();
42
- _.trys.pop(); continue;
43
- }
44
- op = body.call(thisArg, _);
45
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
- }
48
- };
49
13
  import { useGrpcMetadata } from '@parca/components';
50
14
  import useGrpcQuery from './useGrpcQuery';
51
- export var useQuery = function (client, profileSource, reportType, options) {
52
- var _a = (options !== null && options !== void 0 ? options : {}).skip, skip = _a === void 0 ? false : _a;
53
- var metadata = useGrpcMetadata();
54
- var _b = useGrpcQuery({
55
- key: ['query', profileSource, reportType, options === null || options === void 0 ? void 0 : options.nodeTrimThreshold],
56
- queryFn: function () { return __awaiter(void 0, void 0, void 0, function () {
57
- var req, response;
58
- return __generator(this, function (_a) {
59
- switch (_a.label) {
60
- case 0:
61
- req = profileSource.QueryRequest();
62
- req.reportType = reportType;
63
- req.nodeTrimThreshold = options === null || options === void 0 ? void 0 : options.nodeTrimThreshold;
64
- return [4 /*yield*/, client.query(req, { meta: metadata })];
65
- case 1:
66
- response = (_a.sent()).response;
67
- return [2 /*return*/, response];
68
- }
69
- });
70
- }); },
15
+ export const useQuery = (client, profileSource, reportType, options) => {
16
+ const { skip = false } = options ?? {};
17
+ const metadata = useGrpcMetadata();
18
+ const { data, isLoading, error } = useGrpcQuery({
19
+ key: ['query', profileSource, reportType, options?.nodeTrimThreshold],
20
+ queryFn: async () => {
21
+ const req = profileSource.QueryRequest();
22
+ req.reportType = reportType;
23
+ req.nodeTrimThreshold = options?.nodeTrimThreshold;
24
+ const { response } = await client.query(req, { meta: metadata });
25
+ return response;
26
+ },
71
27
  options: {
72
28
  enabled: !skip,
73
29
  staleTime: 1000 * 60 * 5, // 5 minutes
74
30
  },
75
- }), data = _b.data, isLoading = _b.isLoading, error = _b.error;
76
- return { isLoading: isLoading, error: error, response: data !== null && data !== void 0 ? data : null };
31
+ });
32
+ return { isLoading, error: error, response: data ?? null };
77
33
  };
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { RpcMetadata } from '@protobuf-ts/runtime-rpc';
2
2
  import { QueryRequest, QueryServiceClient } from '@parca/client';
3
- export declare const hexifyAddress: (address?: string) => string;
3
+ export declare const hexifyAddress: (address?: bigint) => string;
4
4
  export declare const downloadPprof: (request: QueryRequest, queryClient: QueryServiceClient, metadata: RpcMetadata) => Promise<Blob>;
5
5
  export declare const truncateString: (str: string, num: number) => string;
6
6
  export declare const truncateStringReverse: (str: string, num: number) => string;
package/dist/utils.js CHANGED
@@ -10,84 +10,32 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- var __assign = (this && this.__assign) || function () {
14
- __assign = Object.assign || function(t) {
15
- for (var s, i = 1, n = arguments.length; i < n; i++) {
16
- s = arguments[i];
17
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
18
- t[p] = s[p];
19
- }
20
- return t;
21
- };
22
- return __assign.apply(this, arguments);
23
- };
24
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
25
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
26
- return new (P || (P = Promise))(function (resolve, reject) {
27
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
28
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
29
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
30
- step((generator = generator.apply(thisArg, _arguments || [])).next());
31
- });
32
- };
33
- var __generator = (this && this.__generator) || function (thisArg, body) {
34
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
35
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
36
- function verb(n) { return function (v) { return step([n, v]); }; }
37
- function step(op) {
38
- if (f) throw new TypeError("Generator is already executing.");
39
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
40
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
41
- if (y = 0, t) op = [op[0] & 2, t.value];
42
- switch (op[0]) {
43
- case 0: case 1: t = op; break;
44
- case 4: _.label++; return { value: op[1], done: false };
45
- case 5: _.label++; y = op[1]; op = [0]; continue;
46
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
47
- default:
48
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
49
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
50
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
51
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
52
- if (t[2]) _.ops.pop();
53
- _.trys.pop(); continue;
54
- }
55
- op = body.call(thisArg, _);
56
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
57
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
58
- }
59
- };
60
13
  import { QueryRequest_ReportType } from '@parca/client';
61
- export var hexifyAddress = function (address) {
14
+ export const hexifyAddress = (address) => {
62
15
  if (address == null) {
63
16
  return '';
64
17
  }
65
- return "0x".concat(BigInt(address).toString(16));
18
+ return `0x${address.toString(16)}`;
19
+ };
20
+ export const downloadPprof = async (request, queryClient, metadata) => {
21
+ const req = {
22
+ ...request,
23
+ reportType: QueryRequest_ReportType.PPROF,
24
+ };
25
+ const { response } = await queryClient.query(req, { meta: metadata });
26
+ if (response.report.oneofKind !== 'pprof') {
27
+ throw new Error(`Expected pprof report, got: ${response.report.oneofKind !== undefined ? response.report.oneofKind : 'undefined'}`);
28
+ }
29
+ const blob = new Blob([response.report.pprof], { type: 'application/octet-stream' });
30
+ return blob;
66
31
  };
67
- export var downloadPprof = function (request, queryClient, metadata) { return __awaiter(void 0, void 0, void 0, function () {
68
- var req, response, blob;
69
- return __generator(this, function (_a) {
70
- switch (_a.label) {
71
- case 0:
72
- req = __assign(__assign({}, request), { reportType: QueryRequest_ReportType.PPROF });
73
- return [4 /*yield*/, queryClient.query(req, { meta: metadata })];
74
- case 1:
75
- response = (_a.sent()).response;
76
- if (response.report.oneofKind !== 'pprof') {
77
- throw new Error("Expected pprof report, got: ".concat(response.report.oneofKind !== undefined ? response.report.oneofKind : 'undefined'));
78
- }
79
- blob = new Blob([response.report.pprof], { type: 'application/octet-stream' });
80
- return [2 /*return*/, blob];
81
- }
82
- });
83
- }); };
84
- export var truncateString = function (str, num) {
32
+ export const truncateString = (str, num) => {
85
33
  if (str.length <= num) {
86
34
  return str;
87
35
  }
88
36
  return str.slice(0, num) + '...';
89
37
  };
90
- export var truncateStringReverse = function (str, num) {
38
+ export const truncateStringReverse = (str, num) => {
91
39
  if (str.length <= num) {
92
40
  return str;
93
41
  }
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.16.184",
3
+ "version": "0.16.185",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
- "@parca/client": "^0.16.73",
7
- "@parca/components": "^0.16.145",
6
+ "@parca/client": "^0.16.74",
7
+ "@parca/components": "^0.16.146",
8
8
  "@parca/dynamicsize": "^0.16.54",
9
9
  "@parca/hooks": "^0.0.2",
10
10
  "@parca/parser": "^0.16.55",
11
- "@parca/store": "^0.16.77",
12
- "@parca/utilities": "^0.0.7",
11
+ "@parca/store": "^0.16.78",
12
+ "@parca/utilities": "^0.0.8",
13
13
  "@tanstack/react-query": "^4.0.5",
14
14
  "@types/react-beautiful-dnd": "^13.1.3",
15
15
  "d3": "7.8.5",
@@ -46,5 +46,5 @@
46
46
  "access": "public",
47
47
  "registry": "https://registry.npmjs.org/"
48
48
  },
49
- "gitHead": "850348dc0238c127c875f12ac53b48856ee3c5a2"
49
+ "gitHead": "e1dc36ad29a6efe06f45460bb721325df9416a6b"
50
50
  }
@@ -64,7 +64,7 @@ const Callgraph = ({data, svgString, sampleUnit, width}: Props): JSX.Element =>
64
64
  const maxColor: string = getNewSpanColor(isDarkMode);
65
65
  const minColor: string = d3.scaleLinear([isDarkMode ? 'black' : 'white', maxColor])(0.3);
66
66
  const colorRange: [string, string] = [minColor, maxColor];
67
- const cumulatives = data.edges.map((edge: CallgraphEdge) => parseInt(edge.cumulative));
67
+ const cumulatives = data.edges.map((edge: CallgraphEdge) => edge.cumulative.toString());
68
68
  const cumulativesRange = d3.extent(cumulatives);
69
69
  const colorScale = d3
70
70
  .scaleSequentialLog(d3.interpolateBlues)
@@ -147,8 +147,8 @@ const Callgraph = ({data, svgString, sampleUnit, width}: Props): JSX.Element =>
147
147
  <GraphTooltip
148
148
  type="callgraph"
149
149
  unit={sampleUnit}
150
- total={parseInt(data.cumulative)}
151
- totalUnfiltered={parseInt(data.cumulative)}
150
+ total={data.cumulative}
151
+ totalUnfiltered={data.cumulative}
152
152
  contextElement={containerRef.current}
153
153
  />
154
154
  )}
@@ -117,7 +117,7 @@ export const jsonToDot = ({
117
117
 
118
118
  const edgesAsStrings = edges.map((edge: CallgraphEdge) => {
119
119
  const dataAttributes = {
120
- cumulative: edge.cumulative,
120
+ cumulative: Number(edge.cumulative),
121
121
  color: withAlphaHex(colorRange[1], colorOpacityScale(Number(edge.cumulative))),
122
122
  className: 'edge',
123
123
  // boxHeight: DEFAULT_NODE_HEIGHT,
@@ -31,7 +31,7 @@ import {
31
31
  } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
32
32
  import {useKeyDown} from '@parca/components';
33
33
  import {selectHoveringNode, useAppSelector} from '@parca/store';
34
- import {getLastItem, valueFormatter} from '@parca/utilities';
34
+ import {divide, getLastItem, valueFormatter} from '@parca/utilities';
35
35
 
36
36
  import {hexifyAddress, truncateString, truncateStringReverse} from '../';
37
37
  import {ExpandOnHover} from './ExpandOnHoverValue';
@@ -46,7 +46,7 @@ interface ExtendedCallgraphNodeMeta extends CallgraphNodeMeta {
46
46
  }
47
47
 
48
48
  interface HoveringNode extends FlamegraphRootNode, FlamegraphNode, CallgraphNode {
49
- diff: string;
49
+ diff: bigint;
50
50
  meta?: FlamegraphNodeMeta | ExtendedCallgraphNodeMeta;
51
51
  }
52
52
 
@@ -54,8 +54,8 @@ interface GraphTooltipProps {
54
54
  x?: number;
55
55
  y?: number;
56
56
  unit: string;
57
- total: number;
58
- totalUnfiltered: number;
57
+ total: bigint;
58
+ totalUnfiltered: bigint;
59
59
  hoveringNode?: HoveringNode;
60
60
  contextElement: Element | null;
61
61
  isFixed?: boolean;
@@ -158,11 +158,11 @@ const TooltipMetaInfo = ({
158
158
  if (hoveringNode.meta?.function == null) return '<unknown>';
159
159
 
160
160
  return `${hoveringNode.meta.function.filename} ${
161
- hoveringNode.meta.line?.line !== undefined && hoveringNode.meta.line?.line !== '0'
161
+ hoveringNode.meta.line?.line !== undefined && hoveringNode.meta.line?.line !== 0n
162
162
  ? ` +${hoveringNode.meta.line.line.toString()}`
163
163
  : `${
164
164
  hoveringNode.meta.function?.startLine !== undefined &&
165
- hoveringNode.meta.function?.startLine !== '0'
165
+ hoveringNode.meta.function?.startLine !== 0n
166
166
  ? ` +${hoveringNode.meta.function.startLine}`
167
167
  : ''
168
168
  }`
@@ -192,7 +192,7 @@ const TooltipMetaInfo = ({
192
192
  <td className="w-1/4">Address</td>
193
193
  <td className="w-3/4 break-all">
194
194
  {hoveringNode.meta?.location?.address == null ||
195
- hoveringNode.meta?.location.address === '0' ? (
195
+ hoveringNode.meta?.location.address === 0n ? (
196
196
  <NoData />
197
197
  ) : (
198
198
  <CopyToClipboard
@@ -255,8 +255,8 @@ export const GraphTooltipContent = ({
255
255
  }: {
256
256
  hoveringNode: HoveringNode;
257
257
  unit: string;
258
- total: number;
259
- totalUnfiltered: number;
258
+ total: bigint;
259
+ totalUnfiltered: bigint;
260
260
  isFixed: boolean;
261
261
  strings?: string[];
262
262
  mappings?: Mapping[];
@@ -275,22 +275,22 @@ export const GraphTooltipContent = ({
275
275
  timeoutHandle = setTimeout(() => setIsCopied(false), 3000);
276
276
  };
277
277
 
278
- const hoveringNodeCumulative = parseFloat(hoveringNode.cumulative);
279
- const diff = hoveringNode.diff === undefined ? 0 : parseFloat(hoveringNode.diff);
278
+ const hoveringNodeCumulative = hoveringNode.cumulative;
279
+ const diff = hoveringNode.diff;
280
280
  const prevValue = hoveringNodeCumulative - diff;
281
- const diffRatio = Math.abs(diff) > 0 ? diff / prevValue : 0;
281
+ const diffRatio = diff !== 0n ? divide(diff, prevValue) : 0;
282
282
  const diffSign = diff > 0 ? '+' : '';
283
283
  const diffValueText = diffSign + valueFormatter(diff, unit, 1);
284
284
  const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
285
285
  const diffText = `${diffValueText} (${diffPercentageText})`;
286
286
 
287
- const getTextForCumulative = (hoveringNodeCumulative: number): string => {
287
+ const getTextForCumulative = (hoveringNodeCumulative: bigint): string => {
288
288
  const filtered =
289
289
  totalUnfiltered > total
290
- ? ` / ${((hoveringNodeCumulative * 100) / total).toFixed(2)}% of filtered`
290
+ ? ` / ${divide(hoveringNodeCumulative * 100n, total).toFixed(2)}% of filtered`
291
291
  : '';
292
292
  return `${valueFormatter(hoveringNodeCumulative, unit, 2)}
293
- (${((hoveringNodeCumulative * 100) / totalUnfiltered).toFixed(2)}%${filtered})`;
293
+ (${divide(hoveringNodeCumulative * 100n, totalUnfiltered).toFixed(2)}%${filtered})`;
294
294
  };
295
295
 
296
296
  return (
@@ -314,7 +314,7 @@ export const GraphTooltipContent = ({
314
314
  ) : (
315
315
  <>
316
316
  {hoveringNode.meta.location !== undefined &&
317
- parseInt(hoveringNode.meta.location.address, 10) !== 0 ? (
317
+ hoveringNode.meta.location.address !== 0n ? (
318
318
  <CopyToClipboard
319
319
  onCopy={onCopy}
320
320
  text={hexifyAddress(hoveringNode.meta.location.address)}
@@ -347,7 +347,7 @@ export const GraphTooltipContent = ({
347
347
  </CopyToClipboard>
348
348
  </td>
349
349
  </tr>
350
- {hoveringNode.diff !== undefined && diff !== 0 && (
350
+ {hoveringNode.diff !== undefined && diff !== 0n && (
351
351
  <tr>
352
352
  <td className="w-1/4">Diff</td>
353
353
  <td className="w-3/4">
@@ -139,8 +139,8 @@ export const RawMetricsGraph = ({
139
139
  metric,
140
140
  values: s.samples.reduce<number[][]>(function (agg: number[][], d: MetricsSample) {
141
141
  if (d.timestamp !== undefined && d.valuePerSecond !== undefined) {
142
- const t = (+d.timestamp.seconds * 1e9 + d.timestamp.nanos) / 1e6; // https://github.com/microsoft/TypeScript/issues/5710#issuecomment-157886246
143
- agg.push([t, d.valuePerSecond, parseFloat(d.value), parseFloat(d.duration)]);
142
+ const t = (Number(d.timestamp.seconds) * 1e9 + d.timestamp.nanos) / 1e6; // https://github.com/microsoft/TypeScript/issues/5710#issuecomment-157886246
143
+ agg.push([t, d.valuePerSecond, Number(d.value), Number(d.duration)]);
144
144
  }
145
145
  return agg;
146
146
  }, []),
@@ -474,7 +474,7 @@ export const RawMetricsGraph = ({
474
474
  >
475
475
  <line stroke="currentColor" x2={-6} />
476
476
  <text fill="currentColor" x={-9} dy={'0.32em'}>
477
- {valueFormatter(d, sampleUnit, 1)}
477
+ {valueFormatter(1000, sampleUnit, 1)}
478
478
  </text>
479
479
  </g>
480
480
  ))}
@@ -14,7 +14,6 @@
14
14
  import React, {useMemo} from 'react';
15
15
 
16
16
  import cx from 'classnames';
17
- import {scaleLinear} from 'd3-scale';
18
17
 
19
18
  import {FlamegraphNode} from '@parca/client';
20
19
  import {
@@ -24,7 +23,7 @@ import {
24
23
  } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
25
24
  import {useKeyDown} from '@parca/components';
26
25
  import {selectBinaries, setHoveringNode, useAppDispatch, useAppSelector} from '@parca/store';
27
- import {isSearchMatch} from '@parca/utilities';
26
+ import {isSearchMatch, scaleLinear} from '@parca/utilities';
28
27
 
29
28
  import useNodeColor from './useNodeColor';
30
29
  import {nodeLabel} from './utils';
@@ -39,13 +38,13 @@ interface IcicleGraphNodesProps {
39
38
  functions: ParcaFunction[];
40
39
  x: number;
41
40
  y: number;
42
- total: number;
41
+ total: bigint;
43
42
  totalWidth: number;
44
43
  level: number;
45
44
  curPath: string[];
46
45
  setCurPath: (path: string[]) => void;
47
46
  path: string[];
48
- xScale: (value: number) => number;
47
+ xScale: (value: bigint) => number;
49
48
  searchString?: string;
50
49
  compareMode: boolean;
51
50
  }
@@ -82,7 +81,7 @@ export const IcicleGraphNodes = React.memo(function IcicleGraphNodesNoMemo({
82
81
  return (
83
82
  <g transform={`translate(${x}, ${y})`}>
84
83
  {nodes.map(function nodeMapper(d, i) {
85
- const start = nodes.slice(0, i).reduce((sum, d) => sum + parseFloat(d.cumulative), 0);
84
+ const start = nodes.slice(0, i).reduce((sum, d) => sum + d.cumulative, 0n);
86
85
  const xStart = xScale(start);
87
86
 
88
87
  return (
@@ -125,9 +124,9 @@ interface IcicleNodeProps {
125
124
  locations: Location[];
126
125
  functions: ParcaFunction[];
127
126
  path: string[];
128
- total: number;
127
+ total: bigint;
129
128
  setCurPath: (path: string[]) => void;
130
- xScale: (value: number) => number;
129
+ xScale: (value: bigint) => number;
131
130
  isRoot?: boolean;
132
131
  searchString?: string;
133
132
  compareMode: boolean;
@@ -176,11 +175,11 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
176
175
  const isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
177
176
  const styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
178
177
  const nextLevel = level + 1;
179
- const cumulative = parseFloat(data.cumulative);
178
+ const cumulative = data.cumulative;
180
179
  const nextCurPath = curPath.length === 0 ? [] : curPath.slice(1);
181
180
  const newXScale =
182
181
  nextCurPath.length === 0 && curPath.length === 1
183
- ? scaleLinear().domain([0, cumulative]).range([0, totalWidth])
182
+ ? scaleLinear([0n, cumulative], [0, totalWidth])
184
183
  : xScale;
185
184
 
186
185
  const width =
@@ -203,7 +202,7 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
203
202
  if (isShiftDown) return;
204
203
 
205
204
  // need to add id and flat for tooltip purposes
206
- dispatch(setHoveringNode({...data, id: '', flat: ''}));
205
+ dispatch(setHoveringNode({...data, id: '', flat: 0n}));
207
206
  };
208
207
  const onMouseLeave = (): void => {
209
208
  if (isShiftDown) return;
@@ -13,11 +13,9 @@
13
13
 
14
14
  import {memo, useEffect, useMemo, useRef, useState} from 'react';
15
15
 
16
- import {scaleLinear} from 'd3-scale';
17
-
18
16
  import {Flamegraph} from '@parca/client';
19
17
  import {setHoveringNode, useAppDispatch} from '@parca/store';
20
- import {selectQueryParam, type NavigateFunction} from '@parca/utilities';
18
+ import {scaleLinear, selectQueryParam, type NavigateFunction} from '@parca/utilities';
21
19
 
22
20
  import GraphTooltip from '../../GraphTooltip';
23
21
  import ColorStackLegend from './ColorStackLegend';
@@ -26,8 +24,8 @@ import useColoredGraph from './useColoredGraph';
26
24
 
27
25
  interface IcicleGraphProps {
28
26
  graph: Flamegraph;
29
- total: number;
30
- filtered: number;
27
+ total: bigint;
28
+ filtered: bigint;
31
29
  sampleUnit: string;
32
30
  width?: number;
33
31
  curPath: string[];
@@ -65,9 +63,7 @@ export const IcicleGraph = memo(function IcicleGraph({
65
63
  if (width === undefined) {
66
64
  return () => 0;
67
65
  }
68
- return scaleLinear()
69
- .domain([0, Number(total)])
70
- .range([0, width]);
66
+ return scaleLinear([0n, total], [0, width]);
71
67
  }, [total, width]);
72
68
 
73
69
  if (coloredGraph.root === undefined || width === undefined) {
@@ -29,8 +29,8 @@ const useNodeColor = ({data, compareMode}: Props): string => {
29
29
 
30
30
  const color: string = useMemo(() => {
31
31
  if (compareMode) {
32
- const diff = parseFloat(data.diff);
33
- const cumulative = parseFloat(data.cumulative);
32
+ const diff = data.diff;
33
+ const cumulative = data.cumulative;
34
34
  return diffColor(diff, cumulative, isDarkMode);
35
35
  }
36
36
 
@@ -16,7 +16,7 @@ import {useEffect, useMemo} from 'react';
16
16
  import {Flamegraph} from '@parca/client';
17
17
  import {Button} from '@parca/components';
18
18
  import {useContainerDimensions} from '@parca/hooks';
19
- import {selectQueryParam, type NavigateFunction} from '@parca/utilities';
19
+ import {divide, selectQueryParam, type NavigateFunction} from '@parca/utilities';
20
20
 
21
21
  import DiffLegend from '../components/DiffLegend';
22
22
  import {IcicleGraph} from './IcicleGraph';
@@ -28,8 +28,8 @@ export type ResizeHandler = (width: number, height: number) => void;
28
28
  interface ProfileIcicleGraphProps {
29
29
  width?: number;
30
30
  graph: Flamegraph | undefined;
31
- total: number;
32
- filtered: number;
31
+ total: bigint;
32
+ filtered: bigint;
33
33
  sampleUnit: string;
34
34
  curPath: string[] | [];
35
35
  setNewCurPath: (path: string[]) => void;
@@ -75,20 +75,20 @@ const ProfileIcicleGraph = ({
75
75
  return ['0', '0', false, '0', '0', false, '0', '0'];
76
76
  }
77
77
 
78
- const trimmed = parseInt(graph.trimmed);
78
+ const trimmed = graph.trimmed;
79
79
 
80
80
  const totalUnfiltered = total + filtered;
81
81
  // safeguard against division by zero
82
- const totalUnfilteredDivisor = totalUnfiltered > 0 ? totalUnfiltered : 1;
82
+ const totalUnfilteredDivisor = totalUnfiltered > 0 ? totalUnfiltered : 1n;
83
83
 
84
84
  return [
85
85
  numberFormatter.format(total),
86
86
  numberFormatter.format(totalUnfiltered),
87
87
  trimmed > 0,
88
88
  numberFormatter.format(trimmed),
89
- numberFormatter.format((trimmed * 100) / totalUnfilteredDivisor),
89
+ numberFormatter.format(divide(trimmed * 100n, totalUnfilteredDivisor)),
90
90
  filtered > 0,
91
- numberFormatter.format((total * 100) / totalUnfilteredDivisor),
91
+ numberFormatter.format(divide(total * 100n, totalUnfilteredDivisor)),
92
92
  ];
93
93
  }, [graph, filtered, total]);
94
94
 
@@ -112,7 +112,7 @@ const ProfileIcicleGraph = ({
112
112
 
113
113
  if (graph === undefined) return <div>no data...</div>;
114
114
 
115
- if (total === 0 && !loading) return <>Profile has no samples</>;
115
+ if (total === 0n && !loading) return <>Profile has no samples</>;
116
116
 
117
117
  if (isTrimmed) {
118
118
  console.info(`Trimmed ${trimmedFormatted} (${trimmedPercentage}%) too small values.`);
@@ -245,8 +245,8 @@ export const ProfileView = ({
245
245
  curPath={curPath}
246
246
  setNewCurPath={setNewCurPath}
247
247
  graph={flamegraphData.data}
248
- total={Number(total)}
249
- filtered={Number(filtered)}
248
+ total={total}
249
+ filtered={filtered}
250
250
  sampleUnit={sampleUnit}
251
251
  onContainerResize={onFlamegraphContainerResize}
252
252
  navigateTo={navigateTo}
@@ -100,7 +100,7 @@ export const TopTable = React.memo(function TopTable({
100
100
  }),
101
101
  columnHelper.accessor('flat', {
102
102
  header: () => 'Flat',
103
- cell: info => valueFormatter(Number(info.getValue()), unit, 2),
103
+ cell: info => valueFormatter(info.getValue(), unit, 2),
104
104
  size: 150,
105
105
  meta: {
106
106
  align: 'right',
@@ -109,7 +109,7 @@ export const TopTable = React.memo(function TopTable({
109
109
  }),
110
110
  columnHelper.accessor('cumulative', {
111
111
  header: () => 'Cumulative',
112
- cell: info => valueFormatter(Number(info.getValue()), unit, 2),
112
+ cell: info => valueFormatter(info.getValue(), unit, 2),
113
113
  size: 150,
114
114
  meta: {
115
115
  align: 'right',
@@ -121,7 +121,7 @@ export const TopTable = React.memo(function TopTable({
121
121
  cols.push(
122
122
  columnHelper.accessor('diff', {
123
123
  header: () => 'Diff',
124
- cell: info => addPlusSign(valueFormatter(Number(info.getValue()), unit, 2)),
124
+ cell: info => addPlusSign(valueFormatter(info.getValue(), unit, 2)),
125
125
  size: 150,
126
126
  meta: {
127
127
  align: 'right',
package/src/utils.ts CHANGED
@@ -15,11 +15,11 @@ import type {RpcMetadata} from '@protobuf-ts/runtime-rpc';
15
15
 
16
16
  import {QueryRequest, QueryRequest_ReportType, QueryServiceClient} from '@parca/client';
17
17
 
18
- export const hexifyAddress = (address?: string): string => {
18
+ export const hexifyAddress = (address?: bigint): string => {
19
19
  if (address == null) {
20
20
  return '';
21
21
  }
22
- return `0x${BigInt(address).toString(16)}`;
22
+ return `0x${address.toString(16)}`;
23
23
  };
24
24
 
25
25
  export const downloadPprof = async (