@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,478 @@
1
+ /*
2
+
3
+ This component is based on code from flamebearer project
4
+ https://github.com/mapbox/flamebearer
5
+
6
+ ISC License
7
+
8
+ Copyright (c) 2018, Mapbox
9
+
10
+ Permission to use, copy, modify, and/or distribute this software for any purpose
11
+ with or without fee is hereby granted, provided that the above copyright notice
12
+ and this permission notice appear in all copies.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
15
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
17
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
18
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
20
+ THIS SOFTWARE.
21
+
22
+ */
23
+
24
+ /* eslint-disable no-continue */
25
+ import { createFF, Flamebearer, SpyName } from '../../models';
26
+ import {
27
+ formatPercent,
28
+ getFormatter,
29
+ ratioToPercent,
30
+ } from '../../format/format';
31
+ import { fitToCanvasRect } from '../../fitMode/fitMode';
32
+ import { getRatios } from './utils';
33
+ import {
34
+ PX_PER_LEVEL,
35
+ COLLAPSE_THRESHOLD,
36
+ LABEL_THRESHOLD,
37
+ BAR_HEIGHT,
38
+ GAP,
39
+ } from './constants';
40
+ import {
41
+ colorBasedOnDiffPercent,
42
+ colorBasedOnPackageName,
43
+ colorGreyscale,
44
+ getPackageNameFromStackTrace,
45
+ } from './color';
46
+ import type { FlamegraphPalette } from './colorPalette';
47
+ import { isMatch } from '../../search';
48
+ // there's a dependency cycle here but it should be fine
49
+ /* eslint-disable-next-line import/no-cycle */
50
+ import Flamegraph from './Flamegraph';
51
+
52
+ type CanvasRendererConfig = Flamebearer & {
53
+ canvas: HTMLCanvasElement;
54
+ focusedNode: ConstructorParameters<typeof Flamegraph>[2];
55
+ fitMode: ConstructorParameters<typeof Flamegraph>[3];
56
+ highlightQuery: ConstructorParameters<typeof Flamegraph>[4];
57
+ zoom: ConstructorParameters<typeof Flamegraph>[5];
58
+
59
+ /**
60
+ * Used when zooming, values between 0 and 1.
61
+ * For illustration, in a non zoomed state it has the value of 0
62
+ */
63
+ readonly rangeMin: number;
64
+ /**
65
+ * Used when zooming, values between 0 and 1.
66
+ * For illustration, in a non zoomed state it has the value of 1
67
+ */
68
+ readonly rangeMax: number;
69
+
70
+ tickToX: (i: number) => number;
71
+
72
+ pxPerTick: number;
73
+
74
+ palette: FlamegraphPalette;
75
+ maxSelf?: number;
76
+ };
77
+
78
+ export default function RenderCanvas(props: CanvasRendererConfig) {
79
+ const { canvas, fitMode, units, tickToX, levels, palette } = props;
80
+ const { numTicks, sampleRate, pxPerTick } = props;
81
+ const { rangeMin, rangeMax } = props;
82
+ const { focusedNode, zoom } = props;
83
+
84
+ const graphWidth = getCanvasWidth(canvas);
85
+ // TODO: why is this needed? otherwise height is all messed up
86
+ canvas.width = graphWidth;
87
+
88
+ if (rangeMin >= rangeMax) {
89
+ throw new Error(`'rangeMin' should be strictly smaller than 'rangeMax'`);
90
+ }
91
+
92
+ const { format } = props;
93
+ const ff = createFF(format);
94
+
95
+ // const pxPerTick = graphWidth / numTicks / (rangeMax - rangeMin);
96
+ const ctx = canvas.getContext('2d');
97
+ if (!ctx) {
98
+ throw new Error('Could not get ctx');
99
+ }
100
+
101
+ const selectedLevel = zoom.mapOrElse(
102
+ () => 0,
103
+ (z) => z.i
104
+ );
105
+ const formatter = getFormatter(numTicks, sampleRate, units);
106
+ const isFocused = focusedNode.isJust;
107
+ const topLevel = focusedNode.mapOrElse(
108
+ () => 0,
109
+ (f) => f.i
110
+ );
111
+
112
+ const canvasHeight =
113
+ PX_PER_LEVEL * (levels.length - topLevel) + (isFocused ? BAR_HEIGHT : 0);
114
+ // const canvasHeight = PX_PER_LEVEL * (levels.length - topLevel);
115
+ canvas.height = canvasHeight;
116
+
117
+ // increase pixel ratio, otherwise it looks bad in high resolution devices
118
+ if (devicePixelRatio > 1) {
119
+ canvas.width *= 2;
120
+ canvas.height *= 2;
121
+ ctx.scale(2, 2);
122
+ }
123
+
124
+ const { names } = props;
125
+ // are we focused?
126
+ // if so, add an initial bar telling it's a collapsed one
127
+ // TODO clean this up
128
+ if (isFocused) {
129
+ const width = numTicks * pxPerTick;
130
+ ctx.beginPath();
131
+ ctx.rect(0, 0, numTicks * pxPerTick, BAR_HEIGHT);
132
+ // TODO find a neutral color
133
+ // TODO use getColor ?
134
+ ctx.fillStyle = colorGreyscale(200, 1).rgb().string();
135
+ ctx.fill();
136
+
137
+ // TODO show the samples too?
138
+ const shortName = focusedNode.mapOrElse(
139
+ () => 'total',
140
+ (f) => `total (${f.i - 1} level(s) collapsed)`
141
+ );
142
+
143
+ // Set the font syle
144
+ // It's important to set the font BEFORE calculating 'characterSize'
145
+ // Since it will be used to calculate how many characters can fit
146
+ ctx.textBaseline = 'middle';
147
+ ctx.font =
148
+ '400 11.5px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace';
149
+ // Since this is a monospaced font any character would do
150
+ const characterSize = ctx.measureText('a').width;
151
+ const fitCalc = fitToCanvasRect({
152
+ mode: fitMode,
153
+ charSize: characterSize,
154
+ rectWidth: width,
155
+ fullText: shortName,
156
+ shortText: shortName,
157
+ });
158
+
159
+ const x = 0;
160
+ const y = 0;
161
+ const sh = BAR_HEIGHT;
162
+
163
+ ctx.save();
164
+ ctx.clip();
165
+ ctx.fillStyle = 'black';
166
+ const namePosX = Math.round(Math.max(x, 0));
167
+ ctx.fillText(fitCalc.text, namePosX + fitCalc.marginLeft, y + sh / 2 + 1);
168
+ ctx.restore();
169
+ }
170
+
171
+ for (let i = 0; i < levels.length - topLevel; i += 1) {
172
+ const level = levels[topLevel + i];
173
+ if (!level) {
174
+ throw new Error(`Could not find level: ${topLevel + i}`);
175
+ }
176
+
177
+ for (let j = 0; j < level.length; j += ff.jStep) {
178
+ const barIndex = ff.getBarOffset(level, j);
179
+ const x = tickToX(barIndex);
180
+ const y = i * PX_PER_LEVEL + (isFocused ? BAR_HEIGHT : 0);
181
+
182
+ const sh = BAR_HEIGHT;
183
+
184
+ const highlightModeOn =
185
+ !!props.highlightQuery && props.highlightQuery.length > 0;
186
+
187
+ const isHighlighted = nodeIsInQuery(
188
+ j + ff.jName,
189
+ level,
190
+ names,
191
+ props.highlightQuery
192
+ );
193
+
194
+ let numBarTicks = ff.getBarTotal(level, j);
195
+
196
+ // merge very small blocks into big "collapsed" ones for performance
197
+ const collapsed = numBarTicks * pxPerTick <= COLLAPSE_THRESHOLD;
198
+ if (collapsed) {
199
+ // TODO: refactor this
200
+ while (
201
+ j < level.length - ff.jStep &&
202
+ barIndex + numBarTicks === ff.getBarOffset(level, j + ff.jStep) &&
203
+ ff.getBarTotal(level, j + ff.jStep) * pxPerTick <=
204
+ COLLAPSE_THRESHOLD &&
205
+ isHighlighted ===
206
+ ((props.highlightQuery &&
207
+ nodeIsInQuery(
208
+ j + ff.jStep + ff.jName,
209
+ level,
210
+ names,
211
+ props.highlightQuery
212
+ )) ||
213
+ false)
214
+ ) {
215
+ j += ff.jStep;
216
+ numBarTicks += ff.getBarTotal(level, j);
217
+ }
218
+ }
219
+
220
+ const sw = numBarTicks * pxPerTick - (collapsed ? 0 : GAP);
221
+ /*******************************/
222
+ /* D r a w R e c t */
223
+ /*******************************/
224
+ const { spyName } = props;
225
+
226
+ const getColor = () => {
227
+ const common = {
228
+ level,
229
+ j,
230
+ // discount for the levels we skipped
231
+ // otherwise it will dim out all nodes
232
+ i:
233
+ i +
234
+ focusedNode.mapOrElse(
235
+ () => 0,
236
+ (f) => f.i
237
+ ),
238
+ names,
239
+ collapsed,
240
+ selectedLevel,
241
+ highlightModeOn,
242
+ isHighlighted,
243
+ // keep type narrow https://stackoverflow.com/q/54333982
244
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
245
+ spyName: spyName as SpyName,
246
+ palette,
247
+ };
248
+
249
+ switch (format) {
250
+ case 'single': {
251
+ return getColorSingle({ ...common });
252
+ }
253
+ case 'double': {
254
+ return getColorDouble({
255
+ ...common,
256
+ leftTicks: props.leftTicks,
257
+ rightTicks: props.rightTicks,
258
+ });
259
+ }
260
+ default: {
261
+ throw new Error(`Unsupported format: ${format}`);
262
+ }
263
+ }
264
+ };
265
+
266
+ const color = getColor();
267
+
268
+ ctx.beginPath();
269
+ ctx.rect(x, y, sw, sh);
270
+ ctx.fillStyle = color.string();
271
+ ctx.fill();
272
+
273
+ /*******************************/
274
+ /* D r a w T e x t */
275
+ /*******************************/
276
+ // don't write text if there's not enough space for a single letter
277
+ if (collapsed) {
278
+ continue;
279
+ }
280
+
281
+ if (sw < LABEL_THRESHOLD) {
282
+ continue;
283
+ }
284
+
285
+ const shortName = getFunctionName(names, j, format, level);
286
+ const longName = getLongName(
287
+ shortName,
288
+ numBarTicks,
289
+ numTicks,
290
+ sampleRate,
291
+ formatter
292
+ );
293
+
294
+ // Set the font syle
295
+ // It's important to set the font BEFORE calculating 'characterSize'
296
+ // Since it will be used to calculate how many characters can fit
297
+ ctx.textBaseline = 'middle';
298
+ ctx.font =
299
+ '400 11.5px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace';
300
+ // Since this is a monospaced font any character would do
301
+ const characterSize = ctx.measureText('a').width;
302
+ const fitCalc = fitToCanvasRect({
303
+ mode: fitMode,
304
+ charSize: characterSize,
305
+ rectWidth: sw,
306
+ fullText: longName,
307
+ shortText: shortName,
308
+ });
309
+
310
+ ctx.save();
311
+ ctx.clip();
312
+ ctx.fillStyle = 'black';
313
+ const namePosX = Math.round(Math.max(x, 0));
314
+ ctx.fillText(fitCalc.text, namePosX + fitCalc.marginLeft, y + sh / 2 + 1);
315
+ ctx.restore();
316
+ }
317
+ }
318
+ }
319
+
320
+ function getFunctionName(
321
+ names: CanvasRendererConfig['names'],
322
+ j: number,
323
+ format: CanvasRendererConfig['format'],
324
+ level: number[]
325
+ ) {
326
+ const ff = createFF(format);
327
+
328
+ let l = level[j + ff.jName];
329
+ if (l === undefined) {
330
+ l = -1;
331
+ }
332
+ const shortName = names[l];
333
+
334
+ if (!shortName) {
335
+ console.warn('Could not find function name for', {
336
+ j,
337
+ format,
338
+ level,
339
+ names,
340
+ });
341
+ return '';
342
+ }
343
+ return shortName;
344
+ }
345
+
346
+ function getLongName(
347
+ shortName: string,
348
+ numBarTicks: number,
349
+ numTicks: number,
350
+ sampleRate: number,
351
+ formatter: ReturnType<typeof getFormatter>
352
+ ) {
353
+ const ratio = numBarTicks / numTicks;
354
+ const percent = formatPercent(ratio);
355
+
356
+ const longName = `${shortName} (${percent}, ${formatter.format(
357
+ numBarTicks,
358
+ sampleRate
359
+ )})`;
360
+
361
+ return longName;
362
+ }
363
+
364
+ type getColorCfg = {
365
+ collapsed: boolean;
366
+ level: number[];
367
+ j: number;
368
+ selectedLevel: number;
369
+ i: number;
370
+ highlightModeOn: boolean;
371
+ isHighlighted: boolean;
372
+ names: string[];
373
+ spyName: SpyName;
374
+ palette: FlamegraphPalette;
375
+ };
376
+
377
+ function getColorCommon({
378
+ collapsed,
379
+ highlightModeOn,
380
+ isHighlighted,
381
+ }: Pick<
382
+ getColorCfg,
383
+ 'selectedLevel' | 'i' | 'collapsed' | 'highlightModeOn' | 'isHighlighted'
384
+ >) {
385
+ // Collapsed
386
+ if (collapsed) {
387
+ return colorGreyscale(200, 0.66);
388
+ }
389
+
390
+ // We are in a search
391
+ if (highlightModeOn) {
392
+ if (!isHighlighted) {
393
+ return colorGreyscale(200, 0.66);
394
+ }
395
+ }
396
+
397
+ return null;
398
+ }
399
+
400
+ function getColorSingle(cfg: getColorCfg) {
401
+ const common = getColorCommon(cfg);
402
+
403
+ // common cases, like highlight
404
+ if (common) {
405
+ return common;
406
+ }
407
+
408
+ const ff = createFF('single');
409
+
410
+ const a = cfg.selectedLevel > cfg.i ? 0.33 : 1;
411
+
412
+ // TODO: clean this up
413
+ let l = cfg.level[cfg.j + ff.jName];
414
+ if (l === undefined) {
415
+ console.warn('Could nto find level', {
416
+ l: cfg.j,
417
+ jName: ff.jName,
418
+ level: cfg.level,
419
+ });
420
+ l = -1;
421
+ }
422
+ const name = cfg.names[l] || '';
423
+ const packageName = getPackageNameFromStackTrace(cfg.spyName, name) || '';
424
+
425
+ return colorBasedOnPackageName(cfg.palette, packageName).alpha(a);
426
+ }
427
+
428
+ function getColorDouble(
429
+ cfg: getColorCfg & { leftTicks: number; rightTicks: number }
430
+ ) {
431
+ const common = getColorCommon(cfg);
432
+
433
+ // common cases, like highlight
434
+ if (common) {
435
+ return common;
436
+ }
437
+
438
+ const a = cfg.selectedLevel > cfg.i ? 0.33 : 1;
439
+ const { leftRatio, rightRatio } = getRatios(
440
+ cfg.level,
441
+ cfg.j,
442
+ cfg.leftTicks,
443
+ cfg.rightTicks
444
+ );
445
+
446
+ const leftPercent = ratioToPercent(leftRatio);
447
+ const rightPercent = ratioToPercent(rightRatio);
448
+
449
+ return colorBasedOnDiffPercent(cfg.palette, leftPercent, rightPercent).alpha(
450
+ a
451
+ );
452
+ }
453
+
454
+ function nodeIsInQuery(
455
+ index: number,
456
+ level: number[],
457
+ names: string[],
458
+ query: string
459
+ ) {
460
+ const l = level[index];
461
+ if (!l) {
462
+ return false;
463
+ }
464
+
465
+ const l2 = names[l];
466
+ if (!l2) {
467
+ return false;
468
+ }
469
+
470
+ return isMatch(query, l2);
471
+ }
472
+
473
+ function getCanvasWidth(canvas: HTMLCanvasElement) {
474
+ // clientWidth includes padding
475
+ // however it's not present in node-canvas (used for testing)
476
+ // so we also fallback to canvas.width
477
+ return canvas.clientWidth || canvas.width;
478
+ }
@@ -0,0 +1,56 @@
1
+ // src/FlameGraph/FlameGraphComponent/GraphVizPane.tsx
2
+ import type { Flamebearer } from '../../models';
3
+ import React, { useMemo } from 'react';
4
+ import toGraphviz from '../../convert/toGraphviz';
5
+ import styles from './GraphVizPanel.module.scss';
6
+
7
+ interface IGraphvizProps {
8
+ dot: string;
9
+ options?: object;
10
+ className?: string;
11
+ }
12
+
13
+ // 这里不再引入 graphviz-react,而是用一个简单的占位组件
14
+ // 后续如果真的需要 GraphViz 视图,可以在这里改成动态 import
15
+ const Graphviz: React.FC<IGraphvizProps> = () => null;
16
+
17
+ interface GraphVizPaneProps {
18
+ flamebearer: Flamebearer;
19
+ }
20
+
21
+ export function GraphVizPane({ flamebearer }: GraphVizPaneProps) {
22
+ // TODO(@petethepig): 原始注释,保留
23
+ const fb = flamebearer as ShamefulAny;
24
+
25
+ // flamebearer 是否存在
26
+ const dot = fb.metadata?.format && fb.flamebearer?.levels;
27
+
28
+ // Graphviz 原来的逻辑:通过 key 强制 remount,避免缩放状态不更新
29
+ const key = `graphviz-pane-${fb?.appName || String(new Date().valueOf())}`;
30
+
31
+ const dotValue = useMemo(() => {
32
+ return toGraphviz(fb);
33
+ }, [JSON.stringify(fb)]);
34
+
35
+ return (
36
+ <div className={styles.graphVizPane} key={key}>
37
+ {dot ? (
38
+ <Graphviz
39
+ // options https://github.com/magjac/d3-graphviz#supported-options
40
+ options={{
41
+ zoom: true,
42
+ width: '150%',
43
+ height: '100%',
44
+ scale: 1,
45
+ // 'true' by default, but causes warning
46
+ // https://github.com/magjac/d3-graphviz/blob/master/README.md#defining-the-hpcc-jswasm-script-tag
47
+ useWorker: false,
48
+ }}
49
+ dot={dotValue}
50
+ />
51
+ ) : (
52
+ <div>NO DATA</div>
53
+ )}
54
+ </div>
55
+ );
56
+ }
@@ -0,0 +1,55 @@
1
+ .graphVizPane {
2
+ display: flex;
3
+ flex: 1;
4
+
5
+ // hacky better than !important
6
+ &#{&} {
7
+ margin-right: 0;
8
+ border: 1px solid var(--ps-ui-border);
9
+ }
10
+
11
+ div[id^='graphviz'] {
12
+ width: 100%;
13
+ overflow: hidden;
14
+
15
+ :global {
16
+ .graph > polygon {
17
+ // graphviz overlay
18
+ fill: none;
19
+ }
20
+
21
+ .node {
22
+ polygon {
23
+ // node box
24
+ // stroke: var(--ps-fl-toolbar-btn-bg);
25
+ }
26
+
27
+ text[text-anchor='middle'] {
28
+ // node caption
29
+ // fill: var(--ps-toolbar-icon-color);
30
+ }
31
+ }
32
+
33
+ .edge {
34
+ text[text-anchor='middle'] {
35
+ // edge caption
36
+ fill: var(--ps-toolbar-icon-color);
37
+ // fill: red;
38
+ }
39
+
40
+ a {
41
+ path {
42
+ // arrow body
43
+ // stroke: var(--ps-fl-toolbar-btn-bg);
44
+ }
45
+
46
+ polygon {
47
+ // arrow head
48
+ // stroke: var(--ps-fl-toolbar-btn-bg);
49
+ // fill: var(--ps-fl-toolbar-btn-bg);
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,27 @@
1
+ .flamegraphHeader {
2
+ padding-bottom: 5px;
3
+ display: flex;
4
+ justify-content: space-between;
5
+
6
+ align-items: flex-start;
7
+ }
8
+
9
+ .flamegraphHeader > div:first-child {
10
+ width: 100%;
11
+ }
12
+
13
+ .flamegraphHeader button {
14
+ /* margin: auto;
15
+ display: block; */
16
+ }
17
+
18
+ .row {
19
+ display: flex;
20
+ justify-content: center;
21
+ }
22
+
23
+ .flamegraphTitle {
24
+ width: 100%;
25
+ display: block;
26
+ text-align: center;
27
+ }
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import { Flamebearer } from '../../models';
3
+ import styles from './Header.module.css';
4
+ import { FlamegraphPalette } from './colorPalette';
5
+ import { DiffLegendPaletteDropdown } from './DiffLegendPaletteDropdown';
6
+
7
+ interface HeaderProps {
8
+ format: Flamebearer['format'];
9
+ units: Flamebearer['units'];
10
+
11
+ palette: FlamegraphPalette;
12
+ setPalette: (p: FlamegraphPalette) => void;
13
+ toolbarVisible?: boolean;
14
+ }
15
+ export default function Header(props: HeaderProps) {
16
+ const { format, units, palette, setPalette, toolbarVisible } = props;
17
+
18
+ const unitsToFlamegraphTitle = {
19
+ objects: 'number of objects in RAM per function',
20
+ goroutines: 'number of goroutines',
21
+ bytes: 'amount of RAM per function',
22
+ samples: 'CPU time per function',
23
+ lock_nanoseconds: 'time spent waiting on locks per function',
24
+ lock_samples: 'number of contended locks per function',
25
+ trace_samples: 'aggregated span duration',
26
+ exceptions: 'number of exceptions thrown',
27
+ unknown: '',
28
+ };
29
+
30
+ const getTitle = () => {
31
+ switch (format) {
32
+ case 'single': {
33
+ return (
34
+ <div>
35
+ <div
36
+ className={`${styles.row} ${styles.flamegraphTitle}`}
37
+ role="heading"
38
+ aria-level={2}
39
+ >
40
+ {unitsToFlamegraphTitle[units] && (
41
+ <>Frame width represents {unitsToFlamegraphTitle[units]}</>
42
+ )}
43
+ </div>
44
+ </div>
45
+ );
46
+ }
47
+
48
+ case 'double': {
49
+ return (
50
+ <>
51
+ <DiffLegendPaletteDropdown
52
+ palette={palette}
53
+ onChange={setPalette}
54
+ />
55
+ </>
56
+ );
57
+ }
58
+
59
+ default:
60
+ throw new Error(`unexpected format ${format}`);
61
+ }
62
+ };
63
+
64
+ const title = toolbarVisible ? getTitle() : null;
65
+
66
+ return (
67
+ <div className={styles.flamegraphHeader}>
68
+ <div>{title}</div>
69
+ </div>
70
+ );
71
+ }
@@ -0,0 +1,7 @@
1
+ .highlight {
2
+ position: absolute;
3
+ pointer-events: none;
4
+ background: #ffffff40;
5
+ mix-blend-mode: overlay;
6
+ z-index: 2;
7
+ }