speedscope/flamechart.ts
2018-01-07 18:36:23 -08:00

73 lines
1.9 KiB
TypeScript

import {Frame, CallTreeNode} from './profile'
import { Color } from './color'
import { lastOf } from './utils'
interface FlamechartFrame {
node: CallTreeNode
start: number
end: number
parent: FlamechartFrame | null
children: FlamechartFrame[]
}
type StackLayer = FlamechartFrame[]
interface FlamechartDataSource {
getTotalWeight(): number
formatValue(v: number): string
forEachCall(
openFrame: (node: CallTreeNode, value: number) => void,
closeFrame: (value: number) => void
): void
getColorForFrame(f: Frame): Color
}
export class Flamechart {
// Bottom to top
private layers: StackLayer[] = []
private totalWeight: number = 0
private minFrameWidth: number = 1
getTotalWeight() { return this.totalWeight }
getLayers() { return this.layers }
getColorForFrame(f: Frame) { return this.source.getColorForFrame(f) }
getMinFrameWidth() { return this.minFrameWidth }
formatValue(v: number) { return this.source.formatValue(v) }
constructor(private source: FlamechartDataSource) {
const stack: FlamechartFrame[] = []
const openFrame = (node: CallTreeNode, value: number) => {
const parent = lastOf(stack)
const frame: FlamechartFrame = {
node,
parent,
children: [],
start: value,
end: value,
}
if (parent) {
parent.children.push(frame)
}
stack.push(frame)
}
this.minFrameWidth = Infinity
const closeFrame = (value: number) => {
console.assert(stack.length > 0)
const stackTop = stack.pop()!
stackTop.end = value
if (stackTop.end - stackTop.start === 0) return
const layerIndex = stack.length
while (this.layers.length <= layerIndex) this.layers.push([])
this.layers[layerIndex].push(stackTop)
this.minFrameWidth = Math.min(this.minFrameWidth, stackTop.end - stackTop.start)
}
this.totalWeight = source.getTotalWeight()
source.forEachCall(openFrame, closeFrame)
}
}