This defines a JSON-based file format for speedscope. The motivation for is primarily two things: 1. To enable others to write tools to output profiles which can be read by speedscope 2. To enable others to write tools to handle the output of speedscope, leveraging the variety of importers that speedscope supports Fixes #65
68 lines
1.7 KiB
TypeScript
68 lines
1.7 KiB
TypeScript
import * as fs from 'fs'
|
|
import * as path from 'path'
|
|
import {Profile, CallTreeNode, Frame} from './profile'
|
|
import {importProfile} from './import'
|
|
import {exportProfile, importSingleSpeedscopeProfile} from './file-format'
|
|
|
|
interface DumpedProfile {
|
|
stacks: string[]
|
|
frames: Frame[]
|
|
}
|
|
|
|
export function dumpProfile(profile: Profile): any {
|
|
const dump: DumpedProfile = {
|
|
stacks: [],
|
|
frames: [],
|
|
}
|
|
|
|
profile.forEachFrame(f => dump.frames.push(f))
|
|
|
|
let lastValue = 0
|
|
const curStack: (number | string)[] = []
|
|
|
|
function maybeEmit(value: number) {
|
|
if (lastValue != value) {
|
|
dump.stacks.push(
|
|
curStack.map(k => `${k}`).join(';') + ` ${profile.formatValue(value - lastValue)}`,
|
|
)
|
|
lastValue = value
|
|
}
|
|
}
|
|
|
|
function openFrame(node: CallTreeNode, value: number) {
|
|
maybeEmit(value)
|
|
curStack.push(node.frame.name)
|
|
}
|
|
|
|
function closeFrame(node: CallTreeNode, value: number) {
|
|
maybeEmit(value)
|
|
curStack.pop()
|
|
}
|
|
|
|
profile.forEachCall(openFrame, closeFrame)
|
|
|
|
return dump
|
|
}
|
|
|
|
export async function checkProfileSnapshot(filepath: string) {
|
|
const input = fs.readFileSync(filepath, 'utf8')
|
|
|
|
const profile = await importProfile(path.basename(filepath), input)
|
|
if (profile) {
|
|
expect(dumpProfile(profile)).toMatchSnapshot()
|
|
} else {
|
|
fail('Failed to extract profile')
|
|
return
|
|
}
|
|
|
|
const exported = exportProfile(profile)
|
|
const reimported = importSingleSpeedscopeProfile(exported)
|
|
|
|
expect(reimported.getName()).toEqual(profile.getName())
|
|
expect(reimported.getTotalWeight()).toEqual(profile.getTotalWeight())
|
|
expect(dumpProfile(reimported).stacks.join('\n')).toEqual(dumpProfile(profile).stacks.join('\n'))
|
|
|
|
const reexported = exportProfile(reimported)
|
|
expect(exported).toEqual(reexported)
|
|
}
|