@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.
- package/CHANGELOG.md +1211 -0
- package/LICENSE +202 -0
- package/README.md +251 -0
- package/dist/FlameGraph/FlameGraphComponent/CheckIcon.d.ts +2 -0
- package/dist/FlameGraph/FlameGraphComponent/CheckIcon.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/ContextMenu.d.ts +17 -0
- package/dist/FlameGraph/FlameGraphComponent/ContextMenu.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/ContextMenuHighlight.d.ts +14 -0
- package/dist/FlameGraph/FlameGraphComponent/ContextMenuHighlight.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/DiffLegend.d.ts +9 -0
- package/dist/FlameGraph/FlameGraphComponent/DiffLegend.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.d.ts +8 -0
- package/dist/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/Flamegraph.d.ts +96 -0
- package/dist/FlameGraph/FlameGraphComponent/Flamegraph.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/Flamegraph_render.d.ts +27 -0
- package/dist/FlameGraph/FlameGraphComponent/Flamegraph_render.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/GraphVizPane.d.ts +7 -0
- package/dist/FlameGraph/FlameGraphComponent/GraphVizPane.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/Header.d.ts +12 -0
- package/dist/FlameGraph/FlameGraphComponent/Header.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/Highlight.d.ts +18 -0
- package/dist/FlameGraph/FlameGraphComponent/Highlight.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/LogoLink.d.ts +2 -0
- package/dist/FlameGraph/FlameGraphComponent/LogoLink.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/color.d.ts +20 -0
- package/dist/FlameGraph/FlameGraphComponent/color.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/colorPalette.d.ts +11 -0
- package/dist/FlameGraph/FlameGraphComponent/colorPalette.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/constants.d.ts +6 -0
- package/dist/FlameGraph/FlameGraphComponent/constants.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/index.d.ts +37 -0
- package/dist/FlameGraph/FlameGraphComponent/index.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/murmur3.d.ts +2 -0
- package/dist/FlameGraph/FlameGraphComponent/murmur3.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/testData.d.ts +53 -0
- package/dist/FlameGraph/FlameGraphComponent/testData.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/utils.d.ts +6 -0
- package/dist/FlameGraph/FlameGraphComponent/utils.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphComponent/viewTypes.d.ts +2 -0
- package/dist/FlameGraph/FlameGraphComponent/viewTypes.d.ts.map +1 -0
- package/dist/FlameGraph/FlameGraphRenderer.d.ts +86 -0
- package/dist/FlameGraph/FlameGraphRenderer.d.ts.map +1 -0
- package/dist/FlameGraph/decode.d.ts +27 -0
- package/dist/FlameGraph/decode.d.ts.map +1 -0
- package/dist/FlameGraph/normalize.d.ts +6 -0
- package/dist/FlameGraph/normalize.d.ts.map +1 -0
- package/dist/FlameGraph/uniqueness.d.ts +3 -0
- package/dist/FlameGraph/uniqueness.d.ts.map +1 -0
- package/dist/FlamegraphRenderer.d.ts +19 -0
- package/dist/FlamegraphRenderer.d.ts.map +1 -0
- package/dist/Icons.d.ts +9 -0
- package/dist/Icons.d.ts.map +1 -0
- package/dist/ProfilerTable.d.ts +21 -0
- package/dist/ProfilerTable.d.ts.map +1 -0
- package/dist/SharedQueryInput.d.ts +10 -0
- package/dist/SharedQueryInput.d.ts.map +1 -0
- package/dist/Toolbar.d.ts +31 -0
- package/dist/Toolbar.d.ts.map +1 -0
- package/dist/Tooltip/FlamegraphTooltip.d.ts +59 -0
- package/dist/Tooltip/FlamegraphTooltip.d.ts.map +1 -0
- package/dist/Tooltip/LeftClickIcon.d.ts +2 -0
- package/dist/Tooltip/LeftClickIcon.d.ts.map +1 -0
- package/dist/Tooltip/RightClickIcon.d.ts +2 -0
- package/dist/Tooltip/RightClickIcon.d.ts.map +1 -0
- package/dist/Tooltip/TableTooltip.d.ts +12 -0
- package/dist/Tooltip/TableTooltip.d.ts.map +1 -0
- package/dist/Tooltip/Tooltip.d.ts +29 -0
- package/dist/Tooltip/Tooltip.d.ts.map +1 -0
- package/dist/convert/convertJaegerTraceToProfile.d.ts +3 -0
- package/dist/convert/convertJaegerTraceToProfile.d.ts.map +1 -0
- package/dist/convert/diffTwoProfiles.d.ts +3 -0
- package/dist/convert/diffTwoProfiles.d.ts.map +1 -0
- package/dist/convert/flamebearersToTree.d.ts +11 -0
- package/dist/convert/flamebearersToTree.d.ts.map +1 -0
- package/dist/convert/sandwichViewProfiles.d.ts +14 -0
- package/dist/convert/sandwichViewProfiles.d.ts.map +1 -0
- package/dist/convert/subtract.d.ts +3 -0
- package/dist/convert/subtract.d.ts.map +1 -0
- package/dist/convert/testData.d.ts +50 -0
- package/dist/convert/testData.d.ts.map +1 -0
- package/dist/convert/toGraphviz.d.ts +3 -0
- package/dist/convert/toGraphviz.d.ts.map +1 -0
- package/dist/fitMode/fitMode.d.ts +42 -0
- package/dist/fitMode/fitMode.d.ts.map +1 -0
- package/dist/format/format.d.ts +42 -0
- package/dist/format/format.d.ts.map +1 -0
- package/dist/i18n.d.ts +55 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/index.cjs.css +792 -0
- package/dist/index.cjs.js +5087 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.css +792 -0
- package/dist/index.esm.js +5079 -0
- package/dist/index.node.d.ts +9 -0
- package/dist/index.node.d.ts.map +1 -0
- package/dist/logo-v3-small-T5VXIMRR.svg +32 -0
- package/dist/models/decode.d.ts +3 -0
- package/dist/models/decode.d.ts.map +1 -0
- package/dist/models/flamebearer.d.ts +63 -0
- package/dist/models/flamebearer.d.ts.map +1 -0
- package/dist/models/groups.d.ts +37 -0
- package/dist/models/groups.d.ts.map +1 -0
- package/dist/models/index.d.ts +8 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/profile.d.ts +152 -0
- package/dist/models/profile.d.ts.map +1 -0
- package/dist/models/spyName.d.ts +8 -0
- package/dist/models/spyName.d.ts.map +1 -0
- package/dist/models/trace.d.ts +357 -0
- package/dist/models/trace.d.ts.map +1 -0
- package/dist/models/units.d.ts +6 -0
- package/dist/models/units.d.ts.map +1 -0
- package/dist/search.d.ts +2 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/shims/Box.d.ts +38 -0
- package/dist/shims/Box.d.ts.map +1 -0
- package/dist/shims/Button.d.ts +26 -0
- package/dist/shims/Button.d.ts.map +1 -0
- package/dist/shims/Dropdown.d.ts +30 -0
- package/dist/shims/Dropdown.d.ts.map +1 -0
- package/dist/shims/Input.d.ts +19 -0
- package/dist/shims/Input.d.ts.map +1 -0
- package/dist/shims/LoadingSpinner.d.ts +7 -0
- package/dist/shims/LoadingSpinner.d.ts.map +1 -0
- package/dist/shims/Menu.d.ts +4 -0
- package/dist/shims/Menu.d.ts.map +1 -0
- package/dist/shims/NoData.d.ts +2 -0
- package/dist/shims/NoData.d.ts.map +1 -0
- package/dist/shims/Table.d.ts +52 -0
- package/dist/shims/Table.d.ts.map +1 -0
- package/dist/shims/Tooltip.d.ts +9 -0
- package/dist/shims/Tooltip.d.ts.map +1 -0
- package/package.json +84 -0
- package/src/FlameGraph/FlameGraphComponent/CheckIcon.tsx +27 -0
- package/src/FlameGraph/FlameGraphComponent/ContextMenu.module.scss +10 -0
- package/src/FlameGraph/FlameGraphComponent/ContextMenu.spec.tsx +84 -0
- package/src/FlameGraph/FlameGraphComponent/ContextMenu.tsx +86 -0
- package/src/FlameGraph/FlameGraphComponent/ContextMenuHighlight.module.css +8 -0
- package/src/FlameGraph/FlameGraphComponent/ContextMenuHighlight.tsx +47 -0
- package/src/FlameGraph/FlameGraphComponent/DiffLegend.module.css +21 -0
- package/src/FlameGraph/FlameGraphComponent/DiffLegend.tsx +52 -0
- package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.module.css +40 -0
- package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.tsx +129 -0
- package/src/FlameGraph/FlameGraphComponent/Flamegraph.spec.ts +552 -0
- package/src/FlameGraph/FlameGraphComponent/Flamegraph.ts +446 -0
- package/src/FlameGraph/FlameGraphComponent/Flamegraph_render.spec.tsx +233 -0
- package/src/FlameGraph/FlameGraphComponent/Flamegraph_render.ts +478 -0
- package/src/FlameGraph/FlameGraphComponent/GraphVizPane.tsx +56 -0
- package/src/FlameGraph/FlameGraphComponent/GraphVizPanel.module.scss +55 -0
- package/src/FlameGraph/FlameGraphComponent/Header.module.css +27 -0
- package/src/FlameGraph/FlameGraphComponent/Header.tsx +71 -0
- package/src/FlameGraph/FlameGraphComponent/Highlight.module.css +7 -0
- package/src/FlameGraph/FlameGraphComponent/Highlight.spec.tsx +53 -0
- package/src/FlameGraph/FlameGraphComponent/Highlight.tsx +94 -0
- package/src/FlameGraph/FlameGraphComponent/LogoLink.module.scss +10 -0
- package/src/FlameGraph/FlameGraphComponent/LogoLink.tsx +101 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-collapses-small-blocks-into-one-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-diff-mode-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-highlighted-flamegraph-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-normal-flamegraph-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/canvas-renderer-spec-tsx-canvas-renderer-group-snapshot-works-with-selected-node-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-focused-also-zooms-1-snap.png +0 -0
- 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
- 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
- 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
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-complex-flamegraph-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-double-diff-flamegraph-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-highlighted-double-flamegraph-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-highlighted-flamegraph-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-simple-flamegraph-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-simple-tree-1-snap.png +0 -0
- package/src/FlameGraph/FlameGraphComponent/__image_snapshots__/flamegraph-render-spec-tsx-render-group-snapshot-renders-a-zoomed-flamegraph-1-snap.png +0 -0
- 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
- package/src/FlameGraph/FlameGraphComponent/canvas.module.css +6 -0
- package/src/FlameGraph/FlameGraphComponent/color.spec.ts +308 -0
- package/src/FlameGraph/FlameGraphComponent/color.ts +167 -0
- package/src/FlameGraph/FlameGraphComponent/colorPalette.ts +58 -0
- package/src/FlameGraph/FlameGraphComponent/constants.ts +5 -0
- package/src/FlameGraph/FlameGraphComponent/index.spec.tsx +291 -0
- package/src/FlameGraph/FlameGraphComponent/index.tsx +411 -0
- package/src/FlameGraph/FlameGraphComponent/murmur3.ts +97 -0
- package/src/FlameGraph/FlameGraphComponent/styles.module.scss +10 -0
- package/src/FlameGraph/FlameGraphComponent/testData.ts +427 -0
- package/src/FlameGraph/FlameGraphComponent/utils.ts +31 -0
- package/src/FlameGraph/FlameGraphComponent/viewTypes.ts +6 -0
- package/src/FlameGraph/FlameGraphRenderer.tsx +603 -0
- package/src/FlameGraph/FlamegraphRenderer.module.scss +93 -0
- package/src/FlameGraph/decode.ts +78 -0
- package/src/FlameGraph/normalize.spec.ts +76 -0
- package/src/FlameGraph/normalize.ts +60 -0
- package/src/FlameGraph/testData.json +423 -0
- package/src/FlameGraph/uniqueness.spec.ts +16 -0
- package/src/FlameGraph/uniqueness.ts +84 -0
- package/src/FlamegraphRenderer.tsx +61 -0
- package/src/Icons.tsx +74 -0
- package/src/ProfilerTable.tsx +527 -0
- package/src/SharedQueryInput.module.scss +82 -0
- package/src/SharedQueryInput.tsx +127 -0
- package/src/Toolbar.module.scss +117 -0
- package/src/Toolbar.spec.tsx +217 -0
- package/src/Toolbar.tsx +471 -0
- package/src/Tooltip/FlamegraphTooltip.spec.tsx +81 -0
- package/src/Tooltip/FlamegraphTooltip.tsx +257 -0
- package/src/Tooltip/LeftClickIcon.tsx +18 -0
- package/src/Tooltip/RightClickIcon.tsx +18 -0
- package/src/Tooltip/TableTooltip.spec.tsx +44 -0
- package/src/Tooltip/TableTooltip.tsx +145 -0
- package/src/Tooltip/Tooltip.module.scss +71 -0
- package/src/Tooltip/Tooltip.spec.tsx +395 -0
- package/src/Tooltip/Tooltip.tsx +336 -0
- package/src/__snapshots__/Toolbar.spec.tsx.snap +297 -0
- package/src/convert/convertJaegerTraceToProfile.ts +97 -0
- package/src/convert/diffTwoProfiles.ts +81 -0
- package/src/convert/flamebearersToTree.ts +78 -0
- package/src/convert/sandwichViewProfiles.spec.ts +65 -0
- package/src/convert/sandwichViewProfiles.ts +191 -0
- package/src/convert/subtract.ts +87 -0
- package/src/convert/testData.ts +145 -0
- package/src/convert/toGraphviz.ts +485 -0
- package/src/fitMode/fitMode.spec.ts +93 -0
- package/src/fitMode/fitMode.ts +122 -0
- package/src/format/format.spec.ts +291 -0
- package/src/format/format.ts +303 -0
- package/src/globals.d.ts +13 -0
- package/src/i18n.tsx +293 -0
- package/src/index.node.ts +19 -0
- package/src/index.spec.tsx +383 -0
- package/src/index.tsx +10 -0
- package/src/logo-v3-small.svg +32 -0
- package/src/models/decode.ts +45 -0
- package/src/models/flamebearer.ts +86 -0
- package/src/models/groups.ts +14 -0
- package/src/models/index.ts +7 -0
- package/src/models/profile.spec.ts +32 -0
- package/src/models/profile.ts +48 -0
- package/src/models/spyName.spec.ts +18 -0
- package/src/models/spyName.ts +32 -0
- package/src/models/trace.ts +45 -0
- package/src/models/units.spec.ts +21 -0
- package/src/models/units.ts +24 -0
- package/src/sass/_common.scss +206 -0
- package/src/sass/_css-variables.scss +201 -0
- package/src/sass/_mixins.scss +15 -0
- package/src/sass/_sanitize.scss +407 -0
- package/src/sass/_variables.scss +53 -0
- package/src/sass/flamegraph.scss +18 -0
- package/src/search.spec.ts +11 -0
- package/src/search.ts +4 -0
- package/src/shameful-any.d.ts +2 -0
- package/src/shims/Box.module.scss +57 -0
- package/src/shims/Box.tsx +105 -0
- package/src/shims/Button.module.scss +129 -0
- package/src/shims/Button.tsx +128 -0
- package/src/shims/Dropdown.module.scss +63 -0
- package/src/shims/Dropdown.tsx +96 -0
- package/src/shims/Input.module.scss +15 -0
- package/src/shims/Input.tsx +55 -0
- package/src/shims/LoadingSpinner.tsx +19 -0
- package/src/shims/Menu.tsx +9 -0
- package/src/shims/NoData.module.scss +6 -0
- package/src/shims/NoData.tsx +11 -0
- package/src/shims/Table.module.scss +82 -0
- package/src/shims/Table.spec.tsx +121 -0
- package/src/shims/Table.tsx +252 -0
- 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
|
+
}
|