@grafana/flamegraph
Version:
Grafana flamegraph visualization component
1 lines • 23.3 kB
Source Map (JSON)
{"version":3,"file":"dataTransform.mjs","sources":["../../../src/FlameGraph/dataTransform.ts"],"sourcesContent":["import {\n createTheme,\n DataFrame,\n DisplayProcessor,\n Field,\n FieldType,\n getDisplayProcessor,\n 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[]> = {};\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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"}