Skip to content

Commit

Permalink
adds benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
rsms committed Oct 16, 2020
1 parent 96d9547 commit 3e65f82
Show file tree
Hide file tree
Showing 40 changed files with 12,549 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
**/.DS_Store
/build
/node_modules
/test/spec/spec.html
*.sublime*
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2019 Rasmus Andersson <https://rsms.me/>
Copyright (c) 2019-2020 Rasmus Andersson <https://rsms.me/>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
53 changes: 46 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,30 @@ Based on [md4c](http://github.com/mity/md4c)

## Examples

In Nodejs
In NodeJS, single file with embedded compressed WASM

```js
const markdown = require("./dist/markdown.node.js")
console.log(markdown.parse("# hello\n*world*"))
```

ES module
ES module, WASM loaded async from separate file

```js
import * as markdown from "./dist/markdown.es"
import * as markdown from "./dist/markdown.es.js"
await markdown.ready
console.log(markdown.parse("# hello\n*world*"))
```

Separately loded wasm module (useful in web browsers)
In web browser, WASM loaded async from separate file

```js
require("./dist/markdown").ready.then(markdown => {
```html
<script src="markdown.js"></script>
<script>
window["markdown"].ready.then(markdown => {
console.log(markdown.parse("# hello\n*world*"))
})
</script>
```


Expand All @@ -42,6 +46,41 @@ npm install markdown-wasm
```



## Benchmarks

The [`test/benchmark`](test/benchmark) directory contain a benchmark suite which you can
run yourself. It tests a few popular markdown parser-renderers by parsing & rendering a bunch
of different sample markdown files.

The following results were samples on a 2.9 GHz MacBook running macOS 10.15, NodeJS v14.11.0


#### Average ops/second

Ops/second represents how many times a library is able to parse markdown and render HTML
during a second, on average across all sample files.

![](test/benchmark/results/avg-ops-per-sec.svg)


#### Average throughput

Throughput is the average amount of markdown data processed during a second while both parsing
and rendering to HTML. The statistics does not include HTML generated but only bytes of markdown
source text parsed.

![](test/benchmark/results/avg-throughput.svg)


#### Min–max parse time

This graph shows the spread between the fastest and slowest parse-and-render operations
for each library. Lower numbers are better.

![](test/benchmark/results/minmax-parse-time.svg)


## API

```ts
Expand Down Expand Up @@ -114,7 +153,7 @@ npm install
npx wasmc
```

Build debug version of markdown-es into ./build/debug and watch source files:
Build debug version of markdown into ./build/debug and watch source files:

```
npx wasmc -g -w
Expand Down
2 changes: 2 additions & 0 deletions test/benchmark/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
/results/*.csv
12 changes: 12 additions & 0 deletions test/benchmark/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Markdown-wasm benchmarks

This directory contains a benchmark suite.
You'll need nodejs and npm installed.

1. `npm install`
2. `npm run bench`

Running the benchmarks takes a while since in order to be accurate each parse-and-render
operation is performed synchronously on a single CPU thread.

Results are written to the `results` directory; `bench.csv` along with SVG graphs.
89 changes: 89 additions & 0 deletions test/benchmark/bench.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env node
const Benchmark = require('benchmark').Benchmark
const fs = require('fs')
const Path = require('path')

const commonmark = require('commonmark')
const Showdown = require('showdown')
const marked = require('marked')
const markdownit = require('markdown-it')('commonmark')
const markdown_wasm = require('../../dist/markdown.node.js')

// setup markdownit
// disable expensive IDNa links encoding:
const markdownit_encode = markdownit.utils.lib.mdurl.encode;
markdownit.normalizeLink = function(url) { return markdownit_encode(url); };
markdownit.normalizeLinkText = function(str) { return str; };

// setup showdown
var showdown = new Showdown.Converter()

// setup commonmark
var parser = new commonmark.Parser()
var renderer = new commonmark.HtmlRenderer()

// parse CLI input
let filename = process.argv[2]
if (!filename) {
console.error(`usage: bench.js <markdown-file>`)
console.error(`usage: bench.js <dir-of-markdown-files>`)
process.exit(1)
}

// print CSV header
console.log(csv(["library","file","ops/sec","filesize"]))

// run tests on all files in a directory or a single file
let st = fs.statSync(filename)
if (st.isDirectory()) {
process.chdir(filename)
for (let fn of fs.readdirSync(".")) {
benchmarkFile(fn)
}
} else {
benchmarkFile(filename)
}

// Benchmark.options.maxTime = 10

function csv(values) {
return values.map(s => String(s).replace(/,/g,"\\,")).join(",")
}

function benchmarkFile(benchfile) {

var contents = fs.readFileSync(benchfile, 'utf8');
var contentsBuffer = fs.readFileSync(benchfile);

let csvLinePrefix = `${benchfile.replace(/,/g,"\\,")},${contentsBuffer.length},`

new Benchmark.Suite({
onCycle(ev) {
let b = ev.target
// console.log("cycle", b)
console.log(csv([b.name, benchfile, b.hz, contentsBuffer.length]))
},
// onComplete(ev) {
// let b = ev.target
// console.log("onComplete", {ev}, b.stats, b.times)
// }
}).add('commonmark', function() {
renderer.render(parser.parse(contents));
})
.add('showdown', function() {
showdown.makeHtml(contents);
})
.add('marked', function() {
marked(contents);
})
.add('markdown-it', function() {
markdownit.render(contents);
})
.add('markdown-wasm/string', function() {
markdown_wasm.parse(contents);
})
.add('markdown-wasm/bytes', function() {
markdown_wasm.parse(contentsBuffer, {asMemoryView:true});
})
.run();
}
Loading

0 comments on commit 3e65f82

Please sign in to comment.