Add benchmarks, update README

This commit is contained in:
yuin 2019-05-03 13:00:43 +09:00
parent 9b40d12434
commit 56ebc40a6a
8 changed files with 9907 additions and 6 deletions

View file

@ -34,6 +34,21 @@ This behavior sometimes causes problems. If you migrate your markdown text to bl
As mentioned above, CommonMark is too complicated and hard to implement, So Markdown parsers base on CommonMark barely exist.
Features
----------------------
- **Standard compliant.** : goldmark get full compliance with latest CommonMark spec.
- **Extensible.** : Do you want to add a `@username` mention syntax to the markdown?
You can easily do it in goldmark. You can add your AST nodes,
parsers for block level elements, parsers for inline level elements,
transformers for paragraphs, transformers for whole AST structure, and
renderers.
- **Preformance.** : goldmark performs pretty much equally to the cmark
(CommonMark reference implementation written in c).
- **Builtin extensions.** : goldmark ships with common extensions like tables, strikethrough,
task lists, and definition lists.
- **Depends only on standard libraries.**
Usage
----------------------
@ -90,14 +105,18 @@ Parser and Renderer options
### Built-in extensions
- `extension.Table`
- [Gitmark Flavored Markdown: Tables](https://github.github.com/gfm/#tables-extension-)
- `extension.Strikethrough`
- [Gitmark Flavored Markdown: Strikethrough](https://github.github.com/gfm/#strikethrough-extension-)
- `extension.Linkify`
- [Gitmark Flavored Markdown: Autolinks](https://github.github.com/gfm/#autolinks-extension-)
- `extension.TaskList`
- [Gitmark Flavored Markdown: Task list items](https://github.github.com/gfm/#task-list-items-extension-)
- `extension.GFM`
- This extension enables Table, Strikethrough, Linkify and TaskList.
In addition, this extension sets some tags to `parser.FilterTags` .
- `extension.DefinitionList`
- [PHP Markdown Extra Definition lists](https://michelf.ca/projects/php-markdown/extra/#def-list)
- [PHP Markdown Extra Definition: lists](https://michelf.ca/projects/php-markdown/extra/#def-list)
Create extensions
--------------------
@ -122,17 +141,37 @@ Benchmark
--------------------
You can run this benchmark in the `_benchmark` directory.
blackfriday v2 is fastest, but it is not CommonMark compiliant and not an extensible.
### against other golang libraries
blackfriday v2 seems fastest, but it is not CommonMark compiliant so performance of the
blackfriday v2 can not simply be compared with other Commonmark compliant libraries.
Though goldmark builds clean extensible AST structure and get full compliance with
Commonmark, it is resonably fast and less memory consumption.
```
BenchmarkGoldMark-4 200 7176000 ns/op 2482660 B/op 15597 allocs/op
BenchmarkGolangCommonMark-4 200 7874817 ns/op 3053775 B/op 18682 allocs/op
BenchmarkBlackFriday-4 300 5871891 ns/op 3356419 B/op 17481 allocs/op
BenchmarkGoldMark-4 200 6388385 ns/op 2085552 B/op 13856 allocs/op
BenchmarkGolangCommonMark-4 200 7056577 ns/op 2974119 B/op 18828 allocs/op
BenchmarkBlackFriday-4 300 5635122 ns/op 3341668 B/op 20057 allocs/op
```
### against cmark(A CommonMark reference implementation written in c)
```
----------- cmark -----------
file: _data.md
iteration: 50
average: 0.0050112160 sec
go run ./goldmark_benchmark.go
------- goldmark -------
file: _data.md
iteration: 50
average: 0.0064833820 sec
```
As you can see, goldmark performs pretty much equally to the cmark.
Donation
--------------------
BTC: 1NEDSyUmo4SMTDP83JJQSWi1MvQUGGNMZB

1
_benchmark/cmark/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
cmark-master

21
_benchmark/cmark/Makefile Normal file
View file

@ -0,0 +1,21 @@
CMARK_BIN=cmark_benchmark
CMARK_RUN=LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:./cmark-master/build/src ./$(CMARK_BIN)
ifeq ($(OS),Windows_NT)
CMARK_BIN=cmark_benchmark.exe
CMARK_RUN=bash -c "PATH=./cmark-master/build/src:$${PATH} ./$(CMARK_BIN)"
endif
.PHONY: run
run: $(CMARK_BIN)
$(CMARK_RUN)
go run ./goldmark_benchmark.go
./cmark-master/build/src/config.h:
wget -nc -O cmark.zip https://github.com/commonmark/cmark/archive/master.zip
unzip cmark.zip
rm -f cmark.zip
cd cmark-master && make
$(CMARK_BIN): ./cmark-master/build/src/config.h
gcc -I./cmark-master/build/src -I./cmark-master/src cmark_benchmark.c -o $(CMARK_BIN) -L./cmark-master/build/src -lcmark

View file

@ -0,0 +1,91 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
# include <windows.h>
#else
# include <sys/time.h>
# include <sys/resource.h>
#endif
#include "cmark.h"
#ifdef WIN32
double get_time()
{
LARGE_INTEGER t, f;
QueryPerformanceCounter(&t);
QueryPerformanceFrequency(&f);
return (double)t.QuadPart/(double)f.QuadPart;
}
#else
double get_time()
{
struct timeval t;
struct timezone tzp;
gettimeofday(&t, &tzp);
return t.tv_sec + t.tv_usec*1e-6;
}
#endif
int main(int argc, char **argv) {
char *markdown_file;
FILE *fp;
size_t size;
char *buf;
char *html;
double start, sum;
int i, n;
n = argc > 1 ? atoi(argv[1]) : 50;
markdown_file = argc > 2 ? argv[2] : "_data.md";
fp = fopen(markdown_file,"r");
if(fp == NULL){
fprintf(stderr, "can not open %s", markdown_file);
exit(1);
}
if(fseek(fp, 0, SEEK_END) != 0) {
fprintf(stderr, "can not seek %s", markdown_file);
exit(1);
}
if((size = ftell(fp)) < 0) {
fprintf(stderr, "can not get size of %s", markdown_file);
exit(1);
}
if(fseek(fp, 0, SEEK_SET) != 0) {
fprintf(stderr, "can not seek %s", markdown_file);
exit(1);
}
buf = malloc(sizeof(char) * size);
if(buf == NULL) {
fprintf(stderr, "can not allocate memory for %s", markdown_file);
exit(1);
}
if(fread(buf, 1, size, fp) < size) {
fprintf(stderr, "failed to read for %s", markdown_file);
exit(1);
}
fclose(fp);
for(i = 0; i < n; i++) {
start = get_time();
html = cmark_markdown_to_html(buf, size, CMARK_OPT_UNSAFE);
free(html);
sum += get_time() - start;
}
printf("----------- cmark -----------\n");
printf("file: %s\n", markdown_file);
printf("iteration: %d\n", n);
printf("average: %.10f sec\n", sum / (double)n);
free(buf);
return 0;
}

View file

@ -0,0 +1,45 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strconv"
"time"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/renderer/html"
)
func main() {
n := 50
file := "_data.md"
if len(os.Args) > 1 {
n, _ = strconv.Atoi(os.Args[1])
}
if len(os.Args) > 2 {
file = os.Args[2]
}
source, err := ioutil.ReadFile(file)
if err != nil {
panic(err)
}
markdown := goldmark.New(goldmark.WithRendererOptions(html.WithXHTML(), html.WithUnsafe()))
var out bytes.Buffer
markdown.Convert([]byte(""), &out)
sum := time.Duration(0)
for i := 0; i < n; i++ {
start := time.Now()
out.Reset()
if err := markdown.Convert(source, &out); err != nil {
panic(err)
}
sum += time.Since(start)
}
fmt.Printf("------- goldmark -------\n")
fmt.Printf("file: %s\n", file)
fmt.Printf("iteration: %d\n", n)
fmt.Printf("average: %.10f sec\n", float64((int64(sum)/int64(n)))/1000000000.0)
}

9702
_benchmark/go/_data.md Normal file

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,9 @@ func BenchmarkGoldMark(b *testing.B) {
if err != nil {
panic(err)
}
markdown := goldmark.New(goldmark.WithRendererOptions(html.WithXHTML()))
markdown := goldmark.New(
goldmark.WithRendererOptions(html.WithXHTML(), html.WithUnsafe()),
)
var out bytes.Buffer
markdown.Convert([]byte(""), &out)