Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
ld
go-ld-prime
Commits
259c1f45
Commit
259c1f45
authored
Feb 29, 2020
by
Eric Myhre
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'traversal-benchmarks'
parents
61ebf6e2
55eebc40
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
342 additions
and
61 deletions
+342
-61
_rsrch/nodesolution/codec/marshal.go
_rsrch/nodesolution/codec/marshal.go
+17
-13
_rsrch/nodesolution/node/basic/map_test.go
_rsrch/nodesolution/node/basic/map_test.go
+12
-6
_rsrch/nodesolution/node/mixins/tests/marshalBenchmarks.go
_rsrch/nodesolution/node/mixins/tests/marshalBenchmarks.go
+29
-2
_rsrch/nodesolution/node/mixins/tests/unmarshalBenchmarks.go
_rsrch/nodesolution/node/mixins/tests/unmarshalBenchmarks.go
+31
-1
_rsrch/nodesolution/node/mixins/tests/util.go
_rsrch/nodesolution/node/mixins/tests/util.go
+17
-0
impl/free/bench_test.go
impl/free/bench_test.go
+15
-6
tests/HACKME.md
tests/HACKME.md
+68
-0
tests/corpus/corpus.go
tests/corpus/corpus.go
+7
-0
tests/corpus/corpus_test.go
tests/corpus/corpus_test.go
+3
-0
tests/marshalBenchmarks.go
tests/marshalBenchmarks.go
+41
-9
tests/traversalBenchmarks.go
tests/traversalBenchmarks.go
+36
-20
tests/unmarshalBenchmarks.go
tests/unmarshalBenchmarks.go
+40
-4
tests/util.go
tests/util.go
+26
-0
No files found.
_rsrch/nodesolution/codec/marshal.go
View file @
259c1f45
...
...
@@ -21,18 +21,22 @@ import (
// implementation and need to be encoded in a schemafree way.)
func
Marshal
(
n
ipld
.
Node
,
sink
shared
.
TokenSink
)
error
{
var
tk
tok
.
Token
return
marshal
(
n
,
&
tk
,
sink
)
}
func
marshal
(
n
ipld
.
Node
,
tk
*
tok
.
Token
,
sink
shared
.
TokenSink
)
error
{
switch
n
.
ReprKind
()
{
case
ipld
.
ReprKind_Invalid
:
return
fmt
.
Errorf
(
"cannot traverse a node that is undefined"
)
case
ipld
.
ReprKind_Null
:
tk
.
Type
=
tok
.
TNull
_
,
err
:=
sink
.
Step
(
&
tk
)
_
,
err
:=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_Map
:
// Emit start of map.
tk
.
Type
=
tok
.
TMapOpen
tk
.
Length
=
n
.
Length
()
if
_
,
err
:=
sink
.
Step
(
&
tk
);
err
!=
nil
{
if
_
,
err
:=
sink
.
Step
(
tk
);
err
!=
nil
{
return
err
}
// Emit map contents (and recurse).
...
...
@@ -46,23 +50,23 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
if
err
!=
nil
{
return
err
}
if
_
,
err
:=
sink
.
Step
(
&
tk
);
err
!=
nil
{
if
_
,
err
:=
sink
.
Step
(
tk
);
err
!=
nil
{
return
err
}
if
err
:=
M
arshal
(
v
,
sink
);
err
!=
nil
{
if
err
:=
m
arshal
(
v
,
tk
,
sink
);
err
!=
nil
{
return
err
}
}
// Emit map close.
tk
.
Type
=
tok
.
TMapClose
_
,
err
:=
sink
.
Step
(
&
tk
)
_
,
err
:=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_List
:
// Emit start of list.
tk
.
Type
=
tok
.
TArrOpen
l
:=
n
.
Length
()
tk
.
Length
=
l
if
_
,
err
:=
sink
.
Step
(
&
tk
);
err
!=
nil
{
if
_
,
err
:=
sink
.
Step
(
tk
);
err
!=
nil
{
return
err
}
// Emit list contents (and recurse).
...
...
@@ -71,13 +75,13 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
if
err
!=
nil
{
return
err
}
if
err
:=
M
arshal
(
v
,
sink
);
err
!=
nil
{
if
err
:=
m
arshal
(
v
,
tk
,
sink
);
err
!=
nil
{
return
err
}
}
// Emit list close.
tk
.
Type
=
tok
.
TArrClose
_
,
err
:=
sink
.
Step
(
&
tk
)
_
,
err
:=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_Bool
:
v
,
err
:=
n
.
AsBool
()
...
...
@@ -86,7 +90,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk
.
Type
=
tok
.
TBool
tk
.
Bool
=
v
_
,
err
=
sink
.
Step
(
&
tk
)
_
,
err
=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_Int
:
v
,
err
:=
n
.
AsInt
()
...
...
@@ -95,7 +99,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk
.
Type
=
tok
.
TInt
tk
.
Int
=
int64
(
v
)
_
,
err
=
sink
.
Step
(
&
tk
)
_
,
err
=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_Float
:
v
,
err
:=
n
.
AsFloat
()
...
...
@@ -104,7 +108,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk
.
Type
=
tok
.
TFloat64
tk
.
Float64
=
v
_
,
err
=
sink
.
Step
(
&
tk
)
_
,
err
=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_String
:
v
,
err
:=
n
.
AsString
()
...
...
@@ -113,7 +117,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk
.
Type
=
tok
.
TString
tk
.
Str
=
v
_
,
err
=
sink
.
Step
(
&
tk
)
_
,
err
=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_Bytes
:
v
,
err
:=
n
.
AsBytes
()
...
...
@@ -122,7 +126,7 @@ func Marshal(n ipld.Node, sink shared.TokenSink) error {
}
tk
.
Type
=
tok
.
TBytes
tk
.
Bytes
=
v
_
,
err
=
sink
.
Step
(
&
tk
)
_
,
err
=
sink
.
Step
(
tk
)
return
err
case
ipld
.
ReprKind_Link
:
return
fmt
.
Errorf
(
"link emission not supported by this codec without a schema! (maybe you want dag-cbor or dag-json)"
)
...
...
_rsrch/nodesolution/node/basic/map_test.go
View file @
259c1f45
...
...
@@ -31,13 +31,19 @@ func BenchmarkMapStrInt_25n_Iteration(b *testing.B) {
tests
.
SpecBenchmarkMapStrInt_25n_Iteration
(
b
,
Style__Map
{})
}
func
BenchmarkUnmarshalMapStrInt_3n
(
b
*
testing
.
B
)
{
tests
.
SpecBenchmarkUnmarshalMapStrInt_3n
(
b
,
Style__Map
{})
func
BenchmarkSpec_Marshal_Map3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Marshal_Map3StrInt
(
b
,
Style__Map
{})
}
func
BenchmarkSpec_Marshal_Map3StrInt_CodecNull
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Marshal_Map3StrInt_CodecNull
(
b
,
Style__Map
{})
}
func
BenchmarkSpec_Marshal_MapNStrMap3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Marshal_MapNStrMap3StrInt
(
b
,
Style__Map
{})
}
func
Benchmark
M
arshalMapStrInt
_3n
(
b
*
testing
.
B
)
{
tests
.
Spec
Benchmark
M
arshalMapStrInt
_3n
(
b
,
Style__Map
{})
func
Benchmark
Spec_Unm
arshal
_
Map
3
StrInt
(
b
*
testing
.
B
)
{
tests
.
Benchmark
Spec_Unm
arshal
_
Map
3
StrInt
(
b
,
Style__Map
{})
}
func
Benchmark
MarshalToNull
MapStrInt
_3n
(
b
*
testing
.
B
)
{
tests
.
Spec
Benchmark
MarshalToNull
MapStrInt
_3n
(
b
,
Style__Map
{})
func
Benchmark
Spec_Unmarshal_MapNStr
Map
3
StrInt
(
b
*
testing
.
B
)
{
tests
.
Benchmark
Spec_Unmarshal_MapNStr
Map
3
StrInt
(
b
,
Style__Map
{})
}
_rsrch/nodesolution/node/mixins/tests/marshalBenchmarks.go
View file @
259c1f45
...
...
@@ -2,6 +2,7 @@ package tests
import
(
"bytes"
"fmt"
"testing"
refmtjson
"github.com/polydawn/refmt/json"
...
...
@@ -10,6 +11,7 @@ import (
ipld
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution"
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution/codec"
"github.com/ipld/go-ipld-prime/must"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
...
...
@@ -21,7 +23,7 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
func
Spec
BenchmarkMarshalMapStrInt
_3n
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
func
Benchmark
Spec_
Marshal
_
Map
3
StrInt
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
nb
:=
ns
.
NewBuilder
()
must
.
NotError
(
codec
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
`{"whee":1,"woot":2,"waga":3}`
))))
n
:=
nb
.
Build
()
...
...
@@ -37,7 +39,7 @@ func SpecBenchmarkMarshalMapStrInt_3n(b *testing.B, ns ipld.NodeStyle) {
}
}
func
Spec
BenchmarkMarshal
ToNull
MapStrInt_
3n
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
func
Benchmark
Spec_
Marshal
_
Map
3
StrInt_
CodecNull
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
nb
:=
ns
.
NewBuilder
()
must
.
NotError
(
codec
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
`{"whee":1,"woot":2,"waga":3}`
))))
n
:=
nb
.
Build
()
...
...
@@ -59,3 +61,28 @@ type nullTokenSink struct{}
func
(
nullTokenSink
)
Step
(
_
*
tok
.
Token
)
(
bool
,
error
)
{
return
false
,
nil
}
func
BenchmarkSpec_Marshal_MapNStrMap3StrInt
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
for
_
,
n
:=
range
[]
int
{
0
,
1
,
2
,
4
,
8
,
16
,
32
}
{
b
.
Run
(
fmt
.
Sprintf
(
"n=%d"
,
n
),
func
(
b
*
testing
.
B
)
{
msg
:=
corpus
.
MapNStrMap3StrInt
(
n
)
node
:=
mustNodeFromJsonString
(
ns
.
NewBuilder
(),
msg
)
b
.
ResetTimer
()
var
buf
bytes
.
Buffer
var
err
error
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
buf
=
bytes
.
Buffer
{}
err
=
codec
.
Marshal
(
node
,
refmtjson
.
NewEncoder
(
&
buf
,
refmtjson
.
EncodeOptions
{}))
}
b
.
StopTimer
()
if
err
!=
nil
{
b
.
Fatalf
(
"marshal errored: %s"
,
err
)
}
if
buf
.
String
()
!=
msg
{
b
.
Fatalf
(
"marshal didn't match corpus"
)
}
})
}
}
_rsrch/nodesolution/node/mixins/tests/unmarshalBenchmarks.go
View file @
259c1f45
...
...
@@ -2,12 +2,14 @@ package tests
import
(
"bytes"
"fmt"
"testing"
refmtjson
"github.com/polydawn/refmt/json"
ipld
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution"
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution/codec"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
...
...
@@ -19,7 +21,7 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
func
Spec
BenchmarkUnmarshalMapStrInt
_3n
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
func
Benchmark
Spec_
Unmarshal
_
Map
3
StrInt
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
var
err
error
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
nb
:=
ns
.
NewBuilder
()
...
...
@@ -30,3 +32,31 @@ func SpecBenchmarkUnmarshalMapStrInt_3n(b *testing.B, ns ipld.NodeStyle) {
panic
(
err
)
}
}
func
BenchmarkSpec_Unmarshal_MapNStrMap3StrInt
(
b
*
testing
.
B
,
ns
ipld
.
NodeStyle
)
{
for
_
,
n
:=
range
[]
int
{
0
,
1
,
2
,
4
,
8
,
16
,
32
}
{
b
.
Run
(
fmt
.
Sprintf
(
"n=%d"
,
n
),
func
(
b
*
testing
.
B
)
{
msg
:=
corpus
.
MapNStrMap3StrInt
(
n
)
b
.
ResetTimer
()
var
node
ipld
.
Node
var
err
error
nb
:=
ns
.
NewBuilder
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
err
=
codec
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
msg
)))
node
=
nb
.
Build
()
nb
.
Reset
()
}
b
.
StopTimer
()
if
err
!=
nil
{
b
.
Fatalf
(
"unmarshal errored: %s"
,
err
)
}
var
buf
bytes
.
Buffer
codec
.
Marshal
(
node
,
refmtjson
.
NewEncoder
(
&
buf
,
refmtjson
.
EncodeOptions
{}))
if
buf
.
String
()
!=
msg
{
b
.
Fatalf
(
"remarshal didn't match corpus"
)
}
})
}
}
_rsrch/nodesolution/node/mixins/tests/util.go
View file @
259c1f45
package
tests
import
(
"bytes"
refmtjson
"github.com/polydawn/refmt/json"
ipld
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution"
"github.com/ipld/go-ipld-prime/_rsrch/nodesolution/codec"
)
// various benchmarks assign their final result here,
// in order to defuse the possibility of their work being elided.
var
sink
interface
{}
func
mustNodeFromJsonString
(
nb
ipld
.
NodeBuilder
,
str
string
)
ipld
.
Node
{
err
:=
codec
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
str
)))
if
err
!=
nil
{
panic
(
err
)
}
return
nb
.
Build
()
}
impl/free/bench_test.go
View file @
259c1f45
...
...
@@ -86,18 +86,27 @@ func BenchmarkMap25nGenericMapIterationSimpleKeys(b *testing.B) {
// benchmarks covering encoding -->
func
BenchmarkUnmarshalMapStrInt_3n
(
b
*
testing
.
B
)
{
tests
.
SpecBenchmarkUnmarshalMapStrInt_3n
(
b
,
NodeBuilder
())
func
BenchmarkSpec_Marshal_Map3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Marshal_Map3StrInt
(
b
,
NodeBuilder
())
}
func
BenchmarkSpec_Marshal_MapNStrMap3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Marshal_MapNStrMap3StrInt
(
b
,
NodeBuilder
())
}
func
BenchmarkMarshalMapStrInt_3n
(
b
*
testing
.
B
)
{
tests
.
SpecBenchmarkMarshalMapStrInt_3n
(
b
,
NodeBuilder
())
func
BenchmarkSpec_Unmarshal_Map3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Unmarshal_Map3StrInt
(
b
,
NodeBuilder
())
}
func
BenchmarkSpec_Unmarshal_MapNStrMap3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Unmarshal_MapNStrMap3StrInt
(
b
,
NodeBuilder
())
}
// benchmarks covering traversal -->
func
BenchmarkWalkMapStrInt_3n
(
b
*
testing
.
B
)
{
tests
.
SpecBenchmarkWalkMapStrInt_3n
(
b
,
NodeBuilder
())
func
BenchmarkSpec_Walk_Map3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Walk_Map3StrInt
(
b
,
NodeBuilder
())
}
func
BenchmarkSpec_Walk_MapNStrMap3StrInt
(
b
*
testing
.
B
)
{
tests
.
BenchmarkSpec_Walk_MapNStrMap3StrInt
(
b
,
NodeBuilder
())
}
// copy of helper functions from must package, because import cycles, sigh -->
...
...
tests/HACKME.md
0 → 100644
View file @
259c1f45
HACKME
======
This package is for reusable tests and benchmarks.
These test and benchmark functions work over the Node and NodeBuilder interfaces,
so they should work to test compatibility and compare performance of various implementations of Node.
This is easier said than done.
Naming conventions
------------------
### name prefix
All reusable test functions start with the name prefix
`TestSpec_`
.
All reusable benchmarks start with the name prefix
`BenchmarkSpec_`
.
The "Test" and "Benchmark" prefixes are as per the requirements of the
golang standard
`testing`
package. They take
`*testing.T`
and
`*testing.B`
arguments respectively. They also take at least one interface argument
which is how you give your Node implementation to the test spec.
The word "Spec" reflects on the fact that these are reusable/standardized tests.
We recommend you copy-paste these method names outright into the package of your Node implementation.
It's not necessary, but it's nice for consistency.
(In the future, there may be tooling to help make automated comparisons
of different Node implementation's relative performance; this would
necessarily rely on consistent names across packages.)
If your Node implementation package has
*more*
tests and benchmarks that
*are not*
from this reusable set, that's great -- but don't use the "Spec"
word as a segment of their name; it'll make processing bulk output easier.
### full pattern
The full pattern is:
`BenchmarkSpec_{Application}_{FixtureCohort}/codec={codec}/n={size}`
-
`{Application}`
means what feature or big-picture behavior we're testing.
Examples include "Marshal", "Unmarshal", "Walk", etc.
-
`{FixtureCohort}`
means... well, see the names from the 'corpus' subpackage;
it should be literally one of those strings.
-
`n={size}`
will be present for variable-scale benchmarks.
You'll have to consider the Application and FixtureCohort to understand the
context of what part of the data is being varied in size, though.
-
`codec={codec}`
is an example of extra info that might exist for some applications.
For example, it might include "json" and "cbor" for "Marshal" and "Unmarshal",
but will not be seen at all in other applications like "Walk".
The parts after the slash are those which are handled internally.
For those, you call the
`BenchmarkSpec_*`
function name (stopping before the first slash),
and that function will call
`b.Run`
to make sub-tests for all the variations.
For example, when you call
`BenchmarkSpec_Walk_MapNStrMap3StrInt`
, that one call
will result in a suite of tests for various sizes, each of which will be denoted
in the output by
`BenchmarkSpec_Walk_MapNStrMap3StrInt/n=1`
, then
`.../n=2`
, etc.
### variable scale benchmarks
Some corpuses have fixed sizes. Some are variable.
With fixed-size corpuses, you'll see an integer in the "FixtureCohort" name.
For variable-size corpuses, you'll see the letter "N" in place of an integer.
See the docs in the 'corpus' subpackage for more discussion of this.
tests/corpus/corpus.go
View file @
259c1f45
...
...
@@ -49,3 +49,10 @@ func MapNStrInt(n int) string {
return
fmt
.
Sprintf
(
`"k%d":%d`
,
i
,
i
)
})
+
`}`
}
func
MapNStrMap3StrInt
(
n
int
)
string
{
return
`{`
+
ents
(
n
,
func
(
i
int
)
string
{
return
fmt
.
Sprintf
(
`"k%d":`
,
i
)
+
fmt
.
Sprintf
(
`{"whee":%d,"woot":%d,"waga":%d}`
,
i
*
3
+
1
,
i
*
3
+
2
,
i
*
3
+
3
)
})
+
`}`
}
tests/corpus/corpus_test.go
View file @
259c1f45
...
...
@@ -16,4 +16,7 @@ func TestCorpusValidity(t *testing.T) {
must
.
True
(
json
.
Valid
([]
byte
(
MapNStrInt
(
0
))))
must
.
True
(
json
.
Valid
([]
byte
(
MapNStrInt
(
1
))))
must
.
True
(
json
.
Valid
([]
byte
(
MapNStrInt
(
2
))))
must
.
True
(
json
.
Valid
([]
byte
(
MapNStrMap3StrInt
(
0
))))
must
.
True
(
json
.
Valid
([]
byte
(
MapNStrMap3StrInt
(
1
))))
must
.
True
(
json
.
Valid
([]
byte
(
MapNStrMap3StrInt
(
2
))))
}
tests/marshalBenchmarks.go
View file @
259c1f45
...
...
@@ -2,12 +2,14 @@ package tests
import
(
"bytes"
"fmt"
"testing"
refmtjson
"github.com/polydawn/refmt/json"
ipld
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
...
...
@@ -19,18 +21,48 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
func
SpecBenchmarkMarshalMapStrInt_3n
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
n
,
err
:=
encoding
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
`{"whee":1,"woot":2,"waga":3}`
)))
if
err
!=
nil
{
panic
(
err
)
}
func
BenchmarkSpec_Marshal_Map3StrInt
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
msg
:=
corpus
.
Map3StrInt
()
node
:=
mustNodeFromJsonString
(
nb
,
msg
)
b
.
ResetTimer
()
var
buf
bytes
.
Buffer
var
err
error
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
var
buf
bytes
.
Buffer
err
=
encoding
.
Marshal
(
n
,
refmtjson
.
NewEncoder
(
&
buf
,
refmtjson
.
EncodeOptions
{}))
sink
=
buf
buf
=
bytes
.
Buffer
{}
err
=
encoding
.
Marshal
(
node
,
refmtjson
.
NewEncoder
(
&
buf
,
refmtjson
.
EncodeOptions
{}))
}
b
.
StopTimer
()
if
err
!=
nil
{
panic
(
err
)
b
.
Fatalf
(
"marshal errored: %s"
,
err
)
}
if
buf
.
String
()
!=
msg
{
b
.
Fatalf
(
"marshal didn't match corpus"
)
}
}
func
BenchmarkSpec_Marshal_MapNStrMap3StrInt
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
for
_
,
n
:=
range
[]
int
{
0
,
1
,
2
,
4
,
8
,
16
,
32
}
{
b
.
Run
(
fmt
.
Sprintf
(
"n=%d"
,
n
),
func
(
b
*
testing
.
B
)
{
msg
:=
corpus
.
MapNStrMap3StrInt
(
n
)
node
:=
mustNodeFromJsonString
(
nb
,
msg
)
b
.
ResetTimer
()
var
buf
bytes
.
Buffer
var
err
error
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
buf
=
bytes
.
Buffer
{}
err
=
encoding
.
Marshal
(
node
,
refmtjson
.
NewEncoder
(
&
buf
,
refmtjson
.
EncodeOptions
{}))
}
b
.
StopTimer
()
if
err
!=
nil
{
b
.
Fatalf
(
"marshal errored: %s"
,
err
)
}
if
buf
.
String
()
!=
msg
{
b
.
Fatalf
(
"marshal didn't match corpus"
)
}
})
}
}
tests/traversalBenchmarks.go
View file @
259c1f45
package
tests
import
(
"
bytes
"
"
fmt
"
"testing"
refmtjson
"github.com/polydawn/refmt/json"
ipld
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/tests/corpus"
"github.com/ipld/go-ipld-prime/traversal"
"github.com/ipld/go-ipld-prime/traversal/selector"
)
func
SpecBenchmarkWalkMapStrInt_3n
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
n
,
err
:=
encoding
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
corpus
.
Map3StrInt
())))
if
err
!=
nil
{
panic
(
err
)
}
seldefn
,
err
:=
encoding
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
`{"a":{">":{".":{}}}}`
)))
if
err
!=
nil
{
panic
(
err
)
}
sel
,
err
:=
selector
.
ParseSelector
(
seldefn
)
if
err
!=
nil
{
panic
(
err
)
}
func
BenchmarkSpec_Walk_Map3StrInt
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
node
:=
mustNodeFromJsonString
(
nb
,
corpus
.
Map3StrInt
())
sel
:=
mustSelectorFromJsonString
(
nb
,
`{"a":{">":{".":{}}}}`
)
b
.
ResetTimer
()
var
visitCountSanityCheck
int
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
traversal
.
WalkMatching
(
n
,
sel
,
func
(
tp
traversal
.
Progress
,
n
ipld
.
Node
)
error
{
return
nil
// no need to do anything here; just care about exercising the walk internals.
visitCountSanityCheck
=
0
traversal
.
WalkMatching
(
node
,
sel
,
func
(
tp
traversal
.
Progress
,
n
ipld
.
Node
)
error
{
visitCountSanityCheck
++
// this sanity check is sufficiently cheap to be worth it
return
nil
// no need to do anything here; just care about exercising the walk internals.
})
}
if
visitCountSanityCheck
!=
3
{
b
.
Fatalf
(
"visitCountSanityCheck should be 3, got %d"
,
visitCountSanityCheck
)
}
}
func
BenchmarkSpec_Walk_MapNStrMap3StrInt
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
sel
:=
mustSelectorFromJsonString
(
nb
,
`{"a":{">":{"a":{">":{".":{}}}}}}`
)
for
_
,
n
:=
range
[]
int
{
0
,
1
,
2
,
4
,
8
,
16
,
32
}
{
b
.
Run
(
fmt
.
Sprintf
(
"n=%d"
,
n
),
func
(
b
*
testing
.
B
)
{
node
:=
mustNodeFromJsonString
(
nb
,
corpus
.
MapNStrMap3StrInt
(
n
))
b
.
ResetTimer
()
var
visitCountSanityCheck
int
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
visitCountSanityCheck
=
0
traversal
.
WalkMatching
(
node
,
sel
,
func
(
tp
traversal
.
Progress
,
n
ipld
.
Node
)
error
{
visitCountSanityCheck
++
// this sanity check is sufficiently cheap to be worth it
return
nil
// no need to do anything here; just care about exercising the walk internals.
})
}
if
visitCountSanityCheck
!=
3
*
n
{
b
.
Fatalf
(
"visitCountSanityCheck should be %d, got %d"
,
n
*
3
,
visitCountSanityCheck
)
}
})
}
}
tests/unmarshalBenchmarks.go
View file @
259c1f45
...
...
@@ -2,12 +2,14 @@ package tests
import
(
"bytes"
"fmt"
"testing"
refmtjson
"github.com/polydawn/refmt/json"
ipld
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/tests/corpus"
)
// All of the marshalling and unmarshalling benchmark specs use JSON.
...
...
@@ -19,14 +21,48 @@ import (
// - we can make direct comparisons to the standard library json marshalling
// and unmarshalling, thus having a back-of-the-envelope baseline to compare.
var
sink
interface
{}
func
BenchmarkSpec_Unmarshal_Map3StrInt
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
msg
:=
corpus
.
Map3StrInt
()
b
.
ResetTimer
()
func
SpecBenchmarkUnmarshalMapStrInt_3n
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
var
node
ipld
.
Node
var
err
error
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
sink
,
err
=
encoding
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
`{"whee":1,"woot":2,"waga":3}`
)))
node
,
err
=
encoding
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
msg
)))
}
b
.
StopTimer
()
if
err
!=
nil
{
panic
(
err
)
b
.
Fatalf
(
"unmarshal errored: %s"
,
err
)
}
var
buf
bytes
.
Buffer
encoding
.
Marshal
(
node
,
refmtjson
.
NewEncoder
(
&
buf
,
refmtjson
.
EncodeOptions
{}))
if
buf
.
String
()
!=
msg
{
b
.
Fatalf
(
"remarshal didn't match corpus"
)
}
}
func
BenchmarkSpec_Unmarshal_MapNStrMap3StrInt
(
b
*
testing
.
B
,
nb
ipld
.
NodeBuilder
)
{
for
_
,
n
:=
range
[]
int
{
0
,
1
,
2
,
4
,
8
,
16
,
32
}
{
b
.
Run
(
fmt
.
Sprintf
(
"n=%d"
,
n
),
func
(
b
*
testing
.
B
)
{
msg
:=
corpus
.
MapNStrMap3StrInt
(
n
)
b
.
ResetTimer
()
var
node
ipld
.
Node
var
err
error
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
node
,
err
=
encoding
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
msg
)))
}
b
.
StopTimer
()
if
err
!=
nil
{
b
.
Fatalf
(
"unmarshal errored: %s"
,
err
)
}
var
buf
bytes
.
Buffer
encoding
.
Marshal
(
node
,
refmtjson
.
NewEncoder
(
&
buf
,
refmtjson
.
EncodeOptions
{}))
if
buf
.
String
()
!=
msg
{
b
.
Fatalf
(
"remarshal didn't match corpus"
)
}
})
}
}
tests/util.go
0 → 100644
View file @
259c1f45
package
tests
import
(
"bytes"
refmtjson
"github.com/polydawn/refmt/json"
ipld
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/encoding"
"github.com/ipld/go-ipld-prime/must"
"github.com/ipld/go-ipld-prime/traversal/selector"
)
func
mustNodeFromJsonString
(
nb
ipld
.
NodeBuilder
,
str
string
)
ipld
.
Node
{
return
must
.
Node
(
encoding
.
Unmarshal
(
nb
,
refmtjson
.
NewDecoder
(
bytes
.
NewBufferString
(
str
))))
}
func
mustSelectorFromJsonString
(
nb
ipld
.
NodeBuilder
,
str
string
)
selector
.
Selector
{
// Needing an 'nb' parameter here is sort of off-topic, to be honest.
// Someday the selector package will probably contain codegen'd nodes of its own schema, and we'll use those unconditionally.
// For now... we'll just use whatever node you're already testing, because it oughta work
// (and because it avoids hardcoding any other implementation that might cause import cycle funtimes.).
seldefn
:=
mustNodeFromJsonString
(
nb
,
str
)
sel
,
err
:=
selector
.
ParseSelector
(
seldefn
)
must
.
NotError
(
err
)
return
sel
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment