| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 | /** * 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 onconst 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);
 |