diff --git a/Libraries/ReactNative/__benchmarks__/ReactNativeAttributePayload-benchmark.js b/Libraries/ReactNative/__benchmarks__/ReactNativeAttributePayload-benchmark.js new file mode 100644 index 000000000..afc2b81f3 --- /dev/null +++ b/Libraries/ReactNative/__benchmarks__/ReactNativeAttributePayload-benchmark.js @@ -0,0 +1,324 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule ReactNativeAttributePayload-benchmark + */ +'use strict'; + +var StyleSheet = require('StyleSheet'); + +// Various example props + +var small1 = { + accessible: true, + accessibilityLabel: 'Hello', + collapsable: true, +}; + +var small2 = { + accessible: true, + accessibilityLabel: 'Hello 2', + collapsable: false, + needsOffscreenAlphaCompositing: true, +}; + +var small3 = { + accessible: true, + accessibilityLabel: 'Hello 2', +}; + +var medium1 = { + ...small1, + onLayout: function() {}, + onAccessibilityTap: true, + onMagicTap: function() {}, + collapsable: true, + needsOffscreenAlphaCompositing: true, + style: { + backgroundColor: 'rgba(255, 0, 0, 0.5)' + } +}; + +var medium2 = { + ...small2, + onLayout: function() {}, + onAccessibilityTap: true, + onMagicTap: function() {}, + collapsable: true, + needsOffscreenAlphaCompositing: true, + style: { + backgroundColor: 'rgba(128, 0, 0, 1)', + color: [128, 0, 0], + shadowColor: 56, + textDecorationColor: 34, + tintColor: 45, + + transform: [ + {perspective: 5}, + {scale: 5}, + {scaleX: 10}, + {scaleY: 10}, + {translateX: 2}, + {translateY: 5} + ], + } +}; + +var medium3 = { + ...small3, + onAccessibilityTap: true, + onMagicTap: function() {}, + needsOffscreenAlphaCompositing: true, + style: { + backgroundColor: 'rgba(255, 0, 0, 0.5)', + color: [128, 0, 0], + shadowColor: 56, + textDecorationColor: 34, + tintColor: 45, + + transform: [ + {perspective: 5}, + {scale: 5}, + {scaleX: 12}, + {scaleY: 16}, + {translateX: 10}, + {translateY: 5} + ], + } +}; + +var style1 = { + + backgroundColor: 'rgba(10,0,0,1)', + borderColor: 'rgba(10,0,0,1)', + color: [255, 0, 0], + shadowColor: 54, + textDecorationColor: 34, + tintColor: 45, + + transform: [ + {perspective: 5}, + {scale: 5}, + {scaleX: 2}, + {scaleY: 3}, + {translateX: 2}, + {translateY: 3} + ], + +}; + +var style1b = { + + backgroundColor: 'rgba(10,0,0,1)', + borderColor: 'rgba(10,0,0,1)', + color: [128, 0, 0], + shadowColor: 56, + textDecorationColor: 34, + tintColor: 45, + + transform: [ + {perspective: 5}, + {scale: 5}, + {scaleX: 10}, + {scaleY: 10}, + {translateX: 2}, + {translateY: 5} + ], + +}; + +var style2 = { + + shadowOffset: { width: 10, height: 15 }, + + resizeMode: 'contain', // 'cover' + overflow: 'visible', // 'hidden' + + opacity: 0.5, + + width: 123, + height: 43, + top: 13, + left: 43, + right: 12, + bottom: 123, + margin: 13, + padding: 53, + paddingRight: 523, + borderWidth: 63, + borderRadius: 123, +}; + +var style3 = { + position: 'absolute', // 'relative' + flexDirection: 'row', // 'column' + flexWrap: 'wrap', // 'nowrap' + justifyContent: 'flex-start', // 'flex-end' + alignItems: 'center', + alignSelf: 'auto', + flex: 0, +}; + +var style3b = { + position: 'relative', + flexDirection: 'column', + flexWrap: 'nowrap', + justifyContent: 'flex-end', +}; + +var { regStyle2, regStyle3 } = StyleSheet.create({ + regStyle2: style2, + regStyle3: style3 +}); + +var large1 = { + ...medium1, + style: { + ...medium1.style, + ...style1, + ...style2, + ...style3 + } +}; + +var large2 = { + ...medium2, + style: [ + [regStyle2, style1], + regStyle3 + ] +}; + +var large3 = { + ...medium3, + style: [ + [regStyle2, style1b], + style3 + ] +}; + +var large4 = { + ...medium3, + style: [ + [regStyle2, style1b], + style3b + ] +}; + +// Clones, to test + +var clone = function (obj) { + var str = JSON.stringify(obj, function(k, v) { + return typeof v === 'function' ? 'FUNCTION' : v; + }); + return JSON.parse(str, function(k, v) { + return v === 'FUNCTION' ? function() {} : v; + }); +}; + +var small4 = clone(small3); +var medium4 = clone(medium3); +var large5 = clone(large4); + +// Test combinations + +var variants = { + s1: small1, + s2: small2, + s3: small3, + s4: small4, + m1: medium1, + m2: medium2, + m3: medium3, + m4: medium4, + l1: large1, + l2: large2, + l3: large3, + l4: large4, + l5: large5, +}; + +// Differ + +var validAttributes = require('ReactNativeViewAttributes').UIView; + +var ReactNativeBaseComponent = require('ReactNativeBaseComponent'); +ReactNativeBaseComponent.prototype.diff = + ReactNativeBaseComponent.prototype.computeUpdatedProperties; +var Differ = new ReactNativeBaseComponent({ + validAttributes: validAttributes, + uiViewClassName: 'Differ' +}); + +// Runner + +var numberOfBenchmarks = 0; +var totalTimeForAllBenchmarks = 0; +var results = {}; + +function runBenchmarkOnce(value1, value2) { + // Warm up the differ. This is needed if the differ uses state to store the + // previous values. + Differ.diff({}, value1, validAttributes); + var cache = Differ.previousFlattenedStyle; + var start = Date.now(); + for (var i = 0; i < 100; i++) { + Differ.diff(value1, value2, validAttributes); + Differ.previousFlattenedStyle = cache; + } + var end = Date.now(); + return (end - start); +} + +function runBenchmark(key1, key2, value1, value2) { + var totalTime = 0; + var nthRuns = 5; + for (var i = 0; i < nthRuns; i++) { + totalTime += runBenchmarkOnce(value1, value2); + } + results[key1 + key2] = totalTime / nthRuns; + totalTimeForAllBenchmarks += totalTime / nthRuns; + numberOfBenchmarks++; +} + +function runAllCombinations() { + for (var outerKey in variants) { + for (var innerKey in variants) { + if (variants.hasOwnProperty(outerKey) && + variants.hasOwnProperty(innerKey)) { + runBenchmark( + outerKey, + innerKey, + variants[outerKey], + variants[innerKey] + ); + } + } + } +} + +function formatResult() { + var str = + 'Average runtime: ' + + (totalTimeForAllBenchmarks / numberOfBenchmarks) + + ' units\n'; + + var worstCase = 0; + for (var key in results) { + if (results[key] > worstCase) { + worstCase = results[key]; + } + } + + str += 'Worst case: ' + worstCase + ' units\n'; + + str += 'Per combination:\n'; + for (var key in results) { + str += key + ':\u00A0' + results[key] + ', '; + } + return str; +} + +runAllCombinations(); + +module.exports = formatResult();