@grafana/flamegraph
Version:
Grafana flamegraph visualization component
1 lines • 17.5 kB
Source Map (JSON)
{"version":3,"file":"utils.mjs","sources":["../../../src/CallTree/utils.ts"],"sourcesContent":["import { type GrafanaTheme2 } from '@grafana/data';\n\nimport { getBarColorByDiff, getBarColorByPackage, getBarColorByValue } from '../FlameGraph/colors';\nimport { type FlameGraphDataContainer, type LevelItem } from '../FlameGraph/dataTransform';\nimport { ColorScheme, type ColorSchemeDiff } from '../types';\n\nexport interface CallTreeNode {\n id: string;\n label: string;\n self: number;\n total: number;\n selfPercent: number;\n totalPercent: number;\n depth: number;\n parentId?: string;\n subtreeSize: number;\n levelItem: LevelItem;\n children?: CallTreeNode[];\n\n selfRight?: number;\n totalRight?: number;\n selfPercentRight?: number;\n totalPercentRight?: number;\n diffPercent?: number;\n}\n\nfunction computeDiffPercent(totalPercent: number, totalPercentRight: number): number {\n if (totalPercent > 0) {\n return ((totalPercentRight - totalPercent) / totalPercent) * 100;\n }\n if (totalPercentRight > 0) {\n return Infinity;\n }\n return 0;\n}\n\n/**\n * Build all call tree nodes from the root level items.\n * Returns an array of root nodes, each with their children.\n * This handles cases where there might be multiple root items.\n *\n * For diff flame graphs, separates left (baseline) and right (comparison) totals\n * to match the Flame Graph's calculation method.\n */\nexport function buildAllCallTreeNodes(data: FlameGraphDataContainer): CallTreeNode[] {\n const levels = data.getLevels();\n if (levels.length === 0) {\n return [];\n }\n\n const rootItem = levels[0][0];\n let rootTotalLeft: number;\n let rootTotalRight: number;\n\n if (data.isDiffFlamegraph()) {\n rootTotalRight = rootItem.valueRight || 0;\n rootTotalLeft = rootItem.value - rootTotalRight;\n } else {\n rootTotalLeft = rootItem.value;\n rootTotalRight = 0;\n }\n\n return levels[0].map((item, index) =>\n buildCallTreeNode(data, item, rootTotalLeft, rootTotalRight, undefined, -1, index)\n );\n}\n\n/**\n * Build a hierarchical call tree node from the LevelItem structure.\n * Each node gets a unique ID based on its path in the tree.\n */\nexport function buildCallTreeNode(\n data: FlameGraphDataContainer,\n rootItem: LevelItem,\n rootTotalLeft: number,\n rootTotalRight: number,\n parentId?: string,\n parentDepth = -1,\n childIndex = 0\n): CallTreeNode {\n const nodeId = parentId ? `${parentId}.${childIndex}` : `${childIndex}`;\n const depth = parentDepth + 1;\n\n const label = data.getLabel(rootItem.itemIndexes[0]);\n\n let self: number;\n let total: number;\n let selfPercent: number;\n let totalPercent: number;\n let selfRight: number | undefined;\n let totalRight: number | undefined;\n let selfPercentRight: number | undefined;\n let totalPercentRight: number | undefined;\n let diffPercent: number | undefined;\n\n if (data.isDiffFlamegraph()) {\n const selfLeft = data.getSelf(rootItem.itemIndexes);\n selfRight = data.getSelfRight(rootItem.itemIndexes);\n const totalLeft = rootItem.value - (rootItem.valueRight || 0);\n totalRight = rootItem.valueRight || 0;\n\n self = selfLeft;\n total = totalLeft;\n\n selfPercent = rootTotalLeft > 0 ? (selfLeft / rootTotalLeft) * 100 : 0;\n totalPercent = rootTotalLeft > 0 ? (totalLeft / rootTotalLeft) * 100 : 0;\n selfPercentRight = rootTotalRight > 0 ? (selfRight / rootTotalRight) * 100 : 0;\n totalPercentRight = rootTotalRight > 0 ? (totalRight / rootTotalRight) * 100 : 0;\n\n diffPercent = computeDiffPercent(totalPercent, totalPercentRight);\n } else {\n self = data.getSelf(rootItem.itemIndexes);\n total = rootItem.value;\n const rootTotal = rootTotalLeft;\n selfPercent = rootTotal > 0 ? (self / rootTotal) * 100 : 0;\n totalPercent = rootTotal > 0 ? (total / rootTotal) * 100 : 0;\n }\n\n const children =\n rootItem.children.length > 0\n ? rootItem.children.map((child, index) => {\n return buildCallTreeNode(data, child, rootTotalLeft, rootTotalRight, nodeId, depth, index);\n })\n : undefined;\n\n const subtreeSize = children ? children.reduce((sum, child) => sum + child.subtreeSize + 1, 0) : 0;\n\n return {\n id: nodeId,\n label,\n self,\n total,\n selfPercent,\n totalPercent,\n depth,\n parentId,\n subtreeSize,\n levelItem: rootItem,\n children,\n selfRight,\n totalRight,\n selfPercentRight,\n totalPercentRight,\n diffPercent,\n };\n}\n\n/**\n * Get initial expanded state for the tree.\n * Auto-expands first N levels.\n */\nexport function getInitialExpandedState(nodes: CallTreeNode[], levelsToExpand = 2): Record<string, boolean> {\n const expanded: Record<string, boolean> = {};\n\n nodes.forEach((node) => {\n collectExpandedByDepth(node, levelsToExpand, expanded);\n });\n\n return expanded;\n}\n\nfunction collectExpandedByDepth(node: CallTreeNode, levelsToExpand: number, expanded: Record<string, boolean>): void {\n if (node.depth < levelsToExpand && node.children && node.children.length > 0) {\n expanded[node.id] = true;\n }\n\n if (node.children) {\n node.children.forEach((child) => collectExpandedByDepth(child, levelsToExpand, expanded));\n }\n}\n\n/**\n * Build a callers tree from sandwich levels data.\n *\n * This follows the same pattern as the flame graph's sandwich mode:\n * - The sandwich transformation (mergeParentSubtrees) creates levels where:\n * - The last level contains the target function(s)\n * - Earlier levels contain callers, with `parents` pointing toward the target\n * - We start from the target (last level) and traverse via `parents` to build an inverted tree\n * - Values come directly from item.value (already transformed by sandwich transformation)\n * - Percentages are relative to the target's total (target = 100%), matching sandwich view\n */\nexport function buildCallersTree(levels: LevelItem[][], data: FlameGraphDataContainer): CallTreeNode[] {\n if (levels.length === 0) {\n return [];\n }\n\n const targetLevel = levels[levels.length - 1];\n if (!targetLevel || targetLevel.length === 0) {\n return [];\n }\n\n let targetTotalLeft: number;\n let targetTotalRight: number;\n\n if (data.isDiffFlamegraph()) {\n targetTotalRight = targetLevel.reduce((sum, item) => sum + (item.valueRight || 0), 0);\n targetTotalLeft = targetLevel.reduce((sum, item) => sum + item.value, 0) - targetTotalRight;\n } else {\n targetTotalLeft = targetLevel.reduce((sum, item) => sum + item.value, 0);\n targetTotalRight = 0;\n }\n\n const buildNode = (item: LevelItem, nodeId: string, depth: number, parentId: string | undefined): CallTreeNode => {\n const label = data.getLabel(item.itemIndexes[0]);\n\n let self: number;\n let total: number;\n let selfPercent: number;\n let totalPercent: number;\n let selfRight: number | undefined;\n let totalRight: number | undefined;\n let selfPercentRight: number | undefined;\n let totalPercentRight: number | undefined;\n let diffPercent: number | undefined;\n\n if (data.isDiffFlamegraph()) {\n const selfLeft = data.getSelf(item.itemIndexes);\n selfRight = data.getSelfRight(item.itemIndexes);\n const totalLeft = item.value - (item.valueRight || 0);\n totalRight = item.valueRight || 0;\n\n self = selfLeft;\n total = totalLeft;\n\n selfPercent = targetTotalLeft > 0 ? (selfLeft / targetTotalLeft) * 100 : 0;\n totalPercent = targetTotalLeft > 0 ? (totalLeft / targetTotalLeft) * 100 : 0;\n selfPercentRight = targetTotalRight > 0 ? (selfRight / targetTotalRight) * 100 : 0;\n totalPercentRight = targetTotalRight > 0 ? (totalRight / targetTotalRight) * 100 : 0;\n\n diffPercent = computeDiffPercent(totalPercent, totalPercentRight);\n } else {\n self = data.getSelf(item.itemIndexes);\n total = item.value;\n selfPercent = targetTotalLeft > 0 ? (self / targetTotalLeft) * 100 : 0;\n totalPercent = targetTotalLeft > 0 ? (total / targetTotalLeft) * 100 : 0;\n }\n\n const callers = item.parents || [];\n const children =\n callers.length > 0\n ? callers.map((caller, idx) => {\n return buildNode(caller, `${nodeId}.${idx}`, depth + 1, nodeId);\n })\n : undefined;\n\n const subtreeSize = children ? children.reduce((sum, child) => sum + child.subtreeSize + 1, 0) : 0;\n\n return {\n id: nodeId,\n label,\n self,\n total,\n selfPercent,\n totalPercent,\n depth,\n parentId,\n subtreeSize,\n levelItem: item,\n children,\n selfRight,\n totalRight,\n selfPercentRight,\n totalPercentRight,\n diffPercent,\n };\n };\n\n return targetLevel.map((targetItem, index) => buildNode(targetItem, `${index}`, 0, undefined));\n}\n\nexport function getRowBarColor(\n node: CallTreeNode,\n data: FlameGraphDataContainer,\n colorScheme: ColorScheme | ColorSchemeDiff,\n theme: GrafanaTheme2\n): string {\n if (data.isDiffFlamegraph()) {\n const levels = data.getLevels();\n const rootTotal = levels[0][0].value;\n const rootTotalRight = levels[0][0].valueRight || 0;\n\n const barColor = getBarColorByDiff(\n node.total + (node.totalRight || 0),\n node.totalRight || 0,\n rootTotal,\n rootTotalRight,\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n colorScheme as ColorSchemeDiff\n );\n return barColor.setAlpha(1.0).toString();\n } else {\n if (colorScheme === ColorScheme.ValueBased) {\n const levels = data.getLevels();\n const rootTotal = levels[0][0].value;\n const barColor = getBarColorByValue(node.total, rootTotal, 0, 1);\n return barColor.setAlpha(1.0).toString();\n } else {\n const barColor = getBarColorByPackage(node.label, theme);\n return barColor.setAlpha(1.0).toString();\n }\n }\n}\n"],"names":[],"mappings":"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"}