From efeaea70a97ec1afb54f85e220ce844863f04946 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 22 Jan 2018 17:28:03 -0800 Subject: [PATCH] Benchmarks include forced layout time This change to 'benchmarks' reports the time taken to perform a forced layout after mounting the tree. Adding a forced layout to the stress tests can surface how different approaches to styling may affect browser render timings. The total time displayed is now the sum of "scripting time" (previously total time) and "layout time". The layout time is a reflection of the time the browser takes to perform a style recalculation and relayout of the document. The Benchmark component now has a 'forceLayout' prop. When it is 'true' a forced layout is triggered on componentDidUpdate. The time taken is added to the sample's timing data. --- .flowconfig | 1 - packages/benchmarks/src/app/App.js | 3 + .../benchmarks/src/app/Benchmark/index.js | 82 ++++++++++++------- .../benchmarks/src/app/Benchmark/types.js | 21 +++-- packages/benchmarks/src/app/ReportCard.js | 8 +- packages/benchmarks/src/app/Text.js | 4 - packages/benchmarks/src/impl.js | 2 - 7 files changed, 73 insertions(+), 48 deletions(-) diff --git a/.flowconfig b/.flowconfig index cf05611e..a5a41701 100644 --- a/.flowconfig +++ b/.flowconfig @@ -3,7 +3,6 @@ [ignore] /.*/__tests__/.* -/packages/benchmarks/.* /packages/.*/dist/.* /website/.* .*/node_modules/babel-plugin-transform-react-remove-prop-types/* diff --git a/packages/benchmarks/src/app/App.js b/packages/benchmarks/src/app/App.js index 7cf7b222..d849de82 100644 --- a/packages/benchmarks/src/app/App.js +++ b/packages/benchmarks/src/app/App.js @@ -100,6 +100,8 @@ export default class App extends Component { libraryName={r.libraryName} libraryVersion={r.libraryVersion} mean={r.mean} + meanLayout={r.meanLayout} + meanScripting={r.meanScripting} runTime={r.runTime} sampleCount={r.sampleCount} stdDev={r.stdDev} @@ -130,6 +132,7 @@ export default class App extends Component { ): boolean => { switch (type) { // Render every odd iteration (first, third, etc) @@ -66,7 +66,8 @@ const sortNumbers = (a: number, b: number): number => a - b; type BenchmarkPropsType = { component: typeof React.Component, - getComponentProps?: Function, + forceLayout?: boolean, + getComponentProps: Function, onComplete: (x: BenchResultsType) => void, sampleCount: number, timeout: number, @@ -84,13 +85,13 @@ type BenchmarkStateType = { * TODO: documentation */ export default class Benchmark extends Component { + _raf: ?Function; _startTime: number; _samples: Array; static displayName = 'Benchmark'; static defaultProps = { - getComponentProps: () => emptyObject, sampleCount: 50, timeout: 10000, // 10 seconds type: BenchmarkType.MOUNT @@ -101,8 +102,9 @@ export default class Benchmark extends Component ({ componentProps: nextProps.getComponentProps(state.cycle) })); + if (nextProps) { + this.setState(state => ({ componentProps: nextProps.getComponentProps(state.cycle) })); + } } componentWillUpdate(nextProps: BenchmarkPropsType, nextState: BenchmarkStateType) { @@ -121,11 +125,20 @@ export default class Benchmark extends Component : null; } @@ -162,15 +175,18 @@ export default class Benchmark extends Component { + this._raf = window.requestAnimationFrame(() => { this.setState((state: BenchmarkStateType) => ({ cycle: state.cycle + 1, componentProps @@ -182,10 +198,16 @@ export default class Benchmark extends Component, - { start, end: endTime }: SampleTimingType + { scriptingStart, scriptingEnd, layoutStart, layoutEnd }: SampleTimingType ): Array => { - const end = endTime || 0; - memo.push({ start, end, elapsed: end - start }); + memo.push({ + start: scriptingStart, + end: layoutEnd || scriptingEnd || 0, + scriptingStart, + scriptingEnd: scriptingEnd || 0, + layoutStart, + layoutEnd + }); return memo; }, [] @@ -199,11 +221,13 @@ export default class Benchmark extends Component ({ running: false, cycle: 0 })); const runTime = endTime - this._startTime; - const sortedElapsedTimes = samples - .map(({ elapsed }: { elapsed: number }): number => elapsed) + const sortedElapsedTimes = samples.map(({ start, end }) => end - start).sort(sortNumbers); + const sortedScriptingElapsedTimes = samples + .map(({ scriptingStart, scriptingEnd }) => scriptingEnd - scriptingStart) + .sort(sortNumbers); + const sortedLayoutElapsedTimes = samples + .map(({ layoutStart, layoutEnd }) => (layoutEnd || 0) - (layoutStart || 0)) .sort(sortNumbers); - const mean = getMean(sortedElapsedTimes); - const stdDev = getStdDev(sortedElapsedTimes); onComplete({ startTime: this._startTime, @@ -214,8 +238,10 @@ export default class Benchmark extends Component {fmt(mean)} ±{fmt(stdDev)} ms - - Σ = - {Math.round(runTime)} ms + + (S/L) {fmt(meanScripting)} / {fmt(meanLayout)} ms ) : ( diff --git a/packages/benchmarks/src/app/Text.js b/packages/benchmarks/src/app/Text.js index a284ee6f..451e729b 100644 --- a/packages/benchmarks/src/app/Text.js +++ b/packages/benchmarks/src/app/Text.js @@ -1,9 +1,5 @@ /* eslint-disable react/prop-types */ -/** - * @flow - */ - import { bool } from 'prop-types'; import React from 'react'; import { StyleSheet, Text } from 'react-native'; diff --git a/packages/benchmarks/src/impl.js b/packages/benchmarks/src/impl.js index 504527b3..fae2d0e5 100644 --- a/packages/benchmarks/src/impl.js +++ b/packages/benchmarks/src/impl.js @@ -1,5 +1,3 @@ -/* @flow */ - import { type Component } from 'react'; import packageJson from '../package.json';