Add benchmarks for un/serializing model Meta

This commit is contained in:
Daniel 2018-09-03 17:07:23 +02:00
parent f8ff7d143e
commit 307ddd70fd
7 changed files with 1009 additions and 3 deletions

10
database/model/meta.colf Normal file
View file

@ -0,0 +1,10 @@
package model
type course struct {
Created int64
Modified int64
Expires int64
Deleted int64
Secret bool
Cronjewel bool
}

View file

@ -0,0 +1,8 @@
struct Meta {
Created int64
Modified int64
Expires int64
Deleted int64
Secret bool
Cronjewel bool
}

View file

@ -0,0 +1,163 @@
package model
import (
"io"
"time"
"unsafe"
)
var (
_ = unsafe.Sizeof(0)
_ = io.ReadFull
_ = time.Now()
)
// type Meta struct {
// Created int64
// Modified int64
// Expires int64
// Deleted int64
// Secret bool
// Cronjewel bool
// }
func (d *Meta) Size() (s uint64) {
s += 34
return
}
func (d *Meta) Marshal(buf []byte) ([]byte, error) {
size := d.Size()
{
if uint64(cap(buf)) >= size {
buf = buf[:size]
} else {
buf = make([]byte, size)
}
}
i := uint64(0)
{
buf[0+0] = byte(d.Created >> 0)
buf[1+0] = byte(d.Created >> 8)
buf[2+0] = byte(d.Created >> 16)
buf[3+0] = byte(d.Created >> 24)
buf[4+0] = byte(d.Created >> 32)
buf[5+0] = byte(d.Created >> 40)
buf[6+0] = byte(d.Created >> 48)
buf[7+0] = byte(d.Created >> 56)
}
{
buf[0+8] = byte(d.Modified >> 0)
buf[1+8] = byte(d.Modified >> 8)
buf[2+8] = byte(d.Modified >> 16)
buf[3+8] = byte(d.Modified >> 24)
buf[4+8] = byte(d.Modified >> 32)
buf[5+8] = byte(d.Modified >> 40)
buf[6+8] = byte(d.Modified >> 48)
buf[7+8] = byte(d.Modified >> 56)
}
{
buf[0+16] = byte(d.Expires >> 0)
buf[1+16] = byte(d.Expires >> 8)
buf[2+16] = byte(d.Expires >> 16)
buf[3+16] = byte(d.Expires >> 24)
buf[4+16] = byte(d.Expires >> 32)
buf[5+16] = byte(d.Expires >> 40)
buf[6+16] = byte(d.Expires >> 48)
buf[7+16] = byte(d.Expires >> 56)
}
{
buf[0+24] = byte(d.Deleted >> 0)
buf[1+24] = byte(d.Deleted >> 8)
buf[2+24] = byte(d.Deleted >> 16)
buf[3+24] = byte(d.Deleted >> 24)
buf[4+24] = byte(d.Deleted >> 32)
buf[5+24] = byte(d.Deleted >> 40)
buf[6+24] = byte(d.Deleted >> 48)
buf[7+24] = byte(d.Deleted >> 56)
}
{
if d.Secret {
buf[32] = 1
} else {
buf[32] = 0
}
}
{
if d.Cronjewel {
buf[33] = 1
} else {
buf[33] = 0
}
}
return buf[:i+34], nil
}
func (d *Meta) Unmarshal(buf []byte) (uint64, error) {
i := uint64(0)
{
d.Created = 0 | (int64(buf[0+0]) << 0) | (int64(buf[1+0]) << 8) | (int64(buf[2+0]) << 16) | (int64(buf[3+0]) << 24) | (int64(buf[4+0]) << 32) | (int64(buf[5+0]) << 40) | (int64(buf[6+0]) << 48) | (int64(buf[7+0]) << 56)
}
{
d.Modified = 0 | (int64(buf[0+8]) << 0) | (int64(buf[1+8]) << 8) | (int64(buf[2+8]) << 16) | (int64(buf[3+8]) << 24) | (int64(buf[4+8]) << 32) | (int64(buf[5+8]) << 40) | (int64(buf[6+8]) << 48) | (int64(buf[7+8]) << 56)
}
{
d.Expires = 0 | (int64(buf[0+16]) << 0) | (int64(buf[1+16]) << 8) | (int64(buf[2+16]) << 16) | (int64(buf[3+16]) << 24) | (int64(buf[4+16]) << 32) | (int64(buf[5+16]) << 40) | (int64(buf[6+16]) << 48) | (int64(buf[7+16]) << 56)
}
{
d.Deleted = 0 | (int64(buf[0+24]) << 0) | (int64(buf[1+24]) << 8) | (int64(buf[2+24]) << 16) | (int64(buf[3+24]) << 24) | (int64(buf[4+24]) << 32) | (int64(buf[5+24]) << 40) | (int64(buf[6+24]) << 48) | (int64(buf[7+24]) << 56)
}
{
d.Secret = buf[32] == 1
}
{
d.Cronjewel = buf[33] == 1
}
return i + 34, nil
}

