Skip to content

Commit

Permalink
Pull aggrow from facebookincubator/tracery-prerelease
Browse files Browse the repository at this point in the history
Reviewed By: bnham

Differential Revision: D4250937

fbshipit-source-id: b5f2cfdeb06c04399670e463b8b2498e2fe0074b
  • Loading branch information
cwdick authored and Facebook Github Bot committed Nov 30, 2016
1 parent 3094c36 commit 48d3cd7
Show file tree
Hide file tree
Showing 20 changed files with 25,271 additions and 5 deletions.
22,673 changes: 22,673 additions & 0 deletions local-cli/server/middleware/heapCapture/bundle.js

Large diffs are not rendered by default.

6 changes: 1 addition & 5 deletions local-cli/server/middleware/heapCapture/heapCapture.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
<head>
<meta charset="utf-8">
<title>JSC Heap Capture</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.1/react-dom.js"></script>
<script src="out/aggrow.js"></script>
<script src="out/table.js"></script>
</head>
<body style="margin:0px; height: 100%">
Loading... This could take a while depending on how big the profile is. Check devtools console for errors.
</body>
<script src="preLoadedCapture.js"></script>
<script src="out/heapCapture.js"></script>
<script src="bundle.js"></script>
</html>
21 changes: 21 additions & 0 deletions local-cli/server/middleware/heapCapture/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "jsc-heap-capture",
"version": "1.0.0",
"description": "processes captured heaps from javascript core",
"main": "bundle.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "cwdick",
"devDependencies": {
"babel-core": "^6.17.0",
"babel-loader": "^6.2.5",
"babel-plugin-transform-class-properties": "^6.16.0",
"babel-preset-es2015": "^6.16.0",
"babel-preset-react": "^6.16.0",
"react": "^0.14.1",
"react-dom": "^0.14.1",
"webpack": "^1.13.2"
}
}
190 changes: 190 additions & 0 deletions local-cli/server/middleware/heapCapture/src/Aggrow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// @flow

import invariant from 'invariant';

import AggrowData, {
AggrowDoubleColumn,
AggrowIntColumn,
AggrowStackColumn,
AggrowStringColumn } from './AggrowData';
import AggrowExpander from './AggrowExpander';
import type { FlattenedStack } from './StackRegistry';
import StackRegistry from './StackRegistry';

export type FocusConfig = {
pattern: RegExp,
firstMatch: boolean,
leftSide: boolean,
}
type FocusPredicate = (frameId: number) => boolean;

