mirror of
https://github.com/jlfwong/speedscope.git
synced 2024-11-22 22:14:25 +03:00
Importing from brendangregg/FlameGraph format
This commit is contained in:
parent
e4c378d8ea
commit
15aa924583
@ -259,10 +259,8 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
labels: FlamechartFrameLabel[] = []
|
||||
hoveredLabel: FlamechartFrameLabel | null = null
|
||||
|
||||
private preprocess() {
|
||||
if (!this.canvas) return
|
||||
|
||||
const {flamechart} = this.props
|
||||
private preprocess(flamechart: Flamechart) {
|
||||
if (!this.canvas || !this.ctx) return
|
||||
const configSpaceRects: Rect[] = []
|
||||
const colors: vec3[] = []
|
||||
|
||||
@ -272,6 +270,7 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
|
||||
const frameColors = flamechart.getFrameColors()
|
||||
|
||||
this.labels = []
|
||||
for (let i = 0; i < layers.length; i++) {
|
||||
const layer = layers[i]
|
||||
for (let flamechartFrame of layer) {
|
||||
@ -289,14 +288,15 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
}
|
||||
}
|
||||
|
||||
this.ctx = this.canvas.getContext('webgl')!
|
||||
this.renderer = rectangleBatchRenderer(this.ctx, configSpaceRects, colors)
|
||||
this.configSpaceViewportRect = new Rect()
|
||||
this.hoveredLabel = null
|
||||
}
|
||||
|
||||
private canvasRef = (element?: Element) => {
|
||||
if (element) {
|
||||
this.canvas = element as HTMLCanvasElement
|
||||
this.preprocess()
|
||||
this.ctx = this.canvas.getContext('webgl')!
|
||||
this.renderCanvas()
|
||||
} else {
|
||||
this.canvas = null
|
||||
@ -442,14 +442,8 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
|
||||
// Still initializing: don't resize yet
|
||||
if (width === 0 || height === 0) return
|
||||
|
||||
// Already at the right size
|
||||
if (width === this.canvas.width && height === this.canvas.height) return
|
||||
|
||||
const oldWidth = this.canvas.width
|
||||
const oldHeight = this.canvas.height
|
||||
this.canvas.width = width
|
||||
this.canvas.height = height
|
||||
|
||||
if (this.configSpaceViewportRect.isEmpty()) {
|
||||
this.configSpaceViewportRect = new Rect(
|
||||
@ -466,6 +460,13 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
// Already at the right size
|
||||
if (width === oldWidth && height === oldHeight) return
|
||||
|
||||
this.canvas.width = width
|
||||
this.canvas.height = height
|
||||
|
||||
this.ctx.viewport(0, 0, width, height)
|
||||
}
|
||||
|
||||
@ -488,6 +489,7 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
// size.
|
||||
requestAnimationFrame(() => this.renderCanvas())
|
||||
} else {
|
||||
if (!this.renderer) this.preprocess(this.props.flamechart)
|
||||
this.renderRects()
|
||||
this.renderLabels()
|
||||
}
|
||||
@ -607,7 +609,12 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
}
|
||||
|
||||
shouldComponentUpdate() { return false }
|
||||
componentWillReceiveProps() { this.renderCanvas() }
|
||||
componentWillReceiveProps(nextProps: FlamechartPanZoomViewProps) {
|
||||
if (this.props.flamechart !== nextProps.flamechart) {
|
||||
this.renderer = null
|
||||
}
|
||||
this.renderCanvas()
|
||||
}
|
||||
componentDidMount() {
|
||||
window.addEventListener('mouseup', this.onWindowMouseUp)
|
||||
}
|
||||
@ -662,6 +669,11 @@ export class FlamechartView extends Component<FlamechartViewProps, FlamechartVie
|
||||
static TOOLTIP_WIDTH_MAX = 300
|
||||
static TOOLTIP_HEIGHT_MAX = 75
|
||||
|
||||
formatTime(timeInNs: number) {
|
||||
const totalTimeNs = this.props.flamechart.getDuration()
|
||||
return `${(timeInNs / 1000).toFixed(2)}ms (${(100 * timeInNs/totalTimeNs).toFixed()}%)`
|
||||
}
|
||||
|
||||
renderTooltip() {
|
||||
if (!this.container) return null
|
||||
|
||||
@ -693,10 +705,10 @@ export class FlamechartView extends Component<FlamechartViewProps, FlamechartVie
|
||||
return (
|
||||
<div className={css(style.hoverTip)} style={positionStyle}>
|
||||
<div className={css(style.hoverTipRow)}>{hoveredNode.frame.name}</div>
|
||||
<div className={css(style.hoverTipRow)}>Total Time: {(hoveredNode.getTotalTime() / 1000).toFixed(2)}ms</div>
|
||||
<div className={css(style.hoverTipRow)}>Self Time: {(hoveredNode.getSelfTime() / 1000).toFixed(2)}ms</div>
|
||||
<div className={css(style.hoverTipRow)}>Cum. Total Time: {(hoveredNode.frame.getTotalTime() / 1000).toFixed(2)}ms</div>
|
||||
<div className={css(style.hoverTipRow)}>Cum. Self Time: {(hoveredNode.frame.getSelfTime() / 1000).toFixed(2)}ms</div>
|
||||
<div className={css(style.hoverTipRow)}>Total Time: {this.formatTime(hoveredNode.getTotalTime())}</div>
|
||||
<div className={css(style.hoverTipRow)}>Self Time: {this.formatTime(hoveredNode.getSelfTime())}</div>
|
||||
<div className={css(style.hoverTipRow)}>Cum. Total Time: {this.formatTime(hoveredNode.frame.getTotalTime())}</div>
|
||||
<div className={css(style.hoverTipRow)}>Cum. Self Time: {this.formatTime(hoveredNode.frame.getSelfTime())}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -729,6 +741,7 @@ const style = StyleSheet.create({
|
||||
paddingTop: HOVERTIP_PADDING,
|
||||
paddingBottom: HOVERTIP_PADDING,
|
||||
pointerEvents: 'none',
|
||||
userSelect: 'none',
|
||||
fontSize: FontSize.LABEL,
|
||||
fontFamily: FontFamily.MONOSPACE
|
||||
},
|
||||
|
30
import/bg-flamegraph.ts
Normal file
30
import/bg-flamegraph.ts
Normal file
@ -0,0 +1,30 @@
|
||||
// https://github.com/brendangregg/FlameGraph#2-fold-stacks
|
||||
|
||||
import {Profile, FrameInfo} from '../profile'
|
||||
|
||||
interface BGSample {
|
||||
stack: FrameInfo[]
|
||||
duration: number
|
||||
}
|
||||
|
||||
function parseBGFoldedStacks(contents: string): BGSample[] {
|
||||
const samples: BGSample[] = []
|
||||
contents.replace(/^(.*) (\d+)$/mg, (match: string, stack: string, n: string) => {
|
||||
samples.push({
|
||||
stack: stack.split(';').map(name => ({key: name, name: name})),
|
||||
duration: parseInt(n, 10)
|
||||
})
|
||||
return match
|
||||
})
|
||||
return samples
|
||||
}
|
||||
|
||||
export function importFromBGFlameGraph(contents: string): Profile {
|
||||
const parsed = parseBGFoldedStacks(contents)
|
||||
const duration = parsed.reduce((prev: number, cur: BGSample) => prev + cur.duration, 0)
|
||||
const profile = new Profile(duration)
|
||||
for (let sample of parsed) {
|
||||
profile.appendSample(sample.stack, sample.duration)
|
||||
}
|
||||
return profile
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// https://github.com/tmm1/stackprof
|
||||
|
||||
import {Profile, Frame} from './profile'
|
||||
import {Profile, FrameInfo} from '../profile'
|
||||
|
||||
interface StackprofFrame {
|
||||
name: string
|
||||
@ -25,7 +25,7 @@ export function importFromStackprof(contents: string): Profile {
|
||||
for (let i = 0; i < raw.length;) {
|
||||
const stackHeight = raw[i++]
|
||||
|
||||
const stack: Frame[] = []
|
||||
const stack: FrameInfo[] = []
|
||||
for (let j = 0; j < stackHeight; j++) {
|
||||
const id = raw[i++]
|
||||
stack.push({
|
@ -1,7 +1,8 @@
|
||||
import {h, render, Component} from 'preact'
|
||||
import {StyleSheet, css} from 'aphrodite'
|
||||
|
||||
import {importFromStackprof} from './stackprof'
|
||||
import {importFromBGFlameGraph} from './import/bg-flamegraph'
|
||||
|
||||
import {Profile} from './profile'
|
||||
import {Flamechart, FlamechartView} from './flamechart'
|
||||
|
||||
@ -16,7 +17,7 @@ class Application extends Component<{}, ApplicaionState> {
|
||||
onDrop = (ev: DragEvent) => {
|
||||
const reader = new FileReader
|
||||
reader.addEventListener('loadend', () => {
|
||||
const profile = importFromStackprof(reader.result)
|
||||
const profile = importFromBGFlameGraph(reader.result)
|
||||
const flamechart = new Flamechart(profile)
|
||||
this.setState({profile, flamechart})
|
||||
})
|
||||
|
@ -142,6 +142,7 @@ export class Profile {
|
||||
}
|
||||
|
||||
appendSample(stack: FrameInfo[], timeDelta: number) {
|
||||
if (isNaN(timeDelta)) throw new Error('invalid timeDelta')
|
||||
let node: CallTreeNode | null = null
|
||||
let children = this.calltreeRoots
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user