1
0
mirror of https://github.com/fumiama/go-base16384.git synced 2026-06-05 00:32:52 +08:00

speed up encoder & decoder

name           old time/op    new time/op    delta
Encoder/16-8      136ns ± 2%     102ns ± 1%  -25.00%  (p=0.008 n=5+5)
Encoder/256-8     490ns ± 1%     410ns ± 0%  -16.24%  (p=0.008 n=5+5)
Encoder/4K-8     4.47µs ± 1%    3.52µs ± 1%  -21.10%  (p=0.008 n=5+5)
Encoder/32K-8    38.9µs ± 0%    33.6µs ± 1%  -13.72%  (p=0.008 n=5+5)
Decoder/16-8      269ns ± 1%     253ns ± 1%   -5.95%  (p=0.008 n=5+5)
Decoder/256-8     421ns ± 1%     404ns ± 2%   -4.22%  (p=0.008 n=5+5)
Decoder/4K-8     1.68µs ± 1%    1.66µs ± 3%     ~     (p=0.190 n=5+5)
Decoder/32K-8    12.9µs ± 1%    12.5µs ± 1%   -2.68%  (p=0.008 n=5+5)

name           old speed      new speed      delta
Encoder/16-8    118MB/s ± 2%   157MB/s ± 1%  +33.34%  (p=0.008 n=5+5)
Encoder/256-8   523MB/s ± 1%   624MB/s ± 0%  +19.38%  (p=0.008 n=5+5)
Encoder/4K-8    917MB/s ± 1%  1162MB/s ± 1%  +26.73%  (p=0.008 n=5+5)
Encoder/32K-8   841MB/s ± 0%   975MB/s ± 1%  +15.90%  (p=0.008 n=5+5)
Decoder/16-8   59.5MB/s ± 1%  63.2MB/s ± 1%   +6.34%  (p=0.008 n=5+5)
Decoder/256-8   607MB/s ± 1%   634MB/s ± 2%   +4.42%  (p=0.008 n=5+5)
Decoder/4K-8   2.44GB/s ± 1%  2.46GB/s ± 3%     ~     (p=0.222 n=5+5)
Decoder/32K-8  2.54GB/s ± 1%  2.61GB/s ± 1%   +2.76%  (p=0.008 n=5+5)

name           old alloc/op   new alloc/op   delta
Encoder/16-8      40.0B ± 0%     24.0B ± 0%  -40.00%  (p=0.008 n=5+5)
Encoder/256-8      696B ± 0%      472B ± 0%  -32.18%  (p=0.008 n=5+5)
Encoder/4K-8     4.12kB ± 0%    0.02kB ± 0%  -99.42%  (p=0.008 n=5+5)
Encoder/32K-8    69.7kB ± 0%    41.0kB ± 0%  -41.16%  (p=0.000 n=5+4)
Decoder/16-8       752B ± 0%      752B ± 0%     ~     (all equal)
Decoder/256-8    1.39kB ± 0%    1.39kB ± 0%     ~     (all equal)
Decoder/4K-8     4.98kB ± 0%    4.98kB ± 0%     ~     (all equal)
Decoder/32K-8    41.1kB ± 0%    41.1kB ± 0%     ~     (all equal)

name           old allocs/op  new allocs/op  delta
Encoder/16-8       2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.008 n=5+5)
Encoder/256-8      3.00 ± 0%      2.00 ± 0%  -33.33%  (p=0.008 n=5+5)
Encoder/4K-8       2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.008 n=5+5)
Encoder/32K-8      3.00 ± 0%      2.00 ± 0%  -33.33%  (p=0.008 n=5+5)
Decoder/16-8       3.00 ± 0%      3.00 ± 0%     ~     (all equal)
Decoder/256-8      3.00 ± 0%      3.00 ± 0%     ~     (all equal)
Decoder/4K-8       3.00 ± 0%      3.00 ± 0%     ~     (all equal)
Decoder/32K-8      3.00 ± 0%      3.00 ± 0%     ~     (all equal)
This commit is contained in:
源文雨
2022-04-22 21:05:19 +08:00
parent 87b51ceb35
commit 2e6fe912c2
7 changed files with 163 additions and 79 deletions

View File

@@ -4,7 +4,7 @@
#include "textflag.h"
// func encode(offset, outlen int, b, encd []byte)
TEXT ·encode(SB), NOSPLIT, $56-64
TEXT ·encode(SB), NOSPLIT, $0-64
MOVQ ·offset+0(FP), R10
MOVQ ·outlen+8(FP), AX
MOVQ ·data+16(FP), DI
@@ -125,7 +125,7 @@ encend:
// func decode(offset, outlen int, b, decd []byte)
TEXT ·decode(SB), NOSPLIT, $56-64
TEXT ·decode(SB), NOSPLIT, $0-64
MOVQ ·offset+0(FP), BX
MOVQ ·outlen+8(FP), R8
MOVQ ·data+16(FP), DI

View File

