@grafana/flamegraph
Version:
Grafana flamegraph visualization component
1 lines • 23.6 kB
Source Map (JSON)
{"version":3,"file":"dataTransform.mjs","sources":["../../../src/FlameGraph/dataTransform.ts"],"sourcesContent":["import {\n createTheme,\n type DataFrame,\n type DisplayProcessor,\n type Field,\n FieldType,\n getDisplayProcessor,\n type GrafanaTheme2,\n} from '@grafana/data';\n\nimport { SampleUnit } from '../types';\n\nimport { mergeParentSubtrees, mergeSubtrees } from './treeTransforms';\n\nexport type LevelItem = {\n // Offset from the start of the level.\n start: number;\n // Value here can be different from a value of items in the data frame as for callers tree in sandwich view we have\n // to trim the value to correspond only to the part used by the children in the subtree.\n // In case of diff profile this is actually left + right value.\n value: number;\n // Only exists for diff profiles.\n valueRight?: number;\n // Index into the data frame. It is an array because for sandwich views we may be merging multiple items into single\n // node.\n itemIndexes: number[];\n children: LevelItem[];\n level: number;\n parents?: LevelItem[];\n};\n\nexport type CollapseConfig = {\n items: LevelItem[];\n collapsed: boolean;\n};\n\n/**\n * Convert data frame with nested set format into array of level. This is mainly done for compatibility with current\n * rendering code.\n */\nexport function nestedSetToLevels(\n container: FlameGraphDataContainer,\n options?: Options\n): [LevelItem[][], Record<string, LevelItem[]>, CollapsedMap] {\n const levels: LevelItem[][] = [];\n let offset = 0;\n\n let parent: LevelItem | undefined = undefined;\n const uniqueLabels: Record<string, LevelItem[]> = Object.create(null);\n\n for (let i = 0; i < container.data.length; i++) {\n const currentLevel = container.getLevel(i);\n const prevLevel = i > 0 ? container.getLevel(i - 1) : undefined;\n\n levels[currentLevel] = levels[currentLevel] || [];\n\n if (prevLevel && prevLevel >= currentLevel) {\n // We are going down a level or staying at the same level, so we are adding a sibling to the last item in a level.\n // So we have to compute the correct offset based on the last sibling.\n const lastSibling = levels[currentLevel][levels[currentLevel].length - 1];\n offset =\n lastSibling.start +\n container.getValue(lastSibling.itemIndexes[0]) +\n container.getValueRight(lastSibling.itemIndexes[0]);\n // we assume there is always a single root node so lastSibling should always have a parent.\n // Also it has to have the same parent because of how the items are ordered.\n parent = lastSibling.parents![0];\n }\n\n const newItem: LevelItem = {\n itemIndexes: [i],\n value: container.getValue(i) + container.getValueRight(i),\n valueRight: container.isDiffFlamegraph() ? container.getValueRight(i) : undefined,\n start: offset,\n parents: parent && [parent],\n children: [],\n level: currentLevel,\n };\n\n if (uniqueLabels[container.getLabel(i)]) {\n uniqueLabels[container.getLabel(i)].push(newItem);\n } else {\n uniqueLabels[container.getLabel(i)] = [newItem];\n }\n\n if (parent) {\n parent.children.push(newItem);\n }\n\n parent = newItem;\n levels[currentLevel].push(newItem);\n }\n\n const collapsedMapContainer = new CollapsedMapBuilder(options?.collapsingThreshold);\n if (options?.collapsing) {\n // We collapse similar items here, where it seems like parent and child are the same thing and so the distinction\n // isn't that important. We create a map of items that should be collapsed together. We need to do it with complete\n // tree as we need to know how many children an item has to know if we can collapse it.\n collapsedMapContainer.addTree(levels[0][0]);\n }\n\n return [levels, uniqueLabels, collapsedMapContainer.getCollapsedMap()];\n}\n\n/**\n * Small wrapper around the map of items that should be visually collapsed in the flame graph. Reason this is a wrapper\n * is that we want to make sure that when this is in the state we don't update the map directly but create a new map\n * and to have a place for the methods to collapse/expand either single item or all the items.\n */\nexport class CollapsedMap {\n // The levelItem used as a key is the item that will always be rendered in the flame graph. The config.items are all\n // the items that are in the group and if the config.collapsed is true they will be hidden.\n private map: Map<LevelItem, CollapseConfig> = new Map();\n\n constructor(map?: Map<LevelItem, CollapseConfig>) {\n this.map = map || new Map();\n }\n\n get(item: LevelItem) {\n return this.map.get(item);\n }\n\n keys() {\n return this.map.keys();\n }\n\n values() {\n return this.map.values();\n }\n\n size() {\n return this.map.size;\n }\n\n setCollapsedStatus(item: LevelItem, collapsed: boolean) {\n const newMap = new Map(this.map);\n const collapsedConfig = this.map.get(item)!;\n const newConfig = { ...collapsedConfig, collapsed };\n for (const item of collapsedConfig.items) {\n newMap.set(item, newConfig);\n }\n return new CollapsedMap(newMap);\n }\n\n setAllCollapsedStatus(collapsed: boolean) {\n const newMap = new Map(this.map);\n for (const item of this.map.keys()) {\n const collapsedConfig = this.map.get(item)!;\n const newConfig = { ...collapsedConfig, collapsed };\n newMap.set(item, newConfig);\n }\n\n return new CollapsedMap(newMap);\n }\n}\n\n/**\n * Similar to CollapsedMap but this one is mutable and used during transformation of the dataFrame data into structure\n * we use for rendering. This should not be passed to the React components.\n */\nexport class CollapsedMapBuilder {\n private map = new Map();\n private threshold = 0.99;\n\n constructor(threshold?: number) {\n if (threshold !== undefined) {\n this.threshold = threshold;\n }\n }\n\n addTree(root: LevelItem) {\n const stack = [root];\n while (stack.length) {\n const current = stack.shift()!;\n\n if (current.parents?.length) {\n this.addItem(current, current.parents[0]);\n }\n\n if (current.children.length) {\n stack.unshift(...current.children);\n }\n }\n }\n\n // The heuristics here is pretty simple right now. Just check if it's single child and if we are within threshold.\n // We assume items with small self just aren't too important while we cannot really collapse items with siblings\n // as it's not clear what to do with said sibling.\n addItem(item: LevelItem, parent?: LevelItem) {\n if (parent && item.value > parent.value * this.threshold && parent.children.length === 1) {\n if (this.map.has(parent)) {\n const config = this.map.get(parent)!;\n this.map.set(item, config);\n config.items.push(item);\n } else {\n const config = { items: [parent, item], collapsed: true };\n this.map.set(parent, config);\n this.map.set(item, config);\n }\n }\n }\n\n getCollapsedMap() {\n return new CollapsedMap(this.map);\n }\n}\n\nexport function getMessageCheckFieldsResult(wrongFields: CheckFieldsResult) {\n if (wrongFields.missingFields.length) {\n return `Data is missing fields: ${wrongFields.missingFields.join(', ')}`;\n }\n\n if (wrongFields.wrongTypeFields.length) {\n return `Data has fields of wrong type: ${wrongFields.wrongTypeFields\n .map((f) => `${f.name} has type ${f.type} but should be ${f.expectedTypes.join(' or ')}`)\n .join(', ')}`;\n }\n\n return '';\n}\n\nexport type CheckFieldsResult = {\n wrongTypeFields: Array<{ name: string; expectedTypes: FieldType[]; type: FieldType }>;\n missingFields: string[];\n};\n\nexport function checkFields(data: DataFrame): CheckFieldsResult | undefined {\n const fields: Array<[string, FieldType[]]> = [\n ['label', [FieldType.string, FieldType.enum]],\n ['level', [FieldType.number]],\n ['value', [FieldType.number]],\n ['self', [FieldType.number]],\n ];\n\n const missingFields = [];\n const wrongTypeFields = [];\n\n for (const field of fields) {\n const [name, types] = field;\n const frameField = data?.fields.find((f) => f.name === name);\n if (!frameField) {\n missingFields.push(name);\n continue;\n }\n if (!types.includes(frameField.type)) {\n wrongTypeFields.push({ name, expectedTypes: types, type: frameField.type });\n }\n }\n\n if (missingFields.length > 0 || wrongTypeFields.length > 0) {\n return {\n wrongTypeFields,\n missingFields,\n };\n }\n return undefined;\n}\n\nexport type Options = {\n collapsing: boolean;\n collapsingThreshold?: number;\n};\n\nexport class FlameGraphDataContainer {\n data: DataFrame;\n options: Options;\n\n labelField: Field;\n levelField: Field;\n valueField: Field;\n selfField: Field;\n\n // Optional fields for diff view\n valueRightField?: Field;\n selfRightField?: Field;\n\n labelDisplayProcessor: DisplayProcessor;\n valueDisplayProcessor: DisplayProcessor;\n uniqueLabels: string[];\n\n private levels: LevelItem[][] | undefined;\n private uniqueLabelsMap: Record<string, LevelItem[]> | undefined;\n private collapsedMap: CollapsedMap | undefined;\n\n constructor(data: DataFrame, options: Options, theme: GrafanaTheme2 = createTheme()) {\n this.data = data;\n this.options = options;\n\n const wrongFields = checkFields(data);\n if (wrongFields) {\n throw new Error(getMessageCheckFieldsResult(wrongFields));\n }\n\n this.labelField = data.fields.find((f) => f.name === 'label')!;\n this.levelField = data.fields.find((f) => f.name === 'level')!;\n this.valueField = data.fields.find((f) => f.name === 'value')!;\n this.selfField = data.fields.find((f) => f.name === 'self')!;\n\n this.valueRightField = data.fields.find((f) => f.name === 'valueRight')!;\n this.selfRightField = data.fields.find((f) => f.name === 'selfRight')!;\n\n if ((this.valueField || this.selfField) && !(this.valueField && this.selfField)) {\n throw new Error(\n 'Malformed dataFrame: both valueRight and selfRight has to be present if one of them is present.'\n );\n }\n\n const enumConfig = this.labelField?.config?.type?.enum;\n // Label can actually be an enum field so depending on that we have to access it through display processor. This is\n // both a backward compatibility but also to allow using a simple dataFrame without enum config. This would allow\n // users to use this panel with correct query from data sources that do not return profiles natively.\n if (enumConfig) {\n this.labelDisplayProcessor = getDisplayProcessor({ field: this.labelField, theme });\n this.uniqueLabels = enumConfig.text || [];\n } else {\n this.labelDisplayProcessor = (value) => ({\n text: value + '',\n numeric: 0,\n });\n this.uniqueLabels = [...new Set<string>(this.labelField.values)];\n }\n\n this.valueDisplayProcessor = getDisplayProcessor({\n field: this.valueField,\n theme,\n });\n }\n\n isDiffFlamegraph() {\n return Boolean(this.valueRightField && this.selfRightField);\n }\n\n getLabel(index: number) {\n return this.labelDisplayProcessor(this.labelField.values[index]).text;\n }\n\n getLevel(index: number) {\n return this.levelField.values[index];\n }\n\n getValue(index: number | number[]) {\n return fieldAccessor(this.valueField, index);\n }\n\n getValueRight(index: number | number[]) {\n return fieldAccessor(this.valueRightField, index);\n }\n\n getSelf(index: number | number[]) {\n return fieldAccessor(this.selfField, index);\n }\n\n getSelfRight(index: number | number[]) {\n return fieldAccessor(this.selfRightField, index);\n }\n\n getSelfDisplay(index: number | number[]) {\n return this.valueDisplayProcessor(this.getSelf(index));\n }\n\n getUniqueLabels() {\n return this.uniqueLabels;\n }\n\n getUnitTitle() {\n switch (this.valueField.config.unit) {\n case SampleUnit.Bytes:\n return 'RAM';\n case SampleUnit.Nanoseconds:\n return 'Time';\n }\n\n return 'Count';\n }\n\n getLevels() {\n this.initLevels();\n return this.levels!;\n }\n\n getSandwichLevels(label: string): [LevelItem[][], LevelItem[][]] {\n const nodes = this.getNodesWithLabel(label);\n\n if (!nodes?.length) {\n return [[], []];\n }\n\n const callers = mergeParentSubtrees(nodes, this);\n const callees = mergeSubtrees(nodes, this);\n\n return [callers, callees];\n }\n\n getNodesWithLabel(label: string) {\n this.initLevels();\n return this.uniqueLabelsMap![label];\n }\n\n getCollapsedMap() {\n this.initLevels();\n return this.collapsedMap!;\n }\n\n private initLevels() {\n if (!this.levels) {\n const [levels, uniqueLabelsMap, collapsedMap] = nestedSetToLevels(this, this.options);\n this.levels = levels;\n this.uniqueLabelsMap = uniqueLabelsMap;\n this.collapsedMap = collapsedMap;\n }\n }\n}\n\n// Access field value with either single index or array of indexes. This is needed as we sometimes merge multiple\n// into one, and we want to access aggregated values.\nfunction fieldAccessor(field: Field | undefined, index: number | number[]) {\n if (!field) {\n return 0;\n }\n let indexArray: number[] = typeof index === 'number' ? [index] : index;\n return indexArray.reduce((acc, index) => {\n return acc + field.values[index];\n }, 0);\n}\n"],"names":["item","index"],"mappings":"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"}