diff --git a/README.md b/README.md index 521ed74..b2f3312 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ Go library for the [TOML](https://toml.io/en/) format. This library supports [TOML v1.0.0](https://toml.io/en/v1.0.0). - ## Development status This is the upcoming major version of go-toml. It is currently in active @@ -20,14 +19,12 @@ encouraged to try out this version. [💬 Anything else](https://github.com/pelletier/go-toml/discussions) - ## Documentation Full API, examples, and implementation notes are available in the Go documentation. [![Go Reference](https://pkg.go.dev/badge/github.com/pelletier/go-toml/v2.svg)](https://pkg.go.dev/github.com/pelletier/go-toml/v2) - ## Import ```go @@ -44,7 +41,7 @@ standard library's `encoding/json`. ### Performance While go-toml favors usability, it is written with performance in mind. Most -operations should not be shockingly slow. +operations should not be shockingly slow. See [benchmarks](#benchmarks). ### Strict mode @@ -150,6 +147,43 @@ fmt.Println(string(b)) [marshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Marshal +## Benchmarks + +Execution time speedup compared to other Go TOML libraries: + + + + + + + + + + +
Benchmarkgo-toml v1BurntSushi/toml
HugoFrontMatter2.6x2.2x
ReferenceFile/map2.8x3.0x
ReferenceFile/struct5.4x6.2x
+
See more +

The table above has the results of the most common use-cases. The table +below contains the results of all benchmarks, including unrealistic ones. is +provided for completeness.

+ + + + + + + + + + + + + + + +
Benchmarkgo-toml v1BurntSushi/toml
UnmarshalSimple/map3.8x2.4x
UnmarshalSimple/struct5.4x3.1x
UnmarshalDataset/example2.8x2.0x
UnmarshalDataset/code1.8x2.2x
UnmarshalDataset/twitter2.5x1.8x
UnmarshalDataset/citm_catalog1.9x1.2x
UnmarshalDataset/config3.0x2.5x
[Geo mean]3.0x2.4x
+

This table can be generated with ./ci.sh benchmark -a -html.

+
+ ## Migrating from v1 This section describes the differences between v1 and v2, with some pointers on @@ -191,7 +225,7 @@ d := doc{ } data := ` -[A] +[A] B = "After" ` @@ -252,7 +286,6 @@ This method was not widely used, poorly defined, and added a lot of complexity. A similar effect can be achieved by implementing the `encoding.TextUnmarshaler` interface and use strings. - #### Support for `default` struct tag has been dropped This feature adds complexity and a poorly defined API for an effect that can be @@ -311,7 +344,6 @@ manually sort the fields alphabetically in the struct definition. V1 automatically indents content of tables by default. V2 does not. However the same behavior can be obtained using [`Encoder.SetIndentTables`][sit]. For example: - ```go data := map[string]interface{}{ "table": map[string]string{ @@ -333,15 +365,15 @@ fmt.Println("v2 Encoder:\n" + string(buf.Bytes())) // Output: // v1: -// +// // [table] // key = "value" -// +// // v2: // [table] // key = 'value' -// -// +// +// // v2 Encoder: // [table] // key = 'value' diff --git a/ci.sh b/ci.sh index d7e10cd..22cda0a 100755 --- a/ci.sh +++ b/ci.sh @@ -42,6 +42,9 @@ benchmark [OPTIONS...] [BRANCH] -a Compare benchmarks of HEAD against go-toml v1 and BurntSushi/toml. + -html When used with -a, emits the output as HTML, ready to be + embedded in the README. + coverage [OPTIONS...] [BRANCH] Generates code coverage. @@ -150,16 +153,78 @@ bench() { fi } +fmktemp() { + if mktemp --version|grep GNU >/dev/null; then + mktemp --suffix=-$1; + else + mktemp -t $1; + fi +} + +benchstathtml() { +python3 - $1 <<'EOF' +import sys + +lines = [] +stop = False + +with open(sys.argv[1]) as f: + for line in f.readlines(): + line = line.strip() + if line == "": + stop = True + if not stop: + lines.append(line.split(',')) + +results = [] +for line in reversed(lines[1:]): + v2 = float(line[1]) + results.append([ + line[0].replace("-32", ""), + "%.1fx" % (float(line[3])/v2), # v1 + "%.1fx" % (float(line[5])/v2), # bs + ]) +# move geomean to the end +results.append(results[0]) +del results[0] + + +def printtable(data): + print(""" + + + + + """) + + for r in data: + print(" ".format(*r)) + + print(""" +
Benchmarkgo-toml v1BurntSushi/toml
{}{}{}
""") + + +fold = 3 +printtable(results[:fold]) +print("
See more") +print('

The table above has the results of the most common use-cases. The table below contains the results of all benchmarks, including unrealistic ones. is provided for completeness.

') +printtable(results[fold:]) +print('

This table can be generated with ./ci.sh benchmark -a -html.

') +print("
") + +EOF +} + benchmark() { case "$1" in -d) shift target="${1?Need to provide a target branch argument}" - old=`mktemp --suffix=-${target}` + old=`fmktemp ${target}` bench "${target}" "${old}" - new=`mktemp --suffix=-HEAD` + new=`fmktemp HEAD` bench HEAD "${new}" benchstat "${old}" "${new}" @@ -168,18 +233,24 @@ benchmark() { -a) shift - v2stats=`mktemp -t go-toml-v2` + v2stats=`fmktemp go-toml-v2` bench HEAD "${v2stats}" "github.com/pelletier/go-toml/v2" - v1stats=`mktemp -t go-toml-v1` + v1stats=`fmktemp go-toml-v1` bench HEAD "${v1stats}" "github.com/pelletier/go-toml" - bsstats=`mktemp -t bs-toml` + bsstats=`fmktemp bs-toml` bench HEAD "${bsstats}" "github.com/BurntSushi/toml" cp "${v2stats}" go-toml-v2.txt cp "${v1stats}" go-toml-v1.txt cp "${bsstats}" bs-toml.txt - benchstat -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt + if [ "$1" = "-html" ]; then + tmpcsv=`fmktemp csv` + benchstat -csv -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt > $tmpcsv + benchstathtml $tmpcsv + else + benchstat -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt + fi rm -f go-toml-v2.txt go-toml-v1.txt bs-toml.txt return $?