From 813a94c83f43193c3377adb22acc4fd73d04d9dd Mon Sep 17 00:00:00 2001 From: Jamie Wong Date: Sun, 17 Dec 2017 20:31:27 -0800 Subject: [PATCH] Add alphabetical sort order --- index.tsx | 52 +++++++++++++++++++++++++++++++++++++++++++++------- profile.ts | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/index.tsx b/index.tsx index fbc02cf..ccb4f28 100644 --- a/index.tsx +++ b/index.tsx @@ -7,19 +7,37 @@ import {importFromStackprof} from './import/stackprof' import {Profile} from './profile' import {Flamechart, FlamechartView} from './flamechart' +const enum SortOrder { + CHRONO, + ALPHA +} + interface ApplicationState { profile: Profile | null flamechart: Flamechart | null + sortedFlamechart: Flamechart | null + sortOrder: SortOrder } class Application extends Component<{}, ApplicationState> { + constructor() { + super() + this.state = { + profile: null, + flamechart: null, + sortedFlamechart: null, + sortOrder: SortOrder.CHRONO + } + } + onDrop = (ev: DragEvent) => { const file = ev.dataTransfer.files.item(0) const reader = new FileReader reader.addEventListener('loadend', () => { const profile = file.name.endsWith('json') ? importFromStackprof(reader.result) : importFromBGFlameGraph(reader.result) const flamechart = new Flamechart(profile) - this.setState({profile, flamechart}) + const sortedFlamechart = new Flamechart(profile.sortedAlphabetically()) + this.setState({profile, flamechart, sortedFlamechart}) }) reader.readAsText(file) ev.preventDefault() @@ -29,17 +47,37 @@ class Application extends Component<{}, ApplicationState> { ev.preventDefault() } + onWindowKeyPress = (ev: KeyboardEvent) => { + if (ev.key == 'a') { + this.setState({ + sortOrder: this.state.sortOrder === SortOrder.CHRONO ? SortOrder.ALPHA : SortOrder.CHRONO + }) + } + } + + onWindowResize = () => { + this.forceUpdate() + } + componentDidMount() { - window.addEventListener('resize', () => { - this.forceUpdate() - }) + window.addEventListener('resize', this.onWindowResize) + // TODO(jlfwong): for this to be safely embeddable, there'll need to be some + // way of specify event focus. + window.addEventListener('keypress', this.onWindowKeyPress) + } + + componentWillUnmount() { + window.removeEventListener('resize', this.onWindowResize) + window.removeEventListener('keypress', this.onWindowKeyPress) } render() { - const {flamechart} = this.state + const {flamechart, sortedFlamechart, sortOrder} = this.state + const flamechartToView = sortOrder == SortOrder.CHRONO ? flamechart : sortedFlamechart + return
- {flamechart && - } + {flamechartToView && + }
} } diff --git a/profile.ts b/profile.ts index b51f3b4..94659a6 100644 --- a/profile.ts +++ b/profile.ts @@ -170,4 +170,37 @@ export class Profile { this.timeDeltas.push(timeDelta) } } + + sortedAlphabetically(): Profile { + function key(sample: CallTreeNode) { + let k = '' + let node: CallTreeNode | null = sample + while (node) { + k = node.frame.name + ':' + k + node = node.parent + } + return k + } + + let sortedSamples: [CallTreeNode, number][] = [] + for (let i = 0; i < this.samples.length; i++) { + sortedSamples.push([this.samples[i], this.timeDeltas[i]]) + } + + sortedSamples.sort((a, b) => key(a[0]) < key(b[0]) ? -1 : 1) + + const sortedProfile = new Profile(this.duration) + for (const [stackTop, timeDelta] of sortedSamples) { + const stack: FrameInfo[] = [] + function visit(node: CallTreeNode) { + if (node.parent) visit(node.parent) + const frameInfo = {...node.frame} + frameInfo.key = frameInfo.name + stack.push(frameInfo) + } + visit(stackTop) + sortedProfile.appendSample(stack, timeDelta) + } + return sortedProfile + } } \ No newline at end of file