@parca/profile 0.12.32 → 0.12.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.12.33](https://github.com/parca-dev/parca/compare/ui-v0.12.32...ui-v0.12.33) (2022-05-02)
7
+
8
+ ## [0.12.27](https://github.com/parca-dev/parca/compare/ui-v0.12.26...ui-v0.12.27) (2022-04-29)
9
+
10
+ ## [0.12.26](https://github.com/parca-dev/parca/compare/ui-v0.12.23...ui-v0.12.26) (2022-04-28)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.12.32](https://github.com/parca-dev/parca/compare/ui-v0.12.31...ui-v0.12.32) (2022-05-02)
7
15
 
8
16
  ## [0.12.29](https://github.com/parca-dev/parca/compare/ui-v0.12.26...ui-v0.12.29) (2022-04-29)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.12.32",
3
+ "version": "0.12.33",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@parca/client": "^0.12.30",
@@ -19,5 +19,5 @@
19
19
  "access": "public",
20
20
  "registry": "https://registry.npmjs.org/"
21
21
  },
22
- "gitHead": "f065972a25829a59cacaec8feba3156fd60dc6fd"
22
+ "gitHead": "a7d406cff5634de7835a0e69c42c7acec967828b"
23
23
  }
@@ -4,20 +4,49 @@ import {pointer} from 'd3-selection';
4
4
  import {scaleLinear} from 'd3-scale';
5
5
  import {Flamegraph, FlamegraphNode, FlamegraphRootNode} from '@parca/client';
6
6
  import {usePopper} from 'react-popper';
7
- import {getLastItem, valueFormatter} from '@parca/functions';
7
+ import {getLastItem, valueFormatter, diffColor} from '@parca/functions';
8
8
  import {useAppSelector, selectDarkMode} from '@parca/store';
9
9
 
10
- const RowHeight = 26;
10
+ interface IcicleGraphProps {
11
+ graph: Flamegraph;
12
+ sampleUnit: string;
13
+ width?: number;
14
+ curPath: string[];
15
+ setCurPath: (path: string[]) => void;
16
+ }
11
17
 
12
- const icicleRectStyles = {
13
- cursor: 'pointer',
14
- transition: 'opacity .15s linear',
15
- };
16
- const fadedIcicleRectStyles = {
17
- cursor: 'pointer',
18
- transition: 'opacity .15s linear',
19
- opacity: '0.5',
20
- };
18
+ interface IcicleGraphNodesProps {
19
+ data: FlamegraphNode[];
20
+ x: number;
21
+ y: number;
22
+ total: number;
23
+ totalWidth: number;
24
+ level: number;
25
+ curPath: string[];
26
+ setCurPath: (path: string[]) => void;
27
+ setHoveringNode: (node: FlamegraphNode | FlamegraphRootNode | undefined) => void;
28
+ path: string[];
29
+ xScale: (value: number) => number;
30
+ }
31
+
32
+ interface FlamegraphTooltipProps {
33
+ x: number;
34
+ y: number;
35
+ unit: string;
36
+ total: number;
37
+ hoveringNode: FlamegraphNode | FlamegraphRootNode | undefined;
38
+ contextElement: Element | null;
39
+ }
40
+
41
+ interface IcicleGraphRootNodeProps {
42
+ node: FlamegraphRootNode;
43
+ xScale: (value: number) => number;
44
+ total: number;
45
+ totalWidth: number;
46
+ curPath: string[];
47
+ setCurPath: (path: string[]) => void;
48
+ setHoveringNode: (node: FlamegraphNode | FlamegraphRootNode | undefined) => void;
49
+ }
21
50
 
