Skip to content

Commit

Permalink
Implement speed with running functions in separate processes
Browse files Browse the repository at this point in the history
Fixes: metarhia#9
  • Loading branch information
DzyubSpirit committed Sep 15, 2017
1 parent 430eb14 commit d63c27d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 23 deletions.
58 changes: 49 additions & 9 deletions lib/speed.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,62 @@
'use strict';

const util = require('util');
const rpad = (s, char, count) => (s + char.repeat(count - s.length));
const lpad = (s, char, count) => (char.repeat(count - s.length) + s);
const cp = require('child_process');

const timeStartSrcCode = 'const __begin_time__ = process.hrtime();';
const timeEndSrcCode = `
const __end_time__ = process.hrtime(__begin_time__);
console.log(__end_time__[0] * 1e9 + __end_time__[1]);
`;

const speedSrcCode = (
srcCode, // source code for runnning
preSrcCode = '' // source code for running before start of time measurement
) => {
try {
if (typeof srcCode === 'function') srcCode = '(' + srcCode + ')();';
if (typeof perSrcCode === 'function') {
preSrcCode = '(' + preSrcCode + ')();';
}
const input = util.format('%s;%s;%s;%s',
preSrcCode, timeStartSrcCode, srcCode, timeEndSrcCode);
const stdout = cp.execFileSync('node', [], { input });
const lines = stdout.toString().split('\n');
const time = +lines[lines.length - 2];
return [null, time];
} catch (e) {
return [e];
}
};

const wrapInLoop = (
srcCode, // source to wrap in loop
count // number of loop iterations
) => util.format(`
for (var __loop_counter__ = 0; __loop_counter__ < %d; __loop_counter__++) {
%s;
}`, count, srcCode);

const speedFn = (
fn, // function which speed is measured
{ count, preSrcCode }
// count is number of times which fn will be ran
// preSrcCode is code needed to be declared before function
) => speedSrcCode(wrapInLoop(fn, count), preSrcCode);

const speed = (
caption,
count,
tests
tests // [{ fn, preSrcCode }]
// fn is function for running
// preSrcCode is source code which should be declarated before function
) => {
const times = tests.map((fn) => {
const result = [];
const begin = process.hrtime();
let i;
for (i = 0; i < count; i++) result.push(fn());
const end = process.hrtime(begin);
const time = end[0] * 1e9 + end[1];
const times = tests.map(({ fn, preSrcCode }) => {
const [err, time] = speedFn(fn, { count, preSrcCode });
const name = rpad(fn.name, '.', 25);
return { name, time };
return { name, time: err ? 'FAILED' : time };
});
console.log();
const top = times.sort((t1, t2) => (t1.time - t2.time));
Expand Down
30 changes: 16 additions & 14 deletions test/speed.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ function newPrototype() {
return new ProtoItem('world', 100500, true);
}

const ClassItem = class {
class ClassItem {
constructor(hello, size, flag) {
this.hello = hello;
this.size = size;
this.flag = flag;
}
};
}

function newClass() {
return new ClassItem('world', 100500, true);
Expand Down Expand Up @@ -86,16 +86,18 @@ function itemFactory(hello, size, flag) {
return { hello, size, flag };
}

const makeTest = ([fn, ...usedFns]) => ({ fn, preSrcCode: usedFns.join(';') });

maojian.speed('Benchmark example', 2000000, [
closureInstance,
defineObject,
defineArray,
defineArrayOfString,
defineArrayOfNumber,
mixinObject,
newPrototype,
newClass,
newObject,
objectCreate,
callFactory
]);
[closureInstance, makeClosure],
[defineObject],
[defineArray],
[defineArrayOfString],
[defineArrayOfNumber],
[mixinObject],
[newPrototype, ProtoItem],
[newClass, ClassItem],
[newObject],
[objectCreate],
[callFactory, itemFactory],
].map(makeTest));

0 comments on commit d63c27d

Please sign in to comment.