@@ -4,7 +4,9 @@
package base14
//go:noescape
//go:nosplit
func encode(offset, outlen int, b, encd []byte)
//go:noescape
//go:nosplit
func decode(offset, outlen int, b, decd []byte)

View File

@@ -29,22 +29,23 @@ func TestBase14(t *testing.T) {
}
func TestEncoder(t *testing.T) {
buf := make([]byte, 42242141)
buf := make([]byte, 1024*1024+1)
_, err := rand.Read(buf)
if err != nil {
t.Fatal(err)
}
e := NewEncoder(bytes.NewReader(buf))
w := bytes.NewBuffer(make([]byte, 0, 42242150))
_, err = io.Copy(w, e)
if err != nil {
t.Fatal(err)
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 7 {
e := NewEncoder(bytes.NewReader(buf[:i]))
_, err = io.Copy(w, e)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(Encode(buf[:i]), w.Bytes()) {
t.Fail()
}
w.Reset()
}
out := w.Bytes()
assert.Equal(t, 48276736, w.Len())
d := Decode(out)
t.Log(len(out))
assert.Equal(t, buf, d)
}
func TestBufferedEncoder(t *testing.T) {
@@ -53,17 +54,17 @@ func TestBufferedEncoder(t *testing.T) {
if err != nil {
t.Fatal(err)
}
e := NewBufferedEncoder(buf)
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+16))
_, err = io.Copy(w, e)
if err != nil {
t.Fatal(err)
}
out := w.Bytes()
t.Log(w.Len())
d := Decode(out)
if !bytes.Equal(buf, d) {
t.Fail()
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 7 {
e := NewBufferedEncoder(buf[:i])
_, err = io.Copy(w, e)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(Encode(buf[:i]), w.Bytes()) {
t.Fail()
}
w.Reset()
}
}
@@ -73,15 +74,18 @@ func TestDecoder(t *testing.T) {
if err != nil {
t.Fatal(err)
}
encd := Encode(buf)
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
d := NewDecoder(bytes.NewReader(Encode(buf)))
_, err = io.Copy(w, d)
if err != nil {
t.Fatal(err)
}
t.Log(w.Len())
if !bytes.Equal(buf, w.Bytes()) {
t.Fail()
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 8 {
d := NewDecoder(bytes.NewReader(encd[:i]))
_, err = io.Copy(w, d)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf[:i/8*7], w.Bytes()) {
t.Fail()
}
w.Reset()
}
}
@@ -91,19 +95,22 @@ func TestBufferedDecoder(t *testing.T) {
if err != nil {
t.Fatal(err)
}
encd := Encode(buf)
w := bytes.NewBuffer(make([]byte, 0, 1024*1024+1))
d := NewBufferedDecoder(Encode(buf))
_, err = io.Copy(w, d)
if err != nil {
t.Fatal(err)
}
t.Log(w.Len())
if !bytes.Equal(buf, w.Bytes()) {
t.Fail()
for i := 0; i <= 1024*1024; i += rand.Intn(128) * 8 {
d := NewBufferedDecoder(encd[:i])
_, err = io.Copy(w, d)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(buf[:i/8*7], w.Bytes()) {
t.Fail()
}
w.Reset()
}
}
func benchEncrypt(b *testing.B, data []byte) {
func benchEncode(b *testing.B, data []byte) {
_, err := rand.Read(data)
if err != nil {
panic(err)
@@ -116,7 +123,7 @@ func benchEncrypt(b *testing.B, data []byte) {
}
}
func benchDecrypt(b *testing.B, data []byte) {
func benchDecode(b *testing.B, data []byte) {
_, err := rand.Read(data)
if err != nil {
panic(err)
@@ -136,37 +143,94 @@ func benchDecrypt(b *testing.B, data []byte) {
func BenchmarkEncodeTo(b *testing.B) {
b.Run("16", func(b *testing.B) {
data := make([]byte, 16)
benchEncrypt(b, data)
benchEncode(b, data)
})
b.Run("256", func(b *testing.B) {
data := make([]byte, 256)
benchEncrypt(b, data)
benchEncode(b, data)
})
b.Run("4K", func(b *testing.B) {
data := make([]byte, 1024*4)
benchEncrypt(b, data)
benchEncode(b, data)
})
b.Run("32K", func(b *testing.B) {
data := make([]byte, 1024*32)
benchEncrypt(b, data)
benchEncode(b, data)
})
}
func BenchmarkDecodeTo(b *testing.B) {
b.Run("16", func(b *testing.B) {
data := make([]byte, 16)
benchDecrypt(b, data)
benchDecode(b, data)
})
b.Run("256", func(b *testing.B) {
data := make([]byte, 256)
benchDecrypt(b, data)
benchDecode(b, data)
})
b.Run("4K", func(b *testing.B) {
data := make([]byte, 4096)
benchDecrypt(b, data)
benchDecode(b, data)
})
b.Run("32K", func(b *testing.B) {
data := make([]byte, 1024*32)
benchDecrypt(b, data)
benchDecode(b, data)
})
}
func benchEncoder(b *testing.B, cnt int64) {
enc := NewEncoder(rand.New(rand.NewSource(0)))
buf := bytes.NewBuffer(make([]byte, 0, cnt))
b.SetBytes(cnt)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = io.CopyN(buf, enc, cnt)
buf.Reset()
}
}
func benchDecoder(b *testing.B, cnt int64) {
enc := NewEncoder(rand.New(rand.NewSource(0)))
buf := bytes.NewBuffer(make([]byte, 0, cnt))
_, err := io.CopyN(buf, enc, cnt)
if err != nil {
panic(err)
}
buf2 := bytes.NewBuffer(make([]byte, 0, cnt))
b.SetBytes(cnt)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = io.Copy(buf2, NewDecoder(bytes.NewReader(buf.Bytes())))
buf2.Reset()
}
}
func BenchmarkEncoder(b *testing.B) {
b.Run("16", func(b *testing.B) {
benchEncoder(b, 16)
})
b.Run("256", func(b *testing.B) {
benchEncoder(b, 256)
})
b.Run("4K", func(b *testing.B) {
benchEncoder(b, 1024*4)
})
b.Run("32K", func(b *testing.B) {
benchEncoder(b, 1024*32)
})
}
func BenchmarkDecoder(b *testing.B) {
b.Run("16", func(b *testing.B) {
benchDecoder(b, 16)
})
b.Run("256", func(b *testing.B) {
benchDecoder(b, 256)
})
b.Run("4K", func(b *testing.B) {
benchDecoder(b, 1024*4)
})
b.Run("32K", func(b *testing.B) {
benchDecoder(b, 1024*32)
})
}

View File

@@ -24,43 +24,63 @@ func (d *Decoder) Read(p []byte) (n int, err error) {
err = io.EOF
return
}
inlen := len(p)/7*8 + 2
inlen := len(p) / 7 * 8
if d.r != nil {
d.b = append(d.b, make([]byte, inlen)...)
n, err = d.r.Read(d.b[i:])
if n <= 0 {
return
}
inlen = i + n
d.b = d.b[:inlen]
if err != nil {
if len(d.b) > 0 {
if inlen > 0 {
offset := 0
if d.b[len(d.b)-2] == '=' {
offset = int(d.b[len(d.b)-1])
if d.b[inlen-2] == '=' {
offset = int(d.b[inlen-1])
}
n = DecodeLen(len(d.b), offset)
_ = DecodeTo(d.b, p)
n = DecodeLen(inlen, offset)
_ = DecodeTo(d.b[:inlen], p)
d.b = nil
d.r = nil
}
return
}
if inlen%2 != 0 {
d.b = d.b[:inlen]
n = 0
return
}
offset := 0
if d.b[inlen-2] == '=' {
offset = int(d.b[inlen-1])
}
if offset > 0 {
n = DecodeLen(len(d.b[:inlen]), offset)
_ = DecodeTo(d.b[:inlen], p)
d.b = nil
d.r = nil
} else {
n = DecodeLen(inlen, 0)
_ = DecodeTo(d.b[:inlen], p)
d.b = d.b[:0]
}
return
} else if inlen > len(d.b) {
inlen = len(d.b)
}
if inlen >= 2 {
inlen -= 2
if inlen <= 2 {
err = io.EOF
return
}
if len(d.b[inlen:]) == 2 {
inlen += 2
}
offset := 0
if d.b[len(d.b)-2] == '=' {
offset = int(d.b[len(d.b)-1])
}
if offset > 0 {
n = DecodeLen(len(d.b), offset)
_ = DecodeTo(d.b, p)
d.b = nil
} else {
n = DecodeLen(inlen, 0)
_ = DecodeTo(d.b[:inlen], p)
d.b = d.b[inlen:]
if d.b[inlen-2] == '=' {
offset = int(d.b[inlen-1])
}
n = DecodeLen(inlen, offset)
_ = DecodeTo(d.b[:inlen], p)
d.b = d.b[inlen:]
return
}

View File

@@ -29,7 +29,6 @@ func (e *Encoder) Read(p []byte) (n int, err error) {
e.b = append(e.b, make([]byte, inlen)...)
n, err = e.r.Read(e.b[i:])
inlen = i + n
e.b = e.b[:inlen]
if err != nil {
if len(e.b) > 0 {
n = EncodeLen(inlen)
@@ -39,11 +38,15 @@ func (e *Encoder) Read(p []byte) (n int, err error) {
e.r = nil
return
}
n = EncodeLen(inlen)
err = EncodeTo(e.b[:inlen], p)
e.b = e.b[:0]
return
} else if inlen > len(e.b) {
inlen = len(e.b)
}
n = EncodeLen(inlen)
_ = EncodeTo(e.b[:inlen], p)
err = EncodeTo(e.b[:inlen], p)
e.b = e.b[inlen:]
return
}

8
go.mod
View File

@@ -1,14 +1,8 @@
module github.com/fumiama/go-base16384
go 1.18
go 1.16
require (
github.com/stretchr/testify v1.7.1
golang.org/x/text v0.3.7
)
require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

1
go.sum
View File

@@ -7,6 +7,7 @@ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMT
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=