You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					156 lines
				
				4.5 KiB
			
		
		
			
		
	
	
					156 lines
				
				4.5 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This source code is licensed under the MIT license found in the
							 | 
						||
| 
								 | 
							
								 * LICENSE file in the root directory of this source tree.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Make sure to run node with --expose-gc option!
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The times are reliable if about 1% relative mean error if you run it:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// * immediately after restart
							 | 
						||
| 
								 | 
							
								// * with 100% battery charge
							 | 
						||
| 
								 | 
							
								// * not connected to network
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* eslint import/no-extraneous-dependencies: "off" */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const Benchmark = require('benchmark');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const diffBaseline = require('diff').diffLines;
							 | 
						||
| 
								 | 
							
								const diffImproved = require('../build/index.js').default;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const testBaseline = (a, b) => {
							 | 
						||
| 
								 | 
							
								  const benchmark = new Benchmark({
							 | 
						||
| 
								 | 
							
								    fn() {
							 | 
						||
| 
								 | 
							
								      diffBaseline(a, b);
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    name: 'baseline',
							 | 
						||
| 
								 | 
							
								    onCycle() {
							 | 
						||
| 
								 | 
							
								      global.gc(); // after run cycle
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    onStart() {
							 | 
						||
| 
								 | 
							
								      global.gc(); // when benchmark starts
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  benchmark.run({async: false});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return benchmark.stats;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const testImproved = function(a, b) {
							 | 
						||
| 
								 | 
							
								  const benchmark = new Benchmark({
							 | 
						||
| 
								 | 
							
								    fn() {
							 | 
						||
| 
								 | 
							
								      // Split string arguments to make fair comparison with baseline.
							 | 
						||
| 
								 | 
							
								      const aItems = a.split('\n');
							 | 
						||
| 
								 | 
							
								      const bItems = b.split('\n');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const isCommon = (aIndex, bIndex) => aItems[aIndex] === bItems[bIndex];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // This callback obviously does less than baseline `diff` package,
							 | 
						||
| 
								 | 
							
								      // but avoiding double work and memory churn is the goal.
							 | 
						||
| 
								 | 
							
								      // For example, `jest-diff` has had to split strings that `diff` joins.
							 | 
						||
| 
								 | 
							
								      const foundSubsequence = () => {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      diffImproved(aItems.length, bItems.length, isCommon, foundSubsequence);
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    name: 'improved',
							 | 
						||
| 
								 | 
							
								    onCycle() {
							 | 
						||
| 
								 | 
							
								      global.gc(); // after run cycle
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    onStart() {
							 | 
						||
| 
								 | 
							
								      global.gc(); // when benchmark starts
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  benchmark.run({async: false});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return benchmark.stats;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const writeHeading2 = () => {
							 | 
						||
| 
								 | 
							
								  console.log('## Benchmark time for `diff-sequences` versus `diff`\n');
							 | 
						||
| 
								 | 
							
								  console.log('A ratio less than 1.0 means `diff-sequences` is faster.');
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const writeHeading3 = n => {
							 | 
						||
| 
								 | 
							
								  console.log(`\n### n = ${n}\n`);
							 | 
						||
| 
								 | 
							
								  console.log('| name | % | ratio | improved | rme | baseline | rme |');
							 | 
						||
| 
								 | 
							
								  console.log('| :--- | ---: | :--- | :--- | ---: | :--- | ---: |');
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const writeRow = (name, percent, statsImproved, statsBaseline) => {
							 | 
						||
| 
								 | 
							
								  const {mean: meanImproved, rme: rmeImproved} = statsImproved;
							 | 
						||
| 
								 | 
							
								  const {mean: meanBaseline, rme: rmeBaseline} = statsBaseline;
							 | 
						||
| 
								 | 
							
								  const ratio = meanImproved / meanBaseline;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  console.log(
							 | 
						||
| 
								 | 
							
								    `| ${name} | ${percent}% | ${ratio.toFixed(
							 | 
						||
| 
								 | 
							
								      4,
							 | 
						||
| 
								 | 
							
								    )} | ${meanImproved.toExponential(4)} | ${rmeImproved.toFixed(
							 | 
						||
| 
								 | 
							
								      2,
							 | 
						||
| 
								 | 
							
								    )}% | ${meanBaseline.toExponential(4)} | ${rmeBaseline.toFixed(2)}% |`,
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const testDeleteInsert = (tenths, more, less) => {
							 | 
						||
| 
								 | 
							
								  // For improved `diff-sequences` package, delete is often slower than insert.
							 | 
						||
| 
								 | 
							
								  const statsDeleteImproved = testImproved(more, less);
							 | 
						||
| 
								 | 
							
								  const statsDeleteBaseline = testBaseline(more, less);
							 | 
						||
| 
								 | 
							
								  writeRow('delete', tenths * 10, statsDeleteImproved, statsDeleteBaseline);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // For baseline `diff` package, many insertions is serious perf problem.
							 | 
						||
| 
								 | 
							
								  // However, the benchmark package cannot accurately measure for large n.
							 | 
						||
| 
								 | 
							
								  const statsInsertBaseline = testBaseline(less, more);
							 | 
						||
| 
								 | 
							
								  const statsInsertImproved = testImproved(less, more);
							 | 
						||
| 
								 | 
							
								  writeRow('insert', tenths * 10, statsInsertImproved, statsInsertBaseline);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const testChange = (tenths, expected, received) => {
							 | 
						||
| 
								 | 
							
								  const statsImproved = testImproved(expected, received);
							 | 
						||
| 
								 | 
							
								  const statsBaseline = testBaseline(expected, received);
							 | 
						||
| 
								 | 
							
								  writeRow('change', tenths * 10, statsImproved, statsBaseline);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const getItems = (n, callback) => {
							 | 
						||
| 
								 | 
							
								  const items = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (let i = 0; i !== n; i += 1) {
							 | 
						||
| 
								 | 
							
								    const item = callback(i);
							 | 
						||
| 
								 | 
							
								    if (typeof item === 'string') {
							 | 
						||
| 
								 | 
							
								      items.push(item);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return items.join('\n');
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Simulate change of property name which is usually not same line.
							 | 
						||
| 
								 | 
							
								// Expected: 0 1 2 3 4 5 6 7 8 9 and so on
							 | 
						||
| 
								 | 
							
								// Received: 1 2 3 4 x0 5 6 7 8 9 and so on
							 | 
						||
| 
								 | 
							
								const change2 = i => {
							 | 
						||
| 
								 | 
							
								  const j = i % 10;
							 | 
						||
| 
								 | 
							
								  return j === 4 ? `x${i - 4}` : j < 4 ? `${i + 1}` : `${i}`;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const testLength = n => {
							 | 
						||
| 
								 | 
							
								  const all = getItems(n, i => `${i}`);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  writeHeading3(n);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  [2, 4, 8].forEach(tenth => {
							 | 
						||
| 
								 | 
							
								    testDeleteInsert(tenth, all, getItems(n, i => i % 10 >= tenth && `${i}`));
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								  testChange(1, all, getItems(n, i => (i % 10 === 0 ? `x${i}` : `${i}`)));
							 | 
						||
| 
								 | 
							
								  testChange(2, all, getItems(n, change2));
							 | 
						||
| 
								 | 
							
								  testChange(5, all, getItems(n, i => (i % 2 === 0 ? `x${i}` : `${i}`)));
							 | 
						||
| 
								 | 
							
								  testChange(10, all, getItems(n, i => `x${i}`)); // simulate TDD
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								writeHeading2();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								testLength(20);
							 | 
						||
| 
								 | 
							
								testLength(200);
							 | 
						||
| 
								 | 
							
								testLength(2000);
							 |