22
51
  interface IcicleRectProps {
23
52
  x: number;
@@ -32,6 +61,18 @@ interface IcicleRectProps {
32
61
  curPath: string[];
33
62
  }
34
63
 
64
+ const RowHeight = 26;
65
+
66
+ const icicleRectStyles = {
67
+ cursor: 'pointer',
68
+ transition: 'opacity .15s linear',
69
+ };
70
+ const fadedIcicleRectStyles = {
71
+ cursor: 'pointer',
72
+ transition: 'opacity .15s linear',
73
+ opacity: '0.5',
74
+ };
75
+
35
76
  function IcicleRect({
36
77
  x,
37
78
  y,
@@ -75,20 +116,6 @@ function IcicleRect({
75
116
  );
76
117
  }
77
118
 
78
- interface IcicleGraphNodesProps {
79
- data: FlamegraphNode[];
80
- x: number;
81
- y: number;
82
- total: number;
83
- totalWidth: number;
84
- level: number;
85
- curPath: string[];
86
- setCurPath: (path: string[]) => void;
87
- setHoveringNode: (node: FlamegraphNode | FlamegraphRootNode | undefined) => void;
88
- path: string[];
89
- xScale: (value: number) => number;
90
- }
91
-
92
119
  export function nodeLabel(node: FlamegraphNode): string {
93
120
  if (node.meta === undefined) return '<unknown>';
94
121
  const mapping = `${
@@ -109,26 +136,6 @@ export function nodeLabel(node: FlamegraphNode): string {
109
136
  return fallback === '' ? '<unknown>' : fallback;
110
137
  }
111
138
 
112
- function diffColor(diff: number, cumulative: number, isDarkMode: boolean): string {
113
- const prevValue = cumulative - diff;
114
- const diffRatio = prevValue > 0 ? (Math.abs(diff) > 0 ? diff / prevValue : 0) : 1.0;
115
-
116
- const diffTransparency =
117
- Math.abs(diff) > 0 ? Math.min((Math.abs(diffRatio) / 2 + 0.5) * 0.8, 0.8) : 0;
118
-
119
- const newSpanColor = isDarkMode ? '#B3BAE1' : '#929FEB';
120
- const increasedSpanColor = isDarkMode
121
- ? `rgba(255, 177, 204, ${diffTransparency})`
122
- : `rgba(254, 153, 187, ${diffTransparency})`;
123
- const reducedSpanColor = isDarkMode
124
- ? `rgba(103, 158, 92, ${diffTransparency})`
125
- : `rgba(164, 214, 153, ${diffTransparency})`;
126
-
127
- const color = diff === 0 ? newSpanColor : diff > 0 ? increasedSpanColor : reducedSpanColor;
128
-
129
- return color;
130
- }
131
-
132
139
  export function IcicleGraphNodes({
133
140
  data,
134
141
  x,
@@ -225,15 +232,6 @@ export function IcicleGraphNodes({
225
232
 
226
233
  const MemoizedIcicleGraphNodes = React.memo(IcicleGraphNodes);
227
234
 
228
- interface FlamegraphTooltipProps {
229
- x: number;
230
- y: number;
231
- unit: string;
232
- total: number;
233
- hoveringNode: FlamegraphNode | FlamegraphRootNode | undefined;
234
- contextElement: Element | null;
235
- }
236
-
237
235
  const FlamegraphNodeTooltipTableRows = ({
238
236
  hoveringNode,
239
237
  }: {
@@ -424,16 +422,6 @@ export const FlamegraphTooltip = ({
424
422
  );
425
423
  };
426
424
 
427
- interface IcicleGraphRootNodeProps {
428
- node: FlamegraphRootNode;
429
- xScale: (value: number) => number;
430
- total: number;
431
- totalWidth: number;
432
- curPath: string[];
433
- setCurPath: (path: string[]) => void;
434
- setHoveringNode: (node: FlamegraphNode | FlamegraphRootNode | undefined) => void;
435
- }
436
-
437
425
  export function IcicleGraphRootNode({
438
426
  node,
439
427
  xScale,
@@ -487,14 +475,6 @@ export function IcicleGraphRootNode({
487
475
 
488
476
  const MemoizedIcicleGraphRootNode = React.memo(IcicleGraphRootNode);
489
477
 
490
- interface IcicleGraphProps {
491
- graph: Flamegraph;
492
- sampleUnit: string;
493
- width?: number;
494
- curPath: string[];
495
- setCurPath: (path: string[]) => void;
496
- }
497
-
498
478
  export default function IcicleGraph({
499
479
  graph,
500
480
  width,
@@ -1,5 +1,8 @@
1
- import IcicleGraph from './IcicleGraph';
2
1
  import {Flamegraph} from '@parca/client';
2
+ import {useAppSelector, selectCompareMode} from '@parca/store';
3
+
4
+ import DiffLegend from './components/DiffLegend';
5
+ import IcicleGraph from './IcicleGraph';
3
6
 
4
7
  interface ProfileIcicleGraphProps {
5
8
  width?: number;
@@ -16,18 +19,23 @@ const ProfileIcicleGraph = ({
16
19
  setNewCurPath,
17
20
  sampleUnit,
18
21
  }: ProfileIcicleGraphProps) => {
22
+ const compareMode = useAppSelector(selectCompareMode);
23
+
19
24
  if (graph === undefined) return <div>no data...</div>;
20
25
  const total = graph.total;
21
26
  if (parseFloat(total) === 0) return <>Profile has no samples</>;
22
27
 
23
28
  return (
24
- <IcicleGraph
25
- width={width}
26
- graph={graph}
27
- curPath={curPath}
28
- setCurPath={setNewCurPath}
29
- sampleUnit={sampleUnit}
30
- />
29
+ <>
30
+ {compareMode && <DiffLegend />}
31
+ <IcicleGraph
32
+ width={width}
33
+ graph={graph}
34
+ curPath={curPath}
35
+ setCurPath={setNewCurPath}
36
+ sampleUnit={sampleUnit}
37
+ />
38
+ </>
31
39
  );
32
40
  };
33
41
 
@@ -173,7 +173,7 @@ export const ProfileView = ({
173
173
  </div>
174
174
 
175
175
  <Button
176
- color={`${currentView === 'table' ? 'primary' : 'neutral'}`}
176
+ variant={`${currentView === 'table' ? 'primary' : 'neutral'}`}
177
177
  className="rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons"
178
178
  onClick={() => switchProfileView('table')}
179
179
  >
@@ -181,7 +181,7 @@ export const ProfileView = ({
181
181
  </Button>
182
182
 
183
183
  <Button
184
- color={`${currentView === 'both' ? 'primary' : 'neutral'}`}
184
+ variant={`${currentView === 'both' ? 'primary' : 'neutral'}`}
185
185
  className="rounded-tl-none rounded-tr-none rounded-bl-none rounded-br-none border-l-0 border-r-0 w-auto px-8 whitespace-nowrap no-outline-on-buttons no-outline-on-buttons text-ellipsis"
186
186
  onClick={() => switchProfileView('both')}
187
187
  >
@@ -189,7 +189,7 @@ export const ProfileView = ({
189
189
  </Button>
190
190
 
191
191
  <Button
192
- color={`${currentView === 'icicle' ? 'primary' : 'neutral'}`}
192
+ variant={`${currentView === 'icicle' ? 'primary' : 'neutral'}`}
193
193
  className="rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons"
194
194
  onClick={() => switchProfileView('icicle')}
195
195
  >
@@ -0,0 +1,99 @@
1
+ import {Fragment, useState} from 'react';
2
+ import {Popover, Transition} from '@headlessui/react';
3
+ import {useAppSelector, selectDarkMode} from '@parca/store';
4
+ import {getNewSpanColor, getIncreasedSpanColor, getReducedSpanColor} from '@parca/functions';
5
+ import {usePopper} from 'react-popper';
6
+
7
+ const transparencyValues = [-100, -80, -60, -40, -20, 0, 20, 40, 60, 80, 100];
8
+
9
+ const DiffLegendBar = ({
10
+ onMouseEnter,
11
+ onMouseLeave,
12
+ }: {
13
+ onMouseEnter: () => void;
14
+ onMouseLeave: () => void;
15
+ }) => {
16
+ const isDarkMode = useAppSelector(selectDarkMode);
17
+
18
+ return (
19
+ <div className="flex items-center m-2">
20
+ {transparencyValues.map(value => {
21
+ const valueAsPercentage = value / 100;
22
+ const absoluteValue = Math.abs(valueAsPercentage);
23
+ return (
24
+ <div
25
+ onMouseEnter={onMouseEnter}
26
+ onMouseLeave={onMouseLeave}
27
+ className="w-8 h-4"
28
+ key={valueAsPercentage}
29
+ style={{
30
+ backgroundColor:
31
+ absoluteValue === 0
32
+ ? getNewSpanColor(isDarkMode)
33
+ : valueAsPercentage > 0
34
+ ? getIncreasedSpanColor(absoluteValue, isDarkMode)
35
+ : getReducedSpanColor(absoluteValue, isDarkMode),
36
+ }}
37
+ ></div>
38
+ );
39
+ })}
40
+ </div>
41
+ );
42
+ };
43
+
44
+ const DiffLegend = () => {
45
+ const [showLegendTooltip, setShowLegendTooltip] = useState(false);
46
+ const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
47
+ let [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null);
48
+
49
+ const {styles, attributes, ...popperProps} = usePopper(referenceElement, popperElement, {
50
+ placement: 'auto-start',
51
+ strategy: 'absolute',
52
+ });
53
+
54
+ const handleMouseEnter = () => {
55
+ setShowLegendTooltip(true);
56
+ };
57
+ const handleMouseLeave = () => {
58
+ setShowLegendTooltip(false);
59
+ };
60
+
61
+ return (
62
+ <div className="mt-1 mb-2">
63
+ <div ref={setReferenceElement} className="flex items-center justify-center">
64
+ <span>Better</span>
65
+ <DiffLegendBar onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} />
66
+ <span>Worse</span>
67
+ </div>
68
+ <Popover className="relative">
69
+ {() => (
70
+ <Transition
71
+ show={showLegendTooltip}
72
+ as={Fragment}
73
+ enter="transition ease-out duration-200"
74
+ enterFrom="opacity-0 translate-y-1"
75
+ enterTo="opacity-100 translate-y-0"
76
+ leave="transition ease-in duration-150"
77
+ leaveFrom="opacity-100 translate-y-0"
78
+ leaveTo="opacity-0 translate-y-1"
79
+ >
80
+ <Popover.Panel ref={setPopperElement} style={styles.popper} {...attributes.popper}>
81
+ <div className="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
82
+ <div className="p-4 bg-gray-50 dark:bg-gray-800">
83
+ <div className="flex items-center justify-center"></div>
84
+ <span className="block text-sm text-gray-500 dark:text-gray-50">
85
+ This is a differential icicle graph, where a purple-colored node means
86
+ unchanged, and the darker the red, the worse the node got, and the darker the
87
+ green, the better the node got.
88
+ </span>
89
+ </div>
90
+ </div>
91
+ </Popover.Panel>
92
+ </Transition>
93
+ )}
94
+ </Popover>
95
+ </div>
96
+ );
97
+ };
98
+
99
+ export default DiffLegend;