add bench.json

This commit is contained in:
Tony Brix 2019-04-25 07:47:23 -05:00
parent c99e69b406
commit 99d1fd00e0
2 changed files with 262 additions and 1 deletions

View File

@ -58,7 +58,7 @@
"test:lint": "eslint bin/marked .",
"test:redos": "eslint --plugin vuln-regex-detector --rule '\"vuln-regex-detector/no-vuln-regex\": 2' lib/marked.js",
"test:node4": "npx node@4 ./node_modules/jasmine/bin/jasmine.js --config=jasmine.json",
"bench": "node test --bench",
"bench": "node test/bench.js",
"lint": "eslint --fix bin/marked .",
"build": "uglifyjs lib/marked.js -cm --comments /Copyright/ -o marked.min.js",
"preversion": "npm run build && (git diff --quiet || git commit -am 'minify')"

261
test/bench.js vendored Normal file
View File

@ -0,0 +1,261 @@
#!/usr/bin/env node
const path = require('path');
const fs = require('fs');
const htmlDiffer = require('./helpers/html-differ.js');
let marked = require('../');
function load() {
let folder = path.resolve(__dirname, './specs/commonmark');
const files = fs.readdirSync(folder);
return files.reduce((arr, file) => {
if (file.match(/\.json$/)) {
return arr.concat(require(`${folder}/${file}`));
}
return arr;
}, []);
}
function runBench(options) {
options = options || {};
const specs = load();
// Non-GFM, Non-pedantic
marked.setOptions({
gfm: false,
tables: false,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: false
});
if (options.marked) {
marked.setOptions(options.marked);
}
bench('marked', specs, marked);
// GFM
marked.setOptions({
gfm: true,
tables: false,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: false
});
if (options.marked) {
marked.setOptions(options.marked);
}
bench('marked (gfm)', specs, marked);
// Pedantic
marked.setOptions({
gfm: false,
tables: false,
breaks: false,
pedantic: true,
sanitize: false,
smartLists: false
});
if (options.marked) {
marked.setOptions(options.marked);
}
bench('marked (pedantic)', specs, marked);
try {
bench('commonmark', specs, (() => {
const commonmark = require('commonmark');
const parser = new commonmark.Parser();
const writer = new commonmark.HtmlRenderer();
return function (text) {
return writer.render(parser.parse(text));
};
})());
} catch (e) {
console.error('Could not bench commonmark. (Error: %s)', e.message);
}
try {
bench('markdown-it', specs, (() => {
const MarkdownIt = require('markdown-it');
const md = new MarkdownIt();
return md.render.bind(md);
})());
} catch (e) {
console.error('Could not bench markdown-it. (Error: %s)', e.message);
}
try {
bench('markdown.js', specs, (() => {
const md = require('markdown').markdown;
return md.toHTML.bind(md);
})());
} catch (e) {
console.error('Could not bench markdown.js. (Error: %s)', e.message);
}
}
function bench(name, specs, engine) {
const before = process.hrtime();
for (let i = 0; i < 1e3; i++) {
for (const spec of specs) {
engine(spec.markdown);
}
}
const elapsed = process.hrtime(before);
const ms = prettyElapsedTime(elapsed).toFixed();
const results = [];
for (const spec of specs) {
results.push({
expected: spec.html,
actual: engine(spec.markdown)
});
}
const correct = results.reduce((num, result) => num + (htmlDiffer.isEqual(result.expected, result.actual) ? 1 : 0), 0);
const percent = (correct / results.length * 100).toFixed(2);
console.log('%s completed in %sms and passed %s%', name, ms, percent);
}
/**
* A simple one-time benchmark
*/
function time(options) {
options = options || {};
const specs = load();
if (options.marked) {
marked.setOptions(options.marked);
}
bench('marked', specs, marked);
}
/**
* Argument Parsing
*/
function parseArg(argv) {
argv = argv.slice(2);
const options = {};
const orphans = [];
function getarg() {
let arg = argv.shift();
if (arg.indexOf('--') === 0) {
// e.g. --opt
arg = arg.split('=');
if (arg.length > 1) {
// e.g. --opt=val
argv.unshift(arg.slice(1).join('='));
}
arg = arg[0];
} else if (arg[0] === '-') {
if (arg.length > 2) {
// e.g. -abc
argv = arg.substring(1).split('').map(ch => {
return `-${ch}`;
}).concat(argv);
arg = argv.shift();
} else {
// e.g. -a
}
} else {
// e.g. foo
}
return arg;
}
const defaults = marked.getDefaults();
while (argv.length) {
let arg = getarg();
switch (arg) {
case '-t':
case '--time':
options.time = true;
break;
case '-m':
case '--minified':
options.minified = true;
break;
default:
if (arg.indexOf('--') === 0) {
const opt = camelize(arg.replace(/^--(no-)?/, ''));
if (!defaults.hasOwnProperty(opt)) {
continue;
}
options.marked = options.marked || {};
if (arg.indexOf('--no-') === 0) {
options.marked[opt] = typeof defaults[opt] !== 'boolean'
? null
: false;
} else {
options.marked[opt] = typeof defaults[opt] !== 'boolean'
? argv.shift()
: true;
}
} else {
orphans.push(arg);
}
break;
}
}
if (orphans.length > 0) {
console.error();
console.error('The following arguments are not used:');
orphans.forEach(arg => console.error(` ${arg}`));
console.error();
}
return options;
}
/**
* Helpers
*/
function camelize(text) {
return text.replace(/(\w)-(\w)/g, (_, a, b) => a + b.toUpperCase());
}
/**
* Main
*/
function main(argv) {
const opt = parseArg(argv);
if (opt.minified) {
marked = require('../marked.min.js');
}
if (opt.time) {
time(opt);
} else {
runBench(opt);
}
}
/**
* returns time to millisecond granularity
*/
function prettyElapsedTime(hrtimeElapsed) {
const seconds = hrtimeElapsed[0];
const frac = Math.round(hrtimeElapsed[1] / 1e3) / 1e3;
return seconds * 1e3 + frac;
}
if (!module.parent) {
process.title = 'marked bench';
main(process.argv.slice());
} else {
exports = main;
exports.main = main;
exports.time = time;
exports.runBench = runBench;
exports.load = load;
exports.bench = bench;
module.exports = exports;
}