export default class Aggrow {
data: AggrowData;
expander: AggrowExpander;

constructor(aggrowData: AggrowData) {
aggrowData.flattenStacks();
this.data = aggrowData;
this.expander = new AggrowExpander(aggrowData.rowCount);
}

addSumAggregator(aggregatorName: string, columnName: string): number {
const column = this.data.getColumn(columnName);

invariant(column, `Column ${columnName} does not exist.`);
invariant(column instanceof AggrowIntColumn || column instanceof AggrowDoubleColumn,
`Sum aggregator does not support ${column.constructor.name} columns!`);
return this.expander.addAggregator(
aggregatorName,
(indices: Int32Array): number => {
let size = 0;
indices.forEach((i: number) => { size += column.get(i); });
return size;
},
(value: any): string => value.toLocaleString(),
(a: number, b: number): number => b - a,
);
}

addCountAggregator(aggregatorName: string): number {
return this.expander.addAggregator(
aggregatorName,
(indices: Int32Array): number => indices.length,
(value: any): string => value.toLocaleString(),
(a: number, b: number): number => b - a,
);
}

addStringExpander(expanderName: string, columnName: string): number {
const column = this.data.getColumn(columnName);
invariant(column, `Column ${columnName} does not exist.`);
invariant(column instanceof AggrowStringColumn, 'String expander needs a string column.');
const strings = column.strings;
return this.expander.addFieldExpander(
expanderName,
(rowA: number, rowB: number): number => column.get(rowA) - column.get(rowB),
(row: number): string => strings.get(column.get(row)),
(s: string): string => s,
);
}

addNumberExpander(expanderName: string, columnName: string): number {
const column = this.data.getColumn(columnName);
invariant(column, `Column ${columnName} does not exist.`);
invariant(
column instanceof AggrowIntColumn || column instanceof AggrowDoubleColumn,
`Number expander does not support ${column.constructor.name} columns.`);
return this.expander.addFieldExpander(
expanderName,
(rowA: number, rowB: number): number => column.get(rowA) - column.get(rowB),
(row: number): number => column.get(row),
(n: any): string => n.toLocaleString(),
);
}

addPointerExpander(expanderName: string, columnName: string): number {
const column = this.data.getColumn(columnName);
invariant(column, `Column ${columnName} does not exist.`);
invariant(
column instanceof AggrowIntColumn,
`Pointer expander does not support ${column.constructor.name} columns.`);
return this.expander.addFieldExpander(
expanderName,
(rowA: number, rowB: number): number => column.get(rowA) - column.get(rowB),
(row: number): number => column.get(row),
(p: number): string => `0x${(p >>> 0).toString(16)}`, // eslint-disable-line no-bitwise
);
}

addStackExpander(
expanderName: string,
columnName: string,
reverse: boolean,
focus: ?FocusConfig): number {
const column = this.data.getColumn(columnName);
invariant(column, `Column ${columnName} does not exist.`);
invariant(
column instanceof AggrowStackColumn,
`Stack expander does not support ${column.constructor.name} columns.`);
let stacks = column.stacks;
const getter = column.getter;
const formatter = column.formatter;
if (focus) {
const re = focus.pattern;
const predicate = (frameId: number): boolean => re.test(formatter(getter(frameId)));
stacks = focusStacks(stacks, predicate, focus.firstMatch, focus.leftSide);
}
return this.expander.addStackExpander(
expanderName,
stacks.maxDepth,
(row: number): FlattenedStack => stacks.get(column.get(row)),
getter,
formatter,
!!reverse,
);
}
}

function focusStacks(
stacks: StackRegistry,
predicate: FocusPredicate,
firstMatch: boolean,
leftSide: boolean): FocusedStackRegistry {
let stackMapper;
if (firstMatch && leftSide) {
stackMapper = (stack: FlattenedStack): FlattenedStack => {
for (let i = 0; i < stack.length; i++) {
if (predicate(stack[i])) {
return stack.subarray(0, i + 1);
}
}
return stack.subarray(0, 0);
};
} else if (firstMatch && !leftSide) {
stackMapper = (stack: FlattenedStack): FlattenedStack => {
for (let i = 0; i < stack.length; i++) {
if (predicate(stack[i])) {
return stack.subarray(i, stack.length);
}
}
return stack.subarray(0, 0);
};
} else if (!firstMatch && leftSide) {
stackMapper = (stack: FlattenedStack): FlattenedStack => {
for (let i = stack.length - 1; i >= 0; i--) {
if (predicate(stack[i])) {
return stack.subarray(0, i + 1);
}
}
return stack.subarray(0, 0);
};
} else { // !firstMatch && !leftSide
stackMapper = (stack: FlattenedStack): FlattenedStack => {
for (let i = stack.length - 1; i >= 0; i--) {
if (predicate(stack[i])) {
return stack.subarray(i, stack.length);
}
}
return stack.subarray(0, 0);
};
}

invariant(stacks.stackIdMap, 'Stacks were not flattened.');
return new FocusedStackRegistry(
stacks.stackIdMap.map(stackMapper),
stacks.maxDepth);
}

class FocusedStackRegistry {
maxDepth: number;
stackIdMap: Array<FlattenedStack>;

constructor(stackIdMap: Array<FlattenedStack>, maxDepth: number) {
this.maxDepth = maxDepth;
this.stackIdMap = stackIdMap;
}

get(id: number): FlattenedStack {
return this.stackIdMap[id];
}
}
Loading

0 comments on commit 48d3cd7

Please sign in to comment.