Skip to content

Commit

Permalink
Perf Test: Flamegraphs (microsoft#9550)
Browse files Browse the repository at this point in the history
* Port changes from 6.0 to master.

* WIP: working on scenario list

* scenario list go!

* fix shrinkwrap

* scenariolist fix

* hooking it up with perf-test

* Clean up flamegraphs regressed from webpack server to local file conversion. Fix React render consumption caused by use of fragments.

* Add master reference tests. Generate results blob. Add all scenarios from perf-test app.

* Fix master URL.

* Fix shrinkwrap.

* Add path for perf-tests task since it was removed from root config.

* Fix perf-test command.

* Copy perf test results to PR deploy site. Add BaseButtonNew case.

* Tweak output.

* Final cleanup.

* Disable puppeteer timeout.
  • Loading branch information
JasonGore authored and gingeroun committed Jul 5, 2019
1 parent f068274 commit 38d8720
Show file tree
Hide file tree
Showing 35 changed files with 747 additions and 244 deletions.
1 change: 1 addition & 0 deletions apps/perf-test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
logfiles
8 changes: 1 addition & 7 deletions apps/perf-test/config/pre-copy.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
{
"copyTo": {
"dist": [
"./index.html",
"./node_modules/react/umd/react.development.js",
"./node_modules/react/umd/react.production.min.js",
"./node_modules/react-dom/umd/react-dom.development.js",
"./node_modules/react-dom/umd/react-dom.production.min.js"
]
"dist": ["./index.html", "./node_modules/react/umd/react.production.min.js", "./node_modules/react-dom/umd/react-dom.production.min.js"]
}
}
2 changes: 2 additions & 0 deletions apps/perf-test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
</head>

<body>
<script src="./react.production.min.js"></script>
<script src="./react-dom.production.min.js"></script>
<script type="text/javascript" src="perf-test.js"></script>
</body>
</html>
6 changes: 5 additions & 1 deletion apps/perf-test/just.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
const perfTest = require('./tasks/perf-test');
const { preset, just } = require('@uifabric/build');
const { task } = just;
const { task, series } = just;

preset();

task('run-perf-test', perfTest);
task('perf-test', series('build', 'run-perf-test'));
8 changes: 7 additions & 1 deletion apps/perf-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,23 @@
"@types/react": "16.8.11",
"@types/react-dom": "16.8.4",
"@types/webpack-env": "1.13.9",
"@types/webpack-node-externals": "1.6.3",
"@uifabric/prettier-rules": "^7.0.2",
"@uifabric/tslint-rules": "^7.0.2",
"@uifabric/build": "^7.0.0"
"@uifabric/build": "^7.0.0",
"puppeteer": "^1.13.0",
"flamebearer": "^1.1.3",
"concat-stream": "^2.0.0"
},
"dependencies": {
"@uifabric/set-version": "^7.0.0",
"@uifabric/example-app-base": "^7.1.1",
"@uifabric/experiments": "^7.2.1",
"@microsoft/load-themed-styles": "^1.7.13",
"es6-promise": "^4.1.0",
"immutability-helper": "~2.8.1",
"office-ui-fabric-react": "^7.5.0",
"querystring": "^0.2.0",
"react": "16.8.6",
"react-dom": "16.8.6",
"tslib": "^1.7.1"
Expand Down
24 changes: 24 additions & 0 deletions apps/perf-test/src/index.scenarios.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';
import * as qs from 'querystring';

const scenarios = require('./scenarios/scenarioList');

initializeIcons();

const div = document.createElement('div');
document.body.appendChild(div);

// TODO: could default to displaying list of scenarios if param is not provided.
const defaultScenarioName = Object.keys(scenarios)[0];
const defaultIterations = 10;

const queryParams = qs.parse(window.location.search.substring(1));
const iterations = queryParams.iterations ? parseInt(queryParams.iterations as string, 10) : defaultIterations;
const scenario = queryParams.scenario ? (queryParams.scenario as string) : defaultScenarioName;

// TODO: Using React Fragments increases React (unstable_runWithPriority) render consumption from 4% to 26%.
// It'd be interesting to root cause why at some point.
// ReactDOM.render(<>{Array.from({ length: iterations }, () => (scenarios[scenario]))}</>, div);
ReactDOM.render(<div>{Array.from({ length: iterations }, () => scenarios[scenario])}</div>, div);
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/BaseButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { BaseButton } from 'office-ui-fabric-react';

const scenario = <BaseButton text="I am a button" />;

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/BaseButtonNew.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { BaseButton } from '@uifabric/experiments';

const scenario = <BaseButton text="I am a button" />;

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/DefaultButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { DefaultButton } from 'office-ui-fabric-react';

const scenario = <DefaultButton text="I am a button" />;

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/DefaultButtonNew.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { Button } from '@uifabric/experiments';

const scenario = <Button>I am a button</Button>;

export default scenario;
25 changes: 25 additions & 0 deletions apps/perf-test/src/scenarios/DetailsRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from 'react';
import { DetailsRow, IColumn, Selection, SelectionMode } from 'office-ui-fabric-react';

// tslint:disable-next-line:typedef
const Items = Array.from({ length: 10 }, (n, i) => ({
key: `Item ${i}`,
name: `Item ${i}`,
modified: new Date().toString(),
shared: 'Private',
size: `${Math.round(Math.random() * 1000) / 10}KB`
}));

const selection = new Selection();
selection.setItems(Items);

const Columns: IColumn[] = [
{ key: 'a', name: 'Name', fieldName: 'name', minWidth: 200, maxWidth: 400 },
{ key: 'b', name: 'Last modified', fieldName: 'modified', minWidth: 200, maxWidth: 400 },
{ key: 'c', name: 'Shared', fieldName: 'shared', minWidth: 300, maxWidth: 300 },
{ key: 'c', name: 'Size', fieldName: 'size', minWidth: 300, maxWidth: 300 }
];

const scenario = <DetailsRow itemIndex={0} item={Items[0]} columns={Columns} selection={selection} selectionMode={SelectionMode.single} />;

export default scenario;
36 changes: 36 additions & 0 deletions apps/perf-test/src/scenarios/DetailsRowNoStyles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from 'react';
import { createTheme, DetailsRowBase, IColumn, Selection, SelectionMode } from 'office-ui-fabric-react';

// tslint:disable-next-line:typedef
const Items = Array.from({ length: 10 }, (n, i) => ({
key: `Item ${i}`,
name: `Item ${i}`,
modified: new Date().toString(),
shared: 'Private',
size: `${Math.round(Math.random() * 1000) / 10}KB`
}));

const selection = new Selection();
selection.setItems(Items);

const Columns: IColumn[] = [
{ key: 'a', name: 'Name', fieldName: 'name', minWidth: 200, maxWidth: 400 },
{ key: 'b', name: 'Last modified', fieldName: 'modified', minWidth: 200, maxWidth: 400 },
{ key: 'c', name: 'Shared', fieldName: 'shared', minWidth: 300, maxWidth: 300 },
{ key: 'c', name: 'Size', fieldName: 'size', minWidth: 300, maxWidth: 300 }
];

const defaultTheme = createTheme({});

const scenario = (
<DetailsRowBase
theme={defaultTheme}
itemIndex={0}
item={Items[0]}
columns={Columns}
selection={selection}
selectionMode={SelectionMode.single}
/>
);

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/DocumentCardTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { DocumentCardTitle } from 'office-ui-fabric-react';

const scenario = <DocumentCardTitle title="This is the Title of a Very Interesting Document That Everyone Wnats to Read" shouldTruncate />;

export default scenario;
21 changes: 21 additions & 0 deletions apps/perf-test/src/scenarios/MenuButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import { DefaultButton } from 'office-ui-fabric-react';

const menuProps = {
items: [
{
key: 'emailMessage',
text: 'Email message',
iconProps: { iconName: 'Mail' }
},
{
key: 'calendarEvent',
text: 'Calendar event',
iconProps: { iconName: 'Calendar' }
}
]
};

const scenario = <DefaultButton text="I am a button" menuProps={menuProps} />;

export default scenario;
21 changes: 21 additions & 0 deletions apps/perf-test/src/scenarios/MenuButtonNew.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import { MenuButton } from '@uifabric/experiments';

const menuProps = {
items: [
{
key: 'emailMessage',
text: 'Email message',
iconProps: { iconName: 'Mail' }
},
{
key: 'calendarEvent',
text: 'Calendar event',
iconProps: { iconName: 'Calendar' }
}
]
};

const scenario = <MenuButton content="I am a button" menu={menuProps} />;

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/PrimaryButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { PrimaryButton } from 'office-ui-fabric-react';

const scenario = <PrimaryButton>I am a button</PrimaryButton>;

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/PrimaryButtonNew.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { Button } from '@uifabric/experiments';

const scenario = <Button primary content="I am a button" />;

export default scenario;
25 changes: 25 additions & 0 deletions apps/perf-test/src/scenarios/SplitButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as React from 'react';
import { DefaultButton } from 'office-ui-fabric-react';

const alertClicked = (): void => {
alert('Clicked');
};

const menuProps = {
items: [
{
key: 'emailMessage',
text: 'Email message',
iconProps: { iconName: 'Mail' }
},
{
key: 'calendarEvent',
text: 'Calendar event',
iconProps: { iconName: 'Calendar' }
}
]
};

const scenario = <DefaultButton split={true} text="I am a button" onClick={alertClicked} menuProps={menuProps} />;

export default scenario;
21 changes: 21 additions & 0 deletions apps/perf-test/src/scenarios/SplitButtonNew.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react';
import { SplitButton } from '@uifabric/experiments';

const menuProps = {
items: [
{
key: 'emailMessage',
text: 'Email message',
iconProps: { iconName: 'Mail' }
},
{
key: 'calendarEvent',
text: 'Calendar event',
iconProps: { iconName: 'Calendar' }
}
]
};

const scenario = <SplitButton content="I am a button" menu={menuProps} />;

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/Toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { Toggle } from 'office-ui-fabric-react';

const scenario = <Toggle checked />;

export default scenario;
6 changes: 6 additions & 0 deletions apps/perf-test/src/scenarios/ToggleNew.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { Toggle } from '@uifabric/experiments';

const scenario = <Toggle checked />;

export default scenario;
5 changes: 5 additions & 0 deletions apps/perf-test/src/scenarios/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as React from 'react';

const scenario = <button>I am a button</button>;

export default scenario;
14 changes: 14 additions & 0 deletions apps/perf-test/src/scenarios/scenarioList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const reqContext = require.context('./', false, /^\.\/(?!scenarioList)[^\.]*\.(j|t)sx?$/);

const scenarios: { [scenarioName: string]: string } = {};

reqContext.keys().forEach((key: string) => {
const pathSplit = key.replace(/^\.\//, '').split(/\\\//);
const basename = pathSplit[pathSplit.length - 1];
const scenarioName = basename.indexOf('.') > -1 ? basename.split('.')[0] : basename;
const scenarioModule = reqContext(key);

scenarios[scenarioName] = scenarioModule.default || scenarioModule;
});

module.exports = scenarios;
40 changes: 40 additions & 0 deletions apps/perf-test/tasks/flamegraph/flamebearer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// @ts-check
const fs = require('fs');

// @ts-ignore
const flamebearer = require('flamebearer');

module.exports = function(buf) {
console.time('Parsed JSON in');
let json = {};
try {
json = JSON.parse(buf.toString('utf8'));
} catch (e) {
// noop
}
if (!json.code || !json.ticks) {
console.log('Invalid input; expected a V8 log in JSON format. Produce one with:');
console.log('node --prof-process --preprocess -j isolate*.log');
return;
}
console.timeEnd('Parsed JSON in');

console.time('Processed V8 log in');
const { names, stacks } = flamebearer.v8logToStacks(json);
const levels = flamebearer.mergeStacks(stacks);
console.timeEnd('Processed V8 log in');

const vizSrc = fs.readFileSync(require.resolve('flamebearer/viz.js'), 'utf8');
const src = fs
.readFileSync(require.resolve('flamebearer/index.html'), 'utf8')
.toString()
.split('<script src="viz.js"></script>')
.join(`<script>${vizSrc}</script>`)
.split('/* BIN_SPLIT */')
.filter((str, i) => i % 2 === 0)
.join('')
.split('/* BIN_PLACEHOLDER */')
.join(`names = ${JSON.stringify(names)};\n` + `levels = ${JSON.stringify(levels)};\n` + `numTicks = ${stacks.length};`);

return src;
};
Loading

0 comments on commit 38d8720

Please sign in to comment.