From 436f94e994774c05fb36a3b69cab684e21d4a9b9 Mon Sep 17 00:00:00 2001 From: Roman Atachiants Date: Sat, 23 Oct 2021 13:48:43 +0400 Subject: [PATCH] Added more benchmarks and cleaned up --- commit/buffer.go | 108 +++++++++++++++++++----------------------- commit/buffer_test.go | 71 +++++++++++++++++++++++---- commit/reader.go | 7 ++- 3 files changed, 114 insertions(+), 72 deletions(-) diff --git a/commit/buffer.go b/commit/buffer.go index 8bd12fc..a64a3a9 100644 --- a/commit/buffer.go +++ b/commit/buffer.go @@ -141,72 +141,64 @@ func (b *Buffer) PutAny(op OpType, idx uint32, value interface{}) { // PutUint64 appends a uint64 value. func (b *Buffer) PutUint64(op OpType, idx uint32, value uint64) { - b.writeChunk(idx) - delta := int32(idx) - b.last - b.last = int32(idx) - if delta == 1 { + delta := b.writeChunk(idx) + switch delta { + case 1: b.buffer = append(b.buffer, byte(op)|size8|isNext, byte(value>>56), byte(value>>48), byte(value>>40), byte(value>>32), byte(value>>24), byte(value>>16), byte(value>>8), byte(value), ) - return + default: + b.buffer = append(b.buffer, + byte(op)|size8, + byte(value>>56), byte(value>>48), byte(value>>40), byte(value>>32), + byte(value>>24), byte(value>>16), byte(value>>8), byte(value), + ) + b.writeOffset(uint32(delta)) } - - b.buffer = append(b.buffer, - byte(op)|size8, - byte(value>>56), byte(value>>48), byte(value>>40), byte(value>>32), - byte(value>>24), byte(value>>16), byte(value>>8), byte(value), - ) - b.writeOffset(uint32(delta)) } // PutUint32 appends a uint32 value. func (b *Buffer) PutUint32(op OpType, idx uint32, value uint32) { - b.writeChunk(idx) - delta := int32(idx) - b.last - b.last = int32(idx) - if delta == 1 { + delta := b.writeChunk(idx) + switch delta { + case 1: b.buffer = append(b.buffer, byte(op)|size4|isNext, byte(value>>24), byte(value>>16), byte(value>>8), byte(value), ) - return + default: + b.buffer = append(b.buffer, + byte(op)|size4, + byte(value>>24), byte(value>>16), byte(value>>8), byte(value), + ) + b.writeOffset(uint32(delta)) } - - b.buffer = append(b.buffer, - byte(op)|size4, - byte(value>>24), byte(value>>16), byte(value>>8), byte(value), - ) - b.writeOffset(uint32(delta)) } // PutUint16 appends a uint16 value. func (b *Buffer) PutUint16(op OpType, idx uint32, value uint16) { - b.writeChunk(idx) - delta := int32(idx) - b.last - b.last = int32(idx) - if delta == 1 { + delta := b.writeChunk(idx) + switch delta { + case 1: b.buffer = append(b.buffer, byte(op)|size2|isNext, byte(value>>8), byte(value)) - return + default: + b.buffer = append(b.buffer, byte(op)|size2, byte(value>>8), byte(value)) + b.writeOffset(uint32(delta)) } - - b.buffer = append(b.buffer, byte(op)|size2, byte(value>>8), byte(value)) - b.writeOffset(uint32(delta)) } // PutOperation appends an operation type without a value. func (b *Buffer) PutOperation(op OpType, idx uint32) { - b.writeChunk(idx) - delta := int32(idx) - b.last - b.last = int32(idx) - if delta == 1 { + delta := b.writeChunk(idx) + switch delta { + case 1: b.buffer = append(b.buffer, byte(op)|size0|isNext) - return + default: + b.buffer = append(b.buffer, byte(op)|size0) + b.writeOffset(uint32(delta)) } - - b.buffer = append(b.buffer, byte(op)|size0) - b.writeOffset(uint32(delta)) } // PutBool appends a boolean value. @@ -263,29 +255,25 @@ func (b *Buffer) PutUint(op OpType, idx uint32, value uint) { // PutBytes appends a binary value. func (b *Buffer) PutBytes(op OpType, idx uint32, value []byte) { - b.writeChunk(idx) - delta := int32(idx) - b.last - b.last = int32(idx) - - // Write a 2-byte length (max 65K slices) - length := len(value) - if delta == 1 { + delta := b.writeChunk(idx) + length := len(value) // max 65K slices + switch delta { + case 1: b.buffer = append(b.buffer, byte(op)|size2|isString|isNext, byte(length>>8), byte(length), ) b.buffer = append(b.buffer, value...) - return - } - - b.buffer = append(b.buffer, - byte(op)|size2|isString, - byte(length>>8), byte(length), - ) + default: + b.buffer = append(b.buffer, + byte(op)|size2|isString, + byte(length>>8), byte(length), + ) - // Write the the data itself and the offset - b.buffer = append(b.buffer, value...) - b.writeOffset(uint32(delta)) + // Write the the data itself and the offset + b.buffer = append(b.buffer, value...) + b.writeOffset(uint32(delta)) + } } // PutString appends a string value. @@ -303,8 +291,8 @@ func (b *Buffer) writeOffset(delta uint32) { b.buffer = append(b.buffer, byte(delta)) } -// writeChunk writes a chunk if changed -func (b *Buffer) writeChunk(idx uint32) { +// writeChunk writes a chunk if changed and returns the delta +func (b *Buffer) writeChunk(idx uint32) int32 { if chunk := idx >> chunkShift; b.chunk != chunk { b.chunk = chunk b.chunks = append(b.chunks, header{ @@ -313,6 +301,10 @@ func (b *Buffer) writeChunk(idx uint32) { Value: uint32(b.last), }) } + + delta := int32(idx) - b.last + b.last = int32(idx) + return delta } // toBytes converts a string to a byte slice without allocating. diff --git a/commit/buffer_test.go b/commit/buffer_test.go index 6a41a28..96d41d0 100644 --- a/commit/buffer_test.go +++ b/commit/buffer_test.go @@ -12,15 +12,30 @@ import ( /* cpu: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz -BenchmarkQueue/rw-u16-8 202 5891099 ns/op 7 B/op 0 allocs/op -BenchmarkQueue/rw-u32-8 200 5932520 ns/op 7 B/op 0 allocs/op -BenchmarkQueue/rw-u64-8 190 6192885 ns/op 8 B/op 0 allocs/op -BenchmarkQueue/rw-str-8 98 11060616 ns/op 15 B/op 0 allocs/op -BenchmarkQueue/rw-bool-8 213 5615013 ns/op 7 B/op 0 allocs/op +BenchmarkQueue/u16-rw-8 154 7691836 ns/op 19 B/op 0 allocs/op +BenchmarkQueue/u16-next-8 214 5542922 ns/op 7 B/op 0 allocs/op +BenchmarkQueue/u32-rw-8 152 7743216 ns/op 20 B/op 0 allocs/op +BenchmarkQueue/u32-next-8 212 5616605 ns/op 7 B/op 0 allocs/op +BenchmarkQueue/u64-rw-8 148 8000536 ns/op 20 B/op 0 allocs/op +BenchmarkQueue/u64-next-8 194 6126377 ns/op 7 B/op 0 allocs/op +BenchmarkQueue/str-rw-8 91 12935521 ns/op 33 B/op 0 allocs/op +BenchmarkQueue/str-next-8 98 10901156 ns/op 15 B/op 0 allocs/op +BenchmarkQueue/bool-rw-8 169 6950441 ns/op 18 B/op 0 allocs/op +BenchmarkQueue/bool-next-8 228 5195821 ns/op 6 B/op 0 allocs/op */ func BenchmarkQueue(b *testing.B) { const count = 1000000 - run("rw-u16", b, count, func(buf *Buffer, r *Reader) { + + run("u16-rw", b, count, func(buf *Buffer, r *Reader) { + for i := uint32(0); i < count*2; i += 2 { + buf.PutUint16(Put, i, uint16(i)) + } + for r.Seek(buf); r.Next(); { + _ = r.Uint16() + } + }) + + run("u16-next", b, count, func(buf *Buffer, r *Reader) { for i := uint32(0); i < count; i++ { buf.PutUint16(Put, i, uint16(i)) } @@ -29,7 +44,16 @@ func BenchmarkQueue(b *testing.B) { } }) - run("rw-u32", b, count, func(buf *Buffer, r *Reader) { + run("u32-rw", b, count, func(buf *Buffer, r *Reader) { + for i := uint32(0); i < count*2; i += 2 { + buf.PutUint32(Put, i, i) + } + for r.Seek(buf); r.Next(); { + _ = r.Uint32() + } + }) + + run("u32-next", b, count, func(buf *Buffer, r *Reader) { for i := uint32(0); i < count; i++ { buf.PutUint32(Put, i, i) } @@ -38,7 +62,16 @@ func BenchmarkQueue(b *testing.B) { } }) - run("rw-u64", b, count, func(buf *Buffer, r *Reader) { + run("u64-rw", b, count, func(buf *Buffer, r *Reader) { + for i := uint32(0); i < count*2; i += 2 { + buf.PutUint64(Put, i, uint64(i)) + } + for r.Seek(buf); r.Next(); { + _ = r.Uint64() + } + }) + + run("u64-next", b, count, func(buf *Buffer, r *Reader) { for i := uint32(0); i < count; i++ { buf.PutUint64(Put, i, uint64(i)) } @@ -47,7 +80,16 @@ func BenchmarkQueue(b *testing.B) { } }) - run("rw-str", b, count, func(buf *Buffer, r *Reader) { + run("str-rw", b, count, func(buf *Buffer, r *Reader) { + for i := uint32(0); i < count*2; i += 2 { + buf.PutString(Put, i, "hello world") + } + for r.Seek(buf); r.Next(); { + _ = r.String() + } + }) + + run("str-next", b, count, func(buf *Buffer, r *Reader) { for i := uint32(0); i < count; i++ { buf.PutString(Put, i, "hello world") } @@ -56,7 +98,16 @@ func BenchmarkQueue(b *testing.B) { } }) - run("rw-bool", b, count, func(buf *Buffer, r *Reader) { + run("bool-rw", b, count, func(buf *Buffer, r *Reader) { + for i := uint32(0); i < count*2; i += 2 { + buf.PutBool(i, true) + } + for r.Seek(buf); r.Next(); { + _ = r.Bool() + } + }) + + run("bool-next", b, count, func(buf *Buffer, r *Reader) { for i := uint32(0); i < count; i++ { buf.PutBool(i, true) } diff --git a/commit/reader.go b/commit/reader.go index 760140f..459d9c5 100644 --- a/commit/reader.go +++ b/commit/reader.go @@ -13,9 +13,9 @@ import ( type Reader struct { head int // The read position i0, i1 int // The value start and end + Type OpType // The current operation type buffer []byte // The log slice Offset int32 // The current offset - Type OpType // The current operation type start int32 // The start offset } @@ -329,20 +329,19 @@ func (r *Reader) readOffset() { // readFixed reads the fixed-size value at the current position. func (r *Reader) readFixed(v byte) { size := int(1 << (v >> 4 & 0b11) & 0b1110) - r.Type = OpType(v & 0xf) r.head++ r.i0 = r.head r.head += size r.i1 = r.head + r.Type = OpType(v & 0xf) } // readString reads the operation type and the value at the current position. func (r *Reader) readString(v byte) { - _ = r.buffer[r.head+2] size := int(r.buffer[r.head+2]) | int(r.buffer[r.head+1])<<8 - r.Type = OpType(v & 0xf) r.head += 3 r.i0 = r.head r.head += size r.i1 = r.head + r.Type = OpType(v & 0xf) }