10
database/model/meta.go Normal file
View file

@ -0,0 +1,10 @@
package model
type Meta struct {
Created int64 `json:"c,omitempty" bson:"c,omitempty"`
Modified int64 `json:"m,omitempty" bson:"m,omitempty"`
Expires int64 `json:"e,omitempty" bson:"e,omitempty"`
Deleted int64 `json:"d,omitempty" bson:"d,omitempty"`
Secret bool `json:"s,omitempty" bson:"s,omitempty"` // secrets must not be sent to the UI, only synced between nodes
Cronjewel bool `json:"j,omitempty" bson:"j,omitempty"` // crownjewels must never leave the instance, but may be read by the UI
}

311
database/model/meta_test.go Normal file
View file

@ -0,0 +1,311 @@
package model
import (
"bytes"
"testing"
"time"
"github.com/Safing/portbase/container"
"github.com/Safing/portbase/database/model/model"
"github.com/Safing/portbase/formats/dsd"
xdr2 "github.com/davecgh/go-xdr/xdr2"
)
var (
testMeta = &Meta{
Created: time.Now().Unix(),
Modified: time.Now().Unix(),
Expires: time.Now().Unix(),
Deleted: time.Now().Unix(),
Secret: true,
Cronjewel: true,
}
)
func BenchmarkAllocateBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = make([]byte, 33)
}
}
func BenchmarkAllocateStruct1(b *testing.B) {
for i := 0; i < b.N; i++ {
var new Meta
_ = new
}
}
func BenchmarkAllocateStruct2(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = Meta{}
}
}
func BenchmarkMetaSerializeCustom(b *testing.B) {
// Start benchmark
for i := 0; i < b.N; i++ {
c := container.New()
c.AppendNumber(uint64(testMeta.Created))
c.AppendNumber(uint64(testMeta.Modified))
c.AppendNumber(uint64(testMeta.Expires))
c.AppendNumber(uint64(testMeta.Deleted))
switch {
case testMeta.Secret && testMeta.Cronjewel:
c.AppendNumber(3)
case testMeta.Secret:
c.AppendNumber(1)
case testMeta.Cronjewel:
c.AppendNumber(2)
default:
c.AppendNumber(0)
}
}
}
func BenchmarkMetaUnserializeCustom(b *testing.B) {
// Setup
c := container.New()
c.AppendNumber(uint64(testMeta.Created))
c.AppendNumber(uint64(testMeta.Modified))
c.AppendNumber(uint64(testMeta.Expires))
c.AppendNumber(uint64(testMeta.Deleted))
switch {
case testMeta.Secret && testMeta.Cronjewel:
c.AppendNumber(3)
case testMeta.Secret:
c.AppendNumber(1)
case testMeta.Cronjewel:
c.AppendNumber(2)
default:
c.AppendNumber(0)
}
encodedData := c.CompileData()
// Reset timer for precise results
b.ResetTimer()
// Start benchmark
for i := 0; i < b.N; i++ {
var newMeta Meta
var err error
var num uint64
c := container.New(encodedData)
num, err = c.GetNextN64()
newMeta.Created = int64(num)
if err != nil {
b.Errorf("could not decode: %s", err)
return
}
num, err = c.GetNextN64()
newMeta.Modified = int64(num)
if err != nil {
b.Errorf("could not decode: %s", err)
return
}
num, err = c.GetNextN64()
newMeta.Expires = int64(num)
if err != nil {
b.Errorf("could not decode: %s", err)
return
}
num, err = c.GetNextN64()
newMeta.Deleted = int64(num)
if err != nil {
b.Errorf("could not decode: %s", err)
return
}
flags, err := c.GetNextN8()
if err != nil {
b.Errorf("could not decode: %s", err)
return
}
switch flags {
case 3:
newMeta.Secret = true
newMeta.Cronjewel = true
case 2:
newMeta.Cronjewel = true
case 1:
newMeta.Secret = true
case 0:
default:
b.Errorf("invalid flag value: %d", flags)
return
}
}
}
func BenchmarkMetaSerializeWithXDR2(b *testing.B) {
// Setup
var w bytes.Buffer
// Reset timer for precise results
b.ResetTimer()
// Start benchmark
for i := 0; i < b.N; i++ {
w.Reset()
_, err := xdr2.Marshal(&w, testMeta)
if err != nil {
b.Errorf("failed to serialize with xdr2: %s", err)
return
}
}
}
func BenchmarkMetaUnserializeWithXDR2(b *testing.B) {
// Setup
var w bytes.Buffer
_, err := xdr2.Marshal(&w, testMeta)
if err != nil {
b.Errorf("failed to serialize with xdr2: %s", err)
}
encodedData := w.Bytes()
// Reset timer for precise results
b.ResetTimer()
// Start benchmark
for i := 0; i < b.N; i++ {
var newMeta Meta
_, err := xdr2.Unmarshal(bytes.NewReader(encodedData), &newMeta)
if err != nil {
b.Errorf("failed to unserialize with xdr2: %s", err)
return
}
}
}
func BenchmarkMetaSerializeWithColfer(b *testing.B) {
testColf := &model.Course{
Created: time.Now().Unix(),
Modified: time.Now().Unix(),
Expires: time.Now().Unix(),
Deleted: time.Now().Unix(),
Secret: true,
Cronjewel: true,
}
// Setup
for i := 0; i < b.N; i++ {
_, err := testColf.MarshalBinary()
if err != nil {
b.Errorf("failed to serialize with colfer: %s", err)
return
}
}
}
func BenchmarkMetaUnserializeWithColfer(b *testing.B) {
testColf := &model.Course{
Created: time.Now().Unix(),
Modified: time.Now().Unix(),
Expires: time.Now().Unix(),
Deleted: time.Now().Unix(),
Secret: true,
Cronjewel: true,
}
encodedData, err := testColf.MarshalBinary()
if err != nil {
b.Errorf("failed to serialize with colfer: %s", err)
return
}
// Setup
for i := 0; i < b.N; i++ {
var testUnColf model.Course
err := testUnColf.UnmarshalBinary(encodedData)
if err != nil {
b.Errorf("failed to unserialize with colfer: %s", err)
return
}
}
}
func BenchmarkMetaSerializeWithCodegen(b *testing.B) {
for i := 0; i < b.N; i++ {
buf := make([]byte, 34)
_, err := testMeta.Marshal(buf)
if err != nil {
b.Errorf("failed to serialize with codegen: %s", err)
return
}
}
}
func BenchmarkMetaUnserializeWithCodegen(b *testing.B) {
// Setup
buf := make([]byte, 34)
encodedData, err := testMeta.Marshal(buf)
if err != nil {
b.Errorf("failed to serialize with codegen: %s", err)
return
}
// Reset timer for precise results
b.ResetTimer()
// Start benchmark
for i := 0; i < b.N; i++ {
var newMeta Meta
_, err := newMeta.Unmarshal(encodedData)
if err != nil {
b.Errorf("failed to unserialize with codegen: %s", err)
return
}
}
}
func BenchmarkMetaSerializeWithDSDJSON(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := dsd.Dump(testMeta, dsd.JSON)
if err != nil {
b.Errorf("failed to serialize with DSD/JSON: %s", err)
return
}
}
}
func BenchmarkMetaUnserializeWithDSDJSON(b *testing.B) {
// Setup
encodedData, err := dsd.Dump(testMeta, dsd.JSON)
if err != nil {
b.Errorf("failed to serialize with DSD/JSON: %s", err)
return
}
// Reset timer for precise results
b.ResetTimer()
// Start benchmark
for i := 0; i < b.N; i++ {
var newMeta Meta
_, err := dsd.Load(encodedData, &newMeta)
if err != nil {
b.Errorf("failed to unserialize with DSD/JSON: %s", err)
return
}
}
}

View file

@ -1,7 +1,4 @@
package model
type Meta struct {
}
type Model interface {
}

View file

@ -0,0 +1,507 @@
package model
// Code generated by colf(1); DO NOT EDIT.
// The compiler used schema file meta.colf.
import (
"encoding/binary"
"fmt"
"io"
)
var intconv = binary.BigEndian
// Colfer configuration attributes
var (
// ColferSizeMax is the upper limit for serial byte sizes.
ColferSizeMax = 16 * 1024 * 1024
)
// ColferMax signals an upper limit breach.
type ColferMax string
// Error honors the error interface.
func (m ColferMax) Error() string { return string(m) }
// ColferError signals a data mismatch as as a byte index.
type ColferError int
// Error honors the error interface.
func (i ColferError) Error() string {
return fmt.Sprintf("colfer: unknown header at byte %d", i)
}
// ColferTail signals data continuation as a byte index.
type ColferTail int
// Error honors the error interface.
func (i ColferTail) Error() string {
return fmt.Sprintf("colfer: data continuation at byte %d", i)
}
type Course struct {
Created int64
Modified int64
Expires int64
Deleted int64
Secret bool
Cronjewel bool
}
// MarshalTo encodes o as Colfer into buf and returns the number of bytes written.
// If the buffer is too small, MarshalTo will panic.
func (o *Course) MarshalTo(buf []byte) int {
var i int
if v := o.Created; v != 0 {
x := uint64(v)
if v >= 0 {
buf[i] = 0
} else {
x = ^x + 1
buf[i] = 0 | 0x80
}
i++
for n := 0; x >= 0x80 && n < 8; n++ {
buf[i] = byte(x | 0x80)
x >>= 7
i++
}
buf[i] = byte(x)
i++
}
if v := o.Modified; v != 0 {
x := uint64(v)
if v >= 0 {
buf[i] = 1
} else {
x = ^x + 1
buf[i] = 1 | 0x80
}
i++
for n := 0; x >= 0x80 && n < 8; n++ {
buf[i] = byte(x | 0x80)
x >>= 7
i++
}
buf[i] = byte(x)
i++
}
if v := o.Expires; v != 0 {
x := uint64(v)
if v >= 0 {
buf[i] = 2
} else {
x = ^x + 1
buf[i] = 2 | 0x80
}
i++
for n := 0; x >= 0x80 && n < 8; n++ {
buf[i] = byte(x | 0x80)
x >>= 7
i++
}
buf[i] = byte(x)
i++
}
if v := o.Deleted; v != 0 {
x := uint64(v)
if v >= 0 {
buf[i] = 3
} else {
x = ^x + 1
buf[i] = 3 | 0x80
}
i++
for n := 0; x >= 0x80 && n < 8; n++ {
buf[i] = byte(x | 0x80)
x >>= 7
i++
}
buf[i] = byte(x)
i++
}
if o.Secret {
buf[i] = 4
i++
}
if o.Cronjewel {
buf[i] = 5
i++
}
buf[i] = 0x7f
i++
return i
}
// MarshalLen returns the Colfer serial byte size.
// The error return option is model.ColferMax.
func (o *Course) MarshalLen() (int, error) {
l := 1
if v := o.Created; v != 0 {
l += 2
x := uint64(v)
if v < 0 {
x = ^x + 1
}
for n := 0; x >= 0x80 && n < 8; n++ {
x >>= 7
l++
}
}
if v := o.Modified; v != 0 {
l += 2
x := uint64(v)
if v < 0 {
x = ^x + 1
}
for n := 0; x >= 0x80 && n < 8; n++ {
x >>= 7
l++
}
}
if v := o.Expires; v != 0 {
l += 2
x := uint64(v)
if v < 0 {
x = ^x + 1
}
for n := 0; x >= 0x80 && n < 8; n++ {
x >>= 7
l++
}
}
if v := o.Deleted; v != 0 {
l += 2
x := uint64(v)
if v < 0 {
x = ^x + 1
}
for n := 0; x >= 0x80 && n < 8; n++ {
x >>= 7
l++
}
}
if o.Secret {
l++
}
if o.Cronjewel {
l++
}
if l > ColferSizeMax {
return l, ColferMax(fmt.Sprintf("colfer: struct model.course exceeds %d bytes", ColferSizeMax))
}
return l, nil
}
// MarshalBinary encodes o as Colfer conform encoding.BinaryMarshaler.
// The error return option is model.ColferMax.
func (o *Course) MarshalBinary() (data []byte, err error) {
l, err := o.MarshalLen()
if err != nil {
return nil, err
}
data = make([]byte, l)
o.MarshalTo(data)
return data, nil
}
// Unmarshal decodes data as Colfer and returns the number of bytes read.
// The error return options are io.EOF, model.ColferError and model.ColferMax.
func (o *Course) Unmarshal(data []byte) (int, error) {
if len(data) == 0 {
return 0, io.EOF
}
header := data[0]
i := 1
if header == 0 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Created = int64(x)
header = data[i]
i++
} else if header == 0|0x80 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Created = int64(^x + 1)
header = data[i]
i++
}
if header == 1 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Modified = int64(x)
header = data[i]
i++
} else if header == 1|0x80 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Modified = int64(^x + 1)
header = data[i]
i++
}
if header == 2 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Expires = int64(x)
header = data[i]
i++
} else if header == 2|0x80 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Expires = int64(^x + 1)
header = data[i]
i++
}
if header == 3 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Deleted = int64(x)
header = data[i]
i++
} else if header == 3|0x80 {
if i+1 >= len(data) {
i++
goto eof
}
x := uint64(data[i])
i++
if x >= 0x80 {
x &= 0x7f
for shift := uint(7); ; shift += 7 {
b := uint64(data[i])
i++
if i >= len(data) {
goto eof
}
if b < 0x80 || shift == 56 {
x |= b << shift
break
}
x |= (b & 0x7f) << shift
}
}
o.Deleted = int64(^x + 1)
header = data[i]
i++
}
if header == 4 {
if i >= len(data) {
goto eof
}
o.Secret = true
header = data[i]
i++
}
if header == 5 {
if i >= len(data) {
goto eof
}
o.Cronjewel = true
header = data[i]
i++
}
if header != 0x7f {
return 0, ColferError(i - 1)
}
if i < ColferSizeMax {
return i, nil
}
eof:
if i >= ColferSizeMax {
return 0, ColferMax(fmt.Sprintf("colfer: struct model.course size exceeds %d bytes", ColferSizeMax))
}
return 0, io.EOF
}
// UnmarshalBinary decodes data as Colfer conform encoding.BinaryUnmarshaler.
// The error return options are io.EOF, model.ColferError, model.ColferTail and model.ColferMax.
func (o *Course) UnmarshalBinary(data []byte) error {
i, err := o.Unmarshal(data)
if i < len(data) && err == nil {
return ColferTail(i)
}
return err
}