// the call hirerarhcy is: suite > run > runIteration var ITERATIONS_BASE = 1e6; // reduce it for slow browsers/methods function jsonClone(x) { return JSON.parse(JSON.stringify(x)); } function message(x) { window.postMessage(x, location.origin); } function generateString () { return Math.random().toString(36).slice(2); } function runIteration(maxDepth, maxKeys, copyFn) { var totalKeys = 0; function generate(depth) { const num = depth / 2 + Math.floor(Math.random() * depth); if (num === 0 || totalKeys >= maxKeys) { totalKeys++; return generateString(); } var obj; // actually the proportion of arrays/objects almost doesn't affect executino time for most functions if (Math.random() > 0.1) { obj = {}; for (var i = 0; i < num; i++) { obj[generateString()] = generate(depth - 1); } } else { obj = []; for (var i = 0; i < num; i++) { obj.push(generate(depth - 1)); } } return obj; } var obj = generate(maxDepth); // it generates slightly more nodes, but no more than maxKeys + depth, which is negligible if (totalKeys < maxKeys) return; var start = performance.now(); copyFn(obj); return performance.now() - start; } // stats utility functions function avg(array) { return array.reduce(function(a, b) { return a + b; }, 0) / array.length; } function disp(array) { var avg2 = Math.pow(avg(array), 2); var sq2 = array.reduce(function (a, e) { return a + e * e - avg2; }, 0); return Math.sqrt(sq2) / array.length; } function run(copyFn, iterations, maxDepth, maxKeys) { var times = []; while (times.length < iterations * 1.2) { var time = runIteration(maxDepth, maxKeys, copyFn); if (time) times.push(time); } // remove top and bottom 1/12 times = times .sort(function (a, b) { return a - b; }) .slice(iterations * .1, -iterations * .1); return { avg: avg(times), // actual results seem suspiciously small, but gives some estimations anyway disp: 3 * disp(times) }; } function suite(copyFn) { [ { depth: 10, nodes: 1000 }, { depth: 10, nodes: 2000 }, { depth: 11, nodes: 3000 }, { depth: 11, nodes: 5000 }, { depth: 11, nodes: 7000 }, { depth: 12, nodes: 10000 }, { depth: 12, nodes: 14000 }, { depth: 12, nodes: 20000 }, { depth: 13, nodes: 30000 }, { depth: 13, nodes: 50000 }, { depth: 13, nodes: 70000 }, { depth: 13, nodes: 100000 } ].forEach(function (params) { var depth = params.depth; var nodes = params.nodes; var iterations = Math.max(20, Math.round(ITERATIONS_BASE / nodes / 10) * 10); console.log(nodes, run(copyFn, iterations, depth, nodes)); }); }