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.
		
		
		
		
		
			
		
			
				
					
					
						
							155 lines
						
					
					
						
							4.5 KiB
						
					
					
				
			
		
		
	
	
							155 lines
						
					
					
						
							4.5 KiB
						
					
					
				/** | 
						|
 * 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);
 | 
						|
 |