@kylincloud/flamegraph 0.35.6

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 (267) hide show
  1. package/CHANGELOG.md +1211 -0
  2. package/LICENSE +202 -0
  3. package/README.md +251 -0
  4. package/dist/FlameGraph/FlameGraphComponent/CheckIcon.d.ts +2 -0
  5. package/dist/FlameGraph/FlameGraphComponent/CheckIcon.d.ts.map +1 -0
  6. package/dist/FlameGraph/FlameGraphComponent/ContextMenu.d.ts +17 -0
  7. package/dist/FlameGraph/FlameGraphComponent/ContextMenu.d.ts.map +1 -0
  8. package/dist/FlameGraph/FlameGraphComponent/ContextMenuHighlight.d.ts +14 -0
  9. package/dist/FlameGraph/FlameGraphComponent/ContextMenuHighlight.d.ts.map +1 -0
  10. package/dist/FlameGraph/FlameGraphComponent/DiffLegend.d.ts +9 -0
  11. package/dist/FlameGraph/FlameGraphComponent/DiffLegend.d.ts.map +1 -0
  12. package/dist/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.d.ts +8 -0
  13. package/dist/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.d.ts.map +1 -0
  14. package/dist/FlameGraph/FlameGraphComponent/Flamegraph.d.ts +96 -0
  15. package/dist/FlameGraph/FlameGraphComponent/Flamegraph.d.ts.map +1 -0
  16. package/dist/FlameGraph/FlameGraphComponent/Flamegraph_render.d.ts +27 -0
  17. package/dist/FlameGraph/FlameGraphComponent/Flamegraph_render.d.ts.map +1 -0
  18. package/dist/FlameGraph/FlameGraphComponent/GraphVizPane.d.ts +7 -0
  19. package/dist/FlameGraph/FlameGraphComponent/GraphVizPane.d.ts.map +1 -0
  20. package/dist/FlameGraph/FlameGraphComponent/Header.d.ts +12 -0
  21. package/dist/FlameGraph/FlameGraphComponent/Header.d.ts.map +1 -0
  22. package/dist/FlameGraph/FlameGraphComponent/Highlight.d.ts +18 -0
  23. package/dist/FlameGraph/FlameGraphComponent/Highlight.d.ts.map +1 -0
  24. package/dist/FlameGraph/FlameGraphComponent/LogoLink.d.ts +2 -0
  25. package/dist/FlameGraph/FlameGraphComponent/LogoLink.d.ts.map +1 -0
  26. package/dist/FlameGraph/FlameGraphComponent/color.d.ts +20 -0
  27. package/dist/FlameGraph/FlameGraphComponent/color.d.ts.map +1 -0
  28. package/dist/FlameGraph/FlameGraphComponent/colorPalette.d.ts +11 -0
  29. package/dist/FlameGraph/FlameGraphComponent/colorPalette.d.ts.map +1 -0
  30. package/dist/FlameGraph/FlameGraphComponent/constants.d.ts +6 -0
  31. package/dist/FlameGraph/FlameGraphComponent/constants.d.ts.map +1 -0
  32. package/dist/FlameGraph/FlameGraphComponent/index.d.ts +37 -0
  33. package/dist/FlameGraph/FlameGraphComponent/index.d.ts.map +1 -0
  34. package/dist/FlameGraph/FlameGraphComponent/murmur3.d.ts +2 -0
  35. package/dist/FlameGraph/FlameGraphComponent/murmur3.d.ts.map +1 -0
  36. package/dist/FlameGraph/FlameGraphComponent/testData.d.ts +53 -0
  37. package/dist/FlameGraph/FlameGraphComponent/testData.d.ts.map +1 -0
  38. package/dist/FlameGraph/FlameGraphComponent/utils.d.ts +6 -0
  39. package/dist/FlameGraph/FlameGraphComponent/utils.d.ts.map +1 -0
  40. package/dist/FlameGraph/FlameGraphComponent/viewTypes.d.ts +2 -0
  41. package/dist/FlameGraph/FlameGraphComponent/viewTypes.d.ts.map +1 -0
  42. package/dist/FlameGraph/FlameGraphRenderer.d.ts +86 -0
  43. package/dist/FlameGraph/FlameGraphRenderer.d.ts.map +1 -0
  44. package/dist/FlameGraph/decode.d.ts +27 -0
  45. package/dist/FlameGraph/decode.d.ts.map +1 -0
  46. package/dist/FlameGraph/normalize.d.ts +6 -0
  47. package/dist/FlameGraph/normalize.d.ts.map +1 -0
  48. package/dist/FlameGraph/uniqueness.d.ts +3 -0
  49. package/dist/FlameGraph/uniqueness.d.ts.map +1 -0
  50. package/dist/FlamegraphRenderer.d.ts +19 -0
  51. package/dist/FlamegraphRenderer.d.ts.map +1 -0
  52. package/dist/Icons.d.ts +9 -0
  53. package/dist/Icons.d.ts.map +1 -0
  54. package/dist/ProfilerTable.d.ts +21 -0
  55. package/dist/ProfilerTable.d.ts.map +1 -0
  56. package/dist/SharedQueryInput.d.ts +10 -0
  57. package/dist/SharedQueryInput.d.ts.map +1 -0
  58. package/dist/Toolbar.d.ts +31 -0
  59. package/dist/Toolbar.d.ts.map +1 -0
  60. package/dist/Tooltip/FlamegraphTooltip.d.ts +59 -0
  61. package/dist/Tooltip/FlamegraphTooltip.d.ts.map +1 -0
  62. package/dist/Tooltip/LeftClickIcon.d.ts +2 -0
  63. package/dist/Tooltip/LeftClickIcon.d.ts.map +1 -0
  64. package/dist/Tooltip/RightClickIcon.d.ts +2 -0
  65. package/dist/Tooltip/RightClickIcon.d.ts.map +1 -0
  66. package/dist/Tooltip/TableTooltip.d.ts +12 -0
  67. package/dist/Tooltip/TableTooltip.d.ts.map +1 -0
  68. package/dist/Tooltip/Tooltip.d.ts +29 -0
  69. package/dist/Tooltip/Tooltip.d.ts.map +1 -0
  70. package/dist/convert/convertJaegerTraceToProfile.d.ts +3 -0
  71. package/dist/convert/convertJaegerTraceToProfile.d.ts.map +1 -0
  72. package/dist/convert/diffTwoProfiles.d.ts +3 -0
  73. package/dist/convert/diffTwoProfiles.d.ts.map +1 -0
  74. package/dist/convert/flamebearersToTree.d.ts +11 -0
  75. package/dist/convert/flamebearersToTree.d.ts.map +1 -0
  76. package/dist/convert/sandwichViewProfiles.d.ts +14 -0
  77. package/dist/convert/sandwichViewProfiles.d.ts.map +1 -0
  78. package/dist/convert/subtract.d.ts +3 -0
  79. package/dist/convert/subtract.d.ts.map +1 -0
  80. package/dist/convert/testData.d.ts +50 -0
  81. package/dist/convert/testData.d.ts.map +1 -0
  82. package/dist/convert/toGraphviz.d.ts +3 -0
  83. package/dist/convert/toGraphviz.d.ts.map +1 -0
  84. package/dist/fitMode/fitMode.d.ts +42 -0
  85. package/dist/fitMode/fitMode.d.ts.map +1 -0
  86. package/dist/format/format.d.ts +42 -0
  87. package/dist/format/format.d.ts.map +1 -0
  88. package/dist/i18n.d.ts +55 -0
  89. package/dist/i18n.d.ts.map +1 -0
  90. package/dist/index.cjs.css +792 -0
  91. package/dist/index.cjs.js +5087 -0
  92. package/dist/index.d.ts +4 -0
  93. package/dist/index.d.ts.map +1 -0
  94. package/dist/index.esm.css +792 -0
  95. package/dist/index.esm.js +5079 -0
  96. package/dist/index.node.d.ts +9 -0
  97. package/dist/index.node.d.ts.map +1 -0
  98. package/dist/logo-v3-small-T5VXIMRR.svg +32 -0
  99. package/dist/models/decode.d.ts +3 -0
  100. package/dist/models/decode.d.ts.map +1 -0
  101. package/dist/models/flamebearer.d.ts +63 -0
  102. package/dist/models/flamebearer.d.ts.map +1 -0
  103. package/dist/models/groups.d.ts +37 -0
  104. package/dist/models/groups.d.ts.map +1 -0
  105. package/dist/models/index.d.ts +8 -0
  106. package/dist/models/index.d.ts.map +1 -0
  107. package/dist/models/profile.d.ts +152 -0
  108. package/dist/models/profile.d.ts.map +1 -0
  109. package/dist/models/spyName.d.ts +8 -0
  110. package/dist/models/spyName.d.ts.map +1 -0
  111. package/dist/models/trace.d.ts +357 -0
  112. package/dist/models/trace.d.ts.map +1 -0
  113. package/dist/models/units.d.ts +6 -0
  114. package/dist/models/units.d.ts.map +1 -0
  115. package/dist/search.d.ts +2 -0
  116. package/dist/search.d.ts.map +1 -0
  117. package/dist/shims/Box.d.ts +38 -0
  118. package/dist/shims/Box.d.ts.map +1 -0
  119. package/dist/shims/Button.d.ts +26 -0
  120. package/dist/shims/Button.d.ts.map +1 -0
  121. package/dist/shims/Dropdown.d.ts +30 -0
  122. package/dist/shims/Dropdown.d.ts.map +1 -0
  123. package/dist/shims/Input.d.ts +19 -0
  124. package/dist/shims/Input.d.ts.map +1 -0
  125. package/dist/shims/LoadingSpinner.d.ts +7 -0
  126. package/dist/shims/LoadingSpinner.d.ts.map +1 -0
  127. package/dist/shims/Menu.d.ts +4 -0
  128. package/dist/shims/Menu.d.ts.map +1 -0
  129. package/dist/shims/NoData.d.ts +2 -0
  130. package/dist/shims/NoData.d.ts.map +1 -0
  131. package/dist/shims/Table.d.ts +52 -0
  132. package/dist/shims/Table.d.ts.map +1 -0
  133. package/dist/shims/Tooltip.d.ts +9 -0
  134. package/dist/shims/Tooltip.d.ts.map +1 -0
  135. package/package.json +84 -0
  136. package/src/FlameGraph/FlameGraphComponent/CheckIcon.tsx +27 -0
  137. package/src/FlameGraph/FlameGraphComponent/ContextMenu.module.scss +10 -0
  138. package/src/FlameGraph/FlameGraphComponent/ContextMenu.spec.tsx +84 -0
  139. package/src/FlameGraph/FlameGraphComponent/ContextMenu.tsx +86 -0
  140. package/src/FlameGraph/FlameGraphComponent/ContextMenuHighlight.module.css +8 -0
  141. package/src/FlameGraph/FlameGraphComponent/ContextMenuHighlight.tsx +47 -0
  142. package/src/FlameGraph/FlameGraphComponent/DiffLegend.module.css +21 -0
  143. package/src/FlameGraph/FlameGraphComponent/DiffLegend.tsx +52 -0
  144. package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.module.css +40 -0
  145. package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.tsx +129 -0
  146. package/src/FlameGraph/FlameGraphComponent/Flamegraph.spec.ts +552 -0
  147. package/src/FlameGraph/FlameGraphComponent/Flamegraph.ts +446 -0
  148. package/src/FlameGraph/FlameGraphComponent/Flamegraph_render.spec.tsx +233 -0
  149. package/src/FlameGraph/FlameGraphComponent/Flamegraph_render.ts +478 -0
  150. package/src/FlameGraph/FlameGraphComponent/GraphVizPane.tsx +56 -0
  151. package/src/FlameGraph/FlameGraphComponent/GraphVizPanel.module.scss +55 -0
  152. package/src/FlameGraph/FlameGraphComponent/Header.module.css +27 -0
  153. package/src/FlameGraph/FlameGraphComponent/Header.tsx +71 -0
  154. package/src/FlameGraph/FlameGraphComponent/Highlight.module.css +7 -0
  155. package/src/FlameGraph/FlameGraphComponent/Highlight.spec.tsx +53 -0
  156. package/src/FlameGraph/FlameGraphComponent/Highlight.tsx +94 -0
  157. package/src/FlameGraph/FlameGraphComponent/LogoLink.module.scss +10 -0
  158. package/src/FlameGraph/FlameGraphComponent/LogoLink.tsx +101 -0
  159. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-collapses-small-blocks-into-one-1-snap.png +0 -0
  160. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-diff-mode-1-snap.png +0 -0
  161. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-highlighted-flamegraph-1-snap.png +0 -0
  162. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-normal-flamegraph-1-snap.png +0 -0
  163. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-selected-node-1-snap.png +0 -0
  164. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-focused-also-zooms-1-snap.png +0 -0
  165. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-focused-renders-a-focused-node-in-the-beginning-1-snap.png +0 -0
  166. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-focused-renders-a-focused-node-when-node-is-not-in-the-beginning-1-snap.png +0 -0
  167. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-focused-renders-a-focused-node-zoom-top-level-1-snap.png +0 -0
  168. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-complex-flamegraph-1-snap.png +0 -0
  169. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-double-diff-flamegraph-1-snap.png +0 -0
  170. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-highlighted-double-flamegraph-1-snap.png +0 -0
  171. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-highlighted-flamegraph-1-snap.png +0 -0
  172. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-simple-flamegraph-1-snap.png +0 -0
  173. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-simple-tree-1-snap.png +0 -0
  174. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-zoomed-flamegraph-1-snap.png +0 -0
  175. package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-zoomed-with-fit-mode-tail-1-snap.png +0 -0
  176. package/src/FlameGraph/FlameGraphComponent/canvas.module.css +6 -0
  177. package/src/FlameGraph/FlameGraphComponent/color.spec.ts +308 -0
  178. package/src/FlameGraph/FlameGraphComponent/color.ts +167 -0
  179. package/src/FlameGraph/FlameGraphComponent/colorPalette.ts +58 -0
  180. package/src/FlameGraph/FlameGraphComponent/constants.ts +5 -0
  181. package/src/FlameGraph/FlameGraphComponent/index.spec.tsx +291 -0
  182. package/src/FlameGraph/FlameGraphComponent/index.tsx +411 -0
  183. package/src/FlameGraph/FlameGraphComponent/murmur3.ts +97 -0
  184. package/src/FlameGraph/FlameGraphComponent/styles.module.scss +10 -0
  185. package/src/FlameGraph/FlameGraphComponent/testData.ts +427 -0
  186. package/src/FlameGraph/FlameGraphComponent/utils.ts +31 -0
  187. package/src/FlameGraph/FlameGraphComponent/viewTypes.ts +6 -0
  188. package/src/FlameGraph/FlameGraphRenderer.tsx +603 -0
  189. package/src/FlameGraph/FlamegraphRenderer.module.scss +93 -0
  190. package/src/FlameGraph/decode.ts +78 -0
  191. package/src/FlameGraph/normalize.spec.ts +76 -0
  192. package/src/FlameGraph/normalize.ts +60 -0
  193. package/src/FlameGraph/testData.json +423 -0
  194. package/src/FlameGraph/uniqueness.spec.ts +16 -0
  195. package/src/FlameGraph/uniqueness.ts +84 -0
  196. package/src/FlamegraphRenderer.tsx +61 -0
  197. package/src/Icons.tsx +74 -0
  198. package/src/ProfilerTable.tsx +527 -0
  199. package/src/SharedQueryInput.module.scss +82 -0
  200. package/src/SharedQueryInput.tsx +127 -0
  201. package/src/Toolbar.module.scss +117 -0
  202. package/src/Toolbar.spec.tsx +217 -0
  203. package/src/Toolbar.tsx +471 -0
  204. package/src/Tooltip/FlamegraphTooltip.spec.tsx +81 -0
  205. package/src/Tooltip/FlamegraphTooltip.tsx +257 -0
  206. package/src/Tooltip/LeftClickIcon.tsx +18 -0
  207. package/src/Tooltip/RightClickIcon.tsx +18 -0
  208. package/src/Tooltip/TableTooltip.spec.tsx +44 -0
  209. package/src/Tooltip/TableTooltip.tsx +145 -0
  210. package/src/Tooltip/Tooltip.module.scss +71 -0
  211. package/src/Tooltip/Tooltip.spec.tsx +395 -0
  212. package/src/Tooltip/Tooltip.tsx +336 -0
  213. package/src/__snapshots__/Toolbar.spec.tsx.snap +297 -0
  214. package/src/convert/convertJaegerTraceToProfile.ts +97 -0
  215. package/src/convert/diffTwoProfiles.ts +81 -0
  216. package/src/convert/flamebearersToTree.ts +78 -0
  217. package/src/convert/sandwichViewProfiles.spec.ts +65 -0
  218. package/src/convert/sandwichViewProfiles.ts +191 -0
  219. package/src/convert/subtract.ts +87 -0
  220. package/src/convert/testData.ts +145 -0
  221. package/src/convert/toGraphviz.ts +485 -0
  222. package/src/fitMode/fitMode.spec.ts +93 -0
  223. package/src/fitMode/fitMode.ts +122 -0
  224. package/src/format/format.spec.ts +291 -0
  225. package/src/format/format.ts +303 -0
  226. package/src/globals.d.ts +13 -0
  227. package/src/i18n.tsx +293 -0
  228. package/src/index.node.ts +19 -0
  229. package/src/index.spec.tsx +383 -0
  230. package/src/index.tsx +10 -0
  231. package/src/logo-v3-small.svg +32 -0
  232. package/src/models/decode.ts +45 -0
  233. package/src/models/flamebearer.ts +86 -0
  234. package/src/models/groups.ts +14 -0
  235. package/src/models/index.ts +7 -0
  236. package/src/models/profile.spec.ts +32 -0
  237. package/src/models/profile.ts +48 -0
  238. package/src/models/spyName.spec.ts +18 -0
  239. package/src/models/spyName.ts +32 -0
  240. package/src/models/trace.ts +45 -0
  241. package/src/models/units.spec.ts +21 -0
  242. package/src/models/units.ts +24 -0
  243. package/src/sass/_common.scss +206 -0
  244. package/src/sass/_css-variables.scss +201 -0
  245. package/src/sass/_mixins.scss +15 -0
  246. package/src/sass/_sanitize.scss +407 -0
  247. package/src/sass/_variables.scss +53 -0
  248. package/src/sass/flamegraph.scss +18 -0
  249. package/src/search.spec.ts +11 -0
  250. package/src/search.ts +4 -0
  251. package/src/shameful-any.d.ts +2 -0
  252. package/src/shims/Box.module.scss +57 -0
  253. package/src/shims/Box.tsx +105 -0
  254. package/src/shims/Button.module.scss +129 -0
  255. package/src/shims/Button.tsx +128 -0
  256. package/src/shims/Dropdown.module.scss +63 -0
  257. package/src/shims/Dropdown.tsx +96 -0
  258. package/src/shims/Input.module.scss +15 -0
  259. package/src/shims/Input.tsx +55 -0
  260. package/src/shims/LoadingSpinner.tsx +19 -0
  261. package/src/shims/Menu.tsx +9 -0
  262. package/src/shims/NoData.module.scss +6 -0
  263. package/src/shims/NoData.tsx +11 -0
  264. package/src/shims/Table.module.scss +82 -0
  265. package/src/shims/Table.spec.tsx +121 -0
  266. package/src/shims/Table.tsx +252 -0
  267. package/src/shims/Tooltip.tsx +51 -0
@@ -0,0 +1,53 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
2
+ import React from 'react';
3
+ import { render, screen } from '@testing-library/react';
4
+ import userEvent from '@testing-library/user-event';
5
+ import { Maybe } from 'true-myth';
6
+
7
+ import Highlight, { HighlightProps } from './Highlight';
8
+
9
+ function TestComponent(props: Omit<HighlightProps, 'canvasRef'>) {
10
+ const canvasRef = React.useRef<HTMLCanvasElement>(null);
11
+
12
+ return (
13
+ <>
14
+ <canvas data-testid="canvas" ref={canvasRef} />
15
+ {canvasRef && <Highlight canvasRef={canvasRef} {...props} />}
16
+ </>
17
+ );
18
+ }
19
+
20
+ describe('Highlight', () => {
21
+ it('works', () => {
22
+ const xyToHighlightData = jest.fn();
23
+ render(
24
+ <TestComponent
25
+ barHeight={50}
26
+ xyToHighlightData={xyToHighlightData}
27
+ zoom={Maybe.nothing()}
28
+ />
29
+ );
30
+
31
+ // hover over a bar
32
+ xyToHighlightData.mockReturnValueOnce(
33
+ Maybe.of({
34
+ left: 10,
35
+ top: 5,
36
+ width: 100,
37
+ })
38
+ );
39
+ userEvent.hover(screen.getByTestId('canvas'));
40
+ expect(screen.getByTestId('flamegraph-highlight')).toBeVisible();
41
+ expect(screen.getByTestId('flamegraph-highlight')).toHaveStyle({
42
+ height: '50px',
43
+ left: '10px',
44
+ top: '5px',
45
+ width: '100px',
46
+ });
47
+
48
+ // hover outside the canvas
49
+ xyToHighlightData.mockReturnValueOnce(Maybe.nothing());
50
+ userEvent.hover(screen.getByTestId('canvas'));
51
+ expect(screen.getByTestId('flamegraph-highlight')).not.toBeVisible();
52
+ });
53
+ });
@@ -0,0 +1,94 @@
1
+ import { Maybe } from 'true-myth';
2
+ import React from 'react';
3
+ import { DeepReadonly } from 'ts-essentials';
4
+ import styles from './Highlight.module.css';
5
+
6
+ export interface HighlightProps {
7
+ // probably the same as the bar height
8
+ barHeight: number;
9
+ zoom: Maybe<DeepReadonly<{ i: number; j: number }>>;
10
+ xyToHighlightData: (
11
+ x: number,
12
+ y: number
13
+ ) => Maybe<{
14
+ left: number;
15
+ top: number;
16
+ width: number;
17
+ }>;
18
+
19
+ canvasRef: React.RefObject<HTMLCanvasElement>;
20
+ }
21
+ export default function Highlight(props: HighlightProps) {
22
+ const { canvasRef, barHeight, xyToHighlightData, zoom } = props;
23
+ const [style, setStyle] = React.useState<React.CSSProperties>({
24
+ height: '0px',
25
+ visibility: 'hidden',
26
+ });
27
+
28
+ React.useEffect(() => {
29
+ // stops highlighting every time a node is zoomed or unzoomed
30
+ // then, when a mouse move event is detected,
31
+ // listeners are triggered and highlighting becomes visible again
32
+ setStyle({
33
+ height: '0px',
34
+ visibility: 'hidden',
35
+ });
36
+ }, [zoom]);
37
+
38
+ const onMouseMove = (e: MouseEvent) => {
39
+ const opt = xyToHighlightData(e.offsetX, e.offsetY);
40
+
41
+ if (opt.isJust) {
42
+ const data = opt.value;
43
+
44
+ setStyle({
45
+ visibility: 'visible',
46
+ height: `${barHeight}px`,
47
+ ...data,
48
+ });
49
+ } else {
50
+ // it doesn't map to a valid xy
51
+ // so it means we are hovering out
52
+ onMouseOut();
53
+ }
54
+ };
55
+
56
+ const onMouseOut = () => {
57
+ setStyle({
58
+ ...style,
59
+ visibility: 'hidden',
60
+ });
61
+ };
62
+
63
+ React.useEffect(
64
+ () => {
65
+ // use closure to "cache" the current canvas reference
66
+ // so that when cleaning up, it points to a valid canvas
67
+ // (otherwise it would be null)
68
+ const canvasEl = canvasRef.current;
69
+ if (!canvasEl) {
70
+ return () => {};
71
+ }
72
+
73
+ // watch for mouse events on the bar
74
+ canvasEl.addEventListener('mousemove', onMouseMove);
75
+ canvasEl.addEventListener('mouseout', onMouseOut);
76
+
77
+ return () => {
78
+ canvasEl.removeEventListener('mousemove', onMouseMove);
79
+ canvasEl.removeEventListener('mouseout', onMouseOut);
80
+ };
81
+ },
82
+
83
+ // refresh callback functions when they change
84
+ [canvasRef.current, onMouseMove, onMouseOut]
85
+ );
86
+
87
+ return (
88
+ <div
89
+ className={styles.highlight}
90
+ style={style}
91
+ data-testid="flamegraph-highlight"
92
+ />
93
+ );
94
+ }
@@ -0,0 +1,10 @@
1
+ .logoLink {
2
+ text-decoration: none;
3
+ font-weight: 500;
4
+ opacity: 0.5;
5
+ color: var(--ps-neutral-2);
6
+ position: absolute;
7
+ right: 0;
8
+ bottom: 0;
9
+ z-index: 0;
10
+ }
@@ -0,0 +1,101 @@
1
+ import React from 'react';
2
+
3
+ import styles from './LogoLink.module.scss';
4
+
5
+ // TODO: move this to assets pipeline. for now just embedding it here because this is less likely to break
6
+ function svgLogo() {
7
+ return (
8
+ <svg
9
+ width="22px"
10
+ height="22px"
11
+ viewBox="0 0 1024 1024"
12
+ version="1.1"
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ >
15
+ <defs>
16
+ <radialGradient
17
+ cx="49.4236252%"
18
+ cy="92.6627823%"
19
+ fx="49.4236252%"
20
+ fy="92.6627823%"
21
+ r="195.066755%"
22
+ gradientTransform="translate(0.494236,0.926628),scale(1.000000,0.735610),rotate(-90.000000),translate(-0.494236,-0.926628)"
23
+ id="radialGradient-1"
24
+ >
25
+ <stop stopColor="#FFB90C" offset="0%" />
26
+ <stop stopColor="#F9243A" offset="38.390924%" />
27
+ <stop stopColor="#F9243A" offset="50.5405%" />
28
+ <stop stopColor="#B51424" offset="73.98091%" />
29
+ <stop stopColor="#B51424" offset="100%" />
30
+ </radialGradient>
31
+ </defs>
32
+ <g
33
+ id="Artboard"
34
+ stroke="none"
35
+ strokeWidth="1"
36
+ fill="none"
37
+ fillRule="evenodd"
38
+ >
39
+ <g
40
+ id="fire-part"
41
+ transform="translate(148.516736, 0.000000)"
42
+ fillRule="nonzero"
43
+ >
44
+ <g
45
+ id="whole-thing"
46
+ transform="translate(363.983264, 495.000000) scale(-1, 1) rotate(-180.000000) translate(-363.983264, -495.000000) translate(0.483264, 0.000000)"
47
+ >
48
+ <g
49
+ id="g70"
50
+ transform="translate(-0.000091, 0.685815)"
51
+ fill="url(#radialGradient-1)"
52
+ >
53
+ <path
54
+ d="M65.3646667,571.739321 L65.4492471,571.698868 C19.5139147,505.999969 -5.32464048,424.477859 1.04305801,336.877516 L1.04305801,336.877516 C14.0321963,158.179446 159.192462,13.7596653 338.059844,1.5917266 L338.059844,1.5917266 C419.418369,-3.93888015 495.500283,17.3823334 558.456522,57.4611191 L558.456522,57.4611191 L481.301947,162.097965 C437.516468,136.521928 399.367671,129.590556 363.486536,130.155994 L363.486536,130.155994 C234.497143,130.155994 129.556988,235.032238 129.556988,363.946998 L129.556988,363.946998 C129.556988,492.865683 234.497143,597.738003 363.486536,597.738003 L363.486536,597.738003 C492.483783,597.738003 597.427864,492.865683 597.427864,363.946998 L597.427864,363.946998 C597.41276,304.634864 581.39383,255.677522 530.630465,199.668053 L607.770843,95.1329436 C680.936847,161.576603 726.932594,257.364176 726.932594,363.946998 L726.932594,363.946998 C726.932594,458.031616 691.13483,543.75602 632.416071,608.271816 L632.416071,608.271816 L632.416071,608.275741 L533.597728,748.122808 L428.601388,617.203806 L434.703262,646.563419 C459.453008,765.59222 433.664131,889.543925 363.49439,988.853335 L363.49439,988.853335 L65.3646667,571.723019 L65.3646667,571.739321 Z"
55
+ id="path84"
56
+ />
57
+ </g>
58
+ <g id="blue" transform="translate(191.447039, 191.331780)">
59
+ <g id="g88" transform="translate(-0.000063, 0.685930)">
60
+ <g
61
+ id="g94"
62
+ transform="translate(0.177296, 0.699054)"
63
+ fill="#3EC1D3"
64
+ >
65
+ <path
66
+ d="M171.862466,343.697728 C77.0961324,343.697728 -0.00497405932,266.647602 -0.00497405932,171.934957 C-0.00497405932,77.2182874 77.0961324,0.168162396 171.862466,0.168162396 C266.632828,0.168162396 343.741988,77.2182874 343.741988,171.934957 C343.741988,266.647602 266.632828,343.697728 171.862466,343.697728"
67
+ id="path96"
68
+ />
69
+ </g>
70
+ <g
71
+ id="g98"
72
+ transform="translate(29.362379, 172.629585)"
73
+ fill="#FFFFFF"
74
+ >
75
+ <path
76
+ d="M22.8397982,0 L0.671669409,0 C0.671669409,78.2496309 64.380874,141.920035 142.678189,141.920035 L142.678189,119.765407 C76.6007327,119.765407 22.8397982,66.0372141 22.8397982,0"
77
+ id="path100"
78
+ />
79
+ </g>
80
+ </g>
81
+ </g>
82
+ </g>
83
+ </g>
84
+ </g>
85
+ </svg>
86
+ );
87
+ }
88
+
89
+ export default function LogoLink() {
90
+ return (
91
+ <a
92
+ className={styles.logoLink}
93
+ href="https://github.com/pyroscope-io/pyroscope/"
94
+ target="_blank"
95
+ rel="noreferrer"
96
+ >
97
+ {svgLogo()}
98
+ <span>Pyroscope</span>
99
+ </a>
100
+ );
101
+ }
@@ -0,0 +1,6 @@
1
+ .canvas {
2
+ width: 100%;
3
+ cursor: pointer;
4
+ position: relative;
5
+ z-index: 1;
6
+ }
@@ -0,0 +1,308 @@
1
+ import Color from 'color';
2
+ type Color = ColorLib
3
+ import {
4
+ colorBasedOnDiffPercent,
5
+ NewDiffColor,
6
+ getPackageNameFromStackTrace,
7
+ } from './color';
8
+ import { DefaultPalette } from './colorPalette';
9
+
10
+ describe.each([
11
+ // red (diff > 0)
12
+ [30, 60, DefaultPalette.badColor.toString()],
13
+
14
+ // green (diff < 0%)
15
+ [60, 0, DefaultPalette.goodColor.toString()],
16
+
17
+ // grey (diff == 0)
18
+ [0, 0, DefaultPalette.neutralColor.toString()],
19
+ ])('.colorBasedOnDiffPercent(%i, %i)', (a, b, expected) => {
20
+ it(`returns ${expected}`, () => {
21
+ expect(colorBasedOnDiffPercent(DefaultPalette, a, b).rgb().toString()).toBe(
22
+ expected
23
+ );
24
+ });
25
+ });
26
+
27
+ describe('NewDiffColor with white-to-black example palette', () => {
28
+ describe.each([
29
+ [-100, 'rgb(255, 255, 255)'],
30
+ [0, 'rgb(128, 128, 128)'],
31
+ [100, 'rgb(0, 0, 0)'],
32
+ ])('.NewDiffColor(%i)', (a, expected) => {
33
+ it(`returns ${expected}`, () => {
34
+ const color = NewDiffColor({
35
+ name: 'my palette',
36
+ goodColor: Color('white'),
37
+ neutralColor: Color('grey'),
38
+ badColor: Color('black'),
39
+ });
40
+
41
+ expect(color(a).rgb().toString()).toBe(expected);
42
+ });
43
+ });
44
+ });
45
+
46
+ describe('getPackageNameFromStackTrace', () => {
47
+ describe('golang', () => {
48
+ describe.each([
49
+ ['bufio.(*Reader).fill', 'bufio.'],
50
+ ['cmpbody', 'cmpbody'],
51
+ ['bytes.Compare', 'bytes.'],
52
+ ['crypto/tls.(*Conn).clientHandshake', 'crypto/tls.'],
53
+ [
54
+ 'github.com/DataDog/zstd._Cfunc_ZSTD_compress_wrapper',
55
+ 'github.com/DataDog/zstd.',
56
+ ],
57
+ [
58
+ 'github.com/dgraph-io/badger/v2.(*DB).calculateSize',
59
+ 'github.com/dgraph-io/badger/v2.',
60
+ ],
61
+ [
62
+ 'github.com/dgraph-io/badger/v2/table.(*blockIterator).next',
63
+ 'github.com/dgraph-io/badger/v2/table.',
64
+ ],
65
+ ['path/filepath.walk', 'path/filepath.'],
66
+ ['os.(*File).write', 'os.'],
67
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
68
+ it(`returns '${expected}'`, () => {
69
+ expect(getPackageNameFromStackTrace('gospy', a)).toBe(expected);
70
+ });
71
+ });
72
+ });
73
+
74
+ describe('pyspy', () => {
75
+ describe.each([
76
+ ['total', 'total'],
77
+ [
78
+ 'System.Private.CoreLib!System.Threading.TimerQueue.FireNextTimers()',
79
+ 'System.Private.CoreLib!System.Threading',
80
+ ],
81
+ [
82
+ 'StackExchange.Redis!StackExchange.Redis.ConnectionMultiplexer.OnHeartbeat()',
83
+ 'StackExchange.Redis!StackExchange.Redis',
84
+ ],
85
+ [
86
+ 'Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestPipeReader.ReadAsync(value class System.Threading.CancellationToken)',
87
+ 'Microsoft.AspNetCore.Server.Kestrel.Core!Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http',
88
+ ],
89
+ [
90
+ 'Google.Protobuf!Google.Protobuf.ParsingPrimitivesMessages.ReadRawMessage(value class Google.Protobuf.ParseContext\u0026,class Google.Protobuf.IMessage)',
91
+ 'Google.Protobuf!Google.Protobuf',
92
+ ],
93
+ [
94
+ 'Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal.PipeExtensions.ReadSingleMessageAsync(class System.IO.Pipelines.PipeReader,class Grpc.AspNetCore.Server.Internal.HttpContextServerCallContext,class System.Func`2\u003cclass Grpc.Core.DeserializationContext,!!0\u003e)',
95
+ 'Grpc.AspNetCore.Server!Grpc.AspNetCore.Server.Internal',
96
+ ],
97
+ [
98
+ 'System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[System.__Canon].GetStateMachineBox(!!0\u0026,class System.Threading.Tasks.Task`1\u003c!0\u003e\u0026)',
99
+ 'System.Private.CoreLib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[System',
100
+ ],
101
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
102
+ it(`returns '${expected}'`, () => {
103
+ expect(getPackageNameFromStackTrace('dotnetspy', a)).toBe(expected);
104
+ });
105
+ });
106
+ });
107
+
108
+ describe('pyspy', () => {
109
+ describe.each([
110
+ ['total', 'total'],
111
+ ['urllib3/response.py:579 - stream', 'urllib3/'],
112
+ ['requests/models.py:580 - prepare_cookies', 'requests/'],
113
+ ['logging/__init__.py:1548 - findCaller', 'logging/'],
114
+ [
115
+ 'jaeger_client/thrift_gen/jaeger/ttypes.py:147 - write',
116
+ 'jaeger_client/thrift_gen/jaeger/',
117
+ ],
118
+
119
+ // TODO: this one looks incorrect, but keeping in the test for now
120
+ [
121
+ '\u003cfrozen importlib._bootstrap\u003e:1030 - _gcd_import',
122
+ '<frozen importlib._bootstrap>:1030 - _gcd_import',
123
+ ],
124
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
125
+ it(`returns '${expected}'`, () => {
126
+ expect(getPackageNameFromStackTrace('pyspy', a)).toBe(expected);
127
+ });
128
+ });
129
+ });
130
+
131
+ describe('rbspy', () => {
132
+ describe.each([
133
+ ['total', 'total'],
134
+ ['webrick/utils.rb:194 - watch', 'webrick/'],
135
+ ['webrick/server.rb:190 - block (2 levels) in start', 'webrick/'],
136
+ [
137
+ 'gems/sinatra-2.0.3/lib/sinatra/base.rb:1537 - start_server',
138
+ 'gems/sinatra-2.0.3/lib/sinatra/',
139
+ ],
140
+ ['services/driver/client.rb:34 - get_drivers', 'services/driver/'],
141
+ ['uri/common.rb:742 - URI', 'uri/'],
142
+ ['net/protocol.rb:299 - block in write0', 'net/'],
143
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
144
+ it(`returns '${expected}'`, () => {
145
+ expect(getPackageNameFromStackTrace('rbspy', a)).toBe(expected);
146
+ });
147
+ });
148
+ });
149
+
150
+ describe('ebpfspy', () => {
151
+ describe.each([
152
+ ['total', 'total'],
153
+ ['entry_SYSCALL_64_after_hwframe', 'entry_SYSCALL_64_after_hwframe'],
154
+ ['[unknown]', '[unknown]'],
155
+ [
156
+ 'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
157
+ 'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
158
+ ],
159
+ [
160
+ 'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
161
+ 'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
162
+ ],
163
+ [
164
+ 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
165
+ 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
166
+ ],
167
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
168
+ it(`returns '${expected}'`, () => {
169
+ expect(getPackageNameFromStackTrace('ebpfspy', a)).toBe(expected);
170
+ });
171
+ });
172
+ });
173
+
174
+ describe('default', () => {
175
+ describe.each([
176
+ ['total', 'total'],
177
+ ['entry_SYSCALL_64_after_hwframe', 'entry_SYSCALL_64_after_hwframe'],
178
+ ['[unknown]', '[unknown]'],
179
+ [
180
+ 'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
181
+ 'QApplicationPrivate::notify_helper(QObject*, QEvent*)',
182
+ ],
183
+ [
184
+ 'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
185
+ 'v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)',
186
+ ],
187
+ [
188
+ 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
189
+ 'github.com/pyroscope-io/pyroscope/pkg/agent.(*ProfileSession).Start.dwrap.3',
190
+ ],
191
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
192
+ it(`returns '${expected}'`, () => {
193
+ expect(getPackageNameFromStackTrace('unknown', a)).toBe(expected);
194
+ });
195
+ });
196
+ });
197
+
198
+ describe('rust', () => {
199
+ describe.each([
200
+ ['total', 'total'],
201
+ ['std::thread::local::LocalKey<T>::with', 'std'],
202
+ [
203
+ 'tokio::runtime::basic_scheduler::CoreGuard::block_on::{{closure}}::{{closure}}::{{closure}}',
204
+ 'tokio',
205
+ ],
206
+ [
207
+ '<core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll',
208
+ '<core',
209
+ ],
210
+ [
211
+ 'reqwest::blocking::client::ClientHandle::new::{{closure}}::{{closure}}',
212
+ 'reqwest',
213
+ ],
214
+ ['core::time::Duration::as_secs', 'core'],
215
+ ['clock_gettime@GLIBC_2.2.5', 'clock_gettime@GLIBC_2.2.5'],
216
+ [
217
+ 'hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T>::poll_catch debugger eval code',
218
+ 'hyper',
219
+ ],
220
+ ['openssl::ssl::connector::SslConnector::builder', 'openssl'],
221
+
222
+ // TODO looks incorrect
223
+ [
224
+ '<F as futures_core::future::TryFuture>::try_poll',
225
+ '<F as futures_core',
226
+ ],
227
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
228
+ it(`returns '${expected}'`, () => {
229
+ expect(getPackageNameFromStackTrace('pyroscope-rs', a)).toBe(expected);
230
+ });
231
+ });
232
+ });
233
+
234
+ describe('scrape (pull mode)', () => {
235
+ describe.each([
236
+ ['bufio.(*Reader).fill', 'bufio.'],
237
+ ['cmpbody', 'cmpbody'],
238
+ ['bytes.Compare', 'bytes.'],
239
+ ['crypto/tls.(*Conn).clientHandshake', 'crypto/tls.'],
240
+ [
241
+ 'github.com/DataDog/zstd._Cfunc_ZSTD_compress_wrapper',
242
+ 'github.com/DataDog/zstd.',
243
+ ],
244
+ [
245
+ 'github.com/dgraph-io/badger/v2.(*DB).calculateSize',
246
+ 'github.com/dgraph-io/badger/v2.',
247
+ ],
248
+ [
249
+ 'github.com/dgraph-io/badger/v2/table.(*blockIterator).next',
250
+ 'github.com/dgraph-io/badger/v2/table.',
251
+ ],
252
+ ['path/filepath.walk', 'path/filepath.'],
253
+ ['os.(*File).write', 'os.'],
254
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
255
+ it(`returns '${expected}'`, () => {
256
+ expect(getPackageNameFromStackTrace('scrape', a)).toBe(expected);
257
+ });
258
+ });
259
+ });
260
+
261
+ describe('nodejs spy', () => {
262
+ describe.each([
263
+ ['total', 'total'],
264
+ ['./node_modules/node-fetch/lib/index.js:fetch:1493', 'node-fetch'],
265
+ [
266
+ './node_modules/@pyroscope-node/dist/pull/index.js:sampleFunction:1827',
267
+ '@pyroscope-node',
268
+ ],
269
+ ['node:net:Socket:320', 'node:net'],
270
+ [':(idle):0', ''],
271
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
272
+ it(`returns '${expected}'`, () => {
273
+ expect(getPackageNameFromStackTrace('nodespy', a)).toBe(expected);
274
+ });
275
+ });
276
+ });
277
+
278
+ describe('java spy', () => {
279
+ describe.each([
280
+ [
281
+ 'org/apache/catalina/core/ApplicationFilterChain.doFilter',
282
+ 'org/apache/catalina/core/',
283
+ ],
284
+ [
285
+ 'org/apache/catalina/core/ApplicationFilterChain.internalDoFilter',
286
+ 'org/apache/catalina/core/',
287
+ ],
288
+ [
289
+ 'org/apache/coyote/AbstractProcessorLight.process',
290
+ 'org/apache/coyote/',
291
+ ],
292
+ [
293
+ 'org/springframework/web/servlet/DispatcherServlet.doService',
294
+ 'org/springframework/web/servlet/',
295
+ ],
296
+ [
297
+ 'org/example/rideshare/RideShareController.orderCar',
298
+ 'org/example/rideshare/',
299
+ ],
300
+ ['org/example/rideshare/OrderService.orderCar', 'org/example/rideshare/'],
301
+ ['total', 'total'],
302
+ ])(`.getPackageNameFromStackTrace('%s')`, (a, expected) => {
303
+ it(`returns '${expected}'`, () => {
304
+ expect(getPackageNameFromStackTrace('javaspy', a)).toBe(expected);
305
+ });
306
+ });
307
+ });
308
+ });