Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support sse and add benchmarks #11

Merged
merged 3 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Check License Header
uses: apache/skywalking-eyes/header@v0.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - name: Check License Header
# uses: apache/skywalking-eyes/header@v0.4.0
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

#- name: Check Spell
# uses: crate-ci/typos@master
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "tools/asm2asm"]
path = tools/asm2asm
url = https://github.com/cloudwego/asm2asm
6 changes: 4 additions & 2 deletions base64x.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package base64x

import (
`encoding/base64`

"github.com/cloudwego/base64x/internal/native"
)

// An Encoding is a radix 64 encoding/decoding scheme, defined by a
Expand Down Expand Up @@ -87,7 +89,7 @@ func (self Encoding) Encode(out []byte, src []byte) {
//
// It will also update the length of out.
func (self Encoding) EncodeUnsafe(out *[]byte, src []byte) {
b64encode(out, &src, int(self) | archFlags)
native.B64Encode(out, &src, int(self) | archFlags)
}

// EncodeToString returns the base64 encoding of src.
Expand Down Expand Up @@ -136,7 +138,7 @@ func (self Encoding) Decode(out []byte, src []byte) (int, error) {
//
// It will also update the length of out.
func (self Encoding) DecodeUnsafe(out *[]byte, src []byte) (int, error) {
if n := b64decode(out, mem2addr(src), len(src), int(self) | archFlags); n >= 0 {
if n := native.B64Decode(out, mem2addr(src), len(src), int(self) | archFlags); n >= 0 {
return n, nil
} else {
return 0, base64.CorruptInputError(-n - 1)
Expand Down
18 changes: 18 additions & 0 deletions base64x_subr_amd64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@


package base64x

import (
"github.com/cloudwego/base64x/internal/native"
)

// HACK: maintain these only to prevent breakchange, because sonic-go linkname these
var (
_subr__b64decode uintptr
_subr__b64encode uintptr
)

func init() {
_subr__b64decode = native.S_b64decode
_subr__b64encode = native.S_b64encode
}
123 changes: 0 additions & 123 deletions base64x_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@
package base64x

import (
`crypto/rand`
`encoding/base64`
`io`
`reflect`
`strings`
`testing`
`unsafe`
)

type TestPair struct {
Expand Down Expand Up @@ -178,33 +174,6 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool {
return true
}

func TestEncoderRecover(t *testing.T) {
t.Run("nil dst", func(t *testing.T) {
in := []byte("abc")
defer func(){
if v := recover(); v != nil {
println("recover:", v)
} else {
t.Fatal("not recover")
}
}()
b64encode(nil, &in, int(StdEncoding))
})
t.Run("nil src", func(t *testing.T) {
in := []byte("abc")
(*reflect.SliceHeader)(unsafe.Pointer(&in)).Data = uintptr(0)
out := make([]byte, 0, 10)
defer func(){
if v := recover(); v != nil {
println("recover:", v)
} else {
t.Fatal("not recover")
}
}()
b64encode(&out, &in, int(StdEncoding))
})
}

func TestEncoder(t *testing.T) {
for _, p := range pairs {
for _, tt := range encodingTests {
Expand All @@ -214,46 +183,6 @@ func TestEncoder(t *testing.T) {
}
}

func benchmarkStdlibWithSize(b *testing.B, nb int) {
buf := make([]byte, nb)
dst := make([]byte, base64.StdEncoding.EncodedLen(nb))
_, _ = io.ReadFull(rand.Reader, buf)
b.SetBytes(int64(nb))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
base64.StdEncoding.Encode(dst, buf)
}
})
}

func benchmarkBase64xWithSize(b *testing.B, nb int) {
buf := make([]byte, nb)
dst := make([]byte, StdEncoding.EncodedLen(nb))
_, _ = io.ReadFull(rand.Reader, buf)
b.SetBytes(int64(nb))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
StdEncoding.Encode(dst, buf)
}
})
}

func BenchmarkEncoderStdlib_16B (b *testing.B) { benchmarkStdlibWithSize(b, 16) }
func BenchmarkEncoderStdlib_56B (b *testing.B) { benchmarkStdlibWithSize(b, 56) }
func BenchmarkEncoderStdlib_128B (b *testing.B) { benchmarkStdlibWithSize(b, 128) }
func BenchmarkEncoderStdlib_4kB (b *testing.B) { benchmarkStdlibWithSize(b, 4 * 1024) }
func BenchmarkEncoderStdlib_256kB (b *testing.B) { benchmarkStdlibWithSize(b, 256 * 1024) }
func BenchmarkEncoderStdlib_1MB (b *testing.B) { benchmarkStdlibWithSize(b, 1024 * 1024) }

func BenchmarkEncoderBase64x_16B (b *testing.B) { benchmarkBase64xWithSize(b, 16) }
func BenchmarkEncoderBase64x_56B (b *testing.B) { benchmarkBase64xWithSize(b, 56) }
func BenchmarkEncoderBase64x_128B (b *testing.B) { benchmarkBase64xWithSize(b, 128) }
func BenchmarkEncoderBase64x_4kB (b *testing.B) { benchmarkBase64xWithSize(b, 4 * 1024) }
func BenchmarkEncoderBase64x_256kB (b *testing.B) { benchmarkBase64xWithSize(b, 256 * 1024) }
func BenchmarkEncoderBase64x_1MB (b *testing.B) { benchmarkBase64xWithSize(b, 1024 * 1024) }

func TestDecoder(t *testing.T) {
for _, p := range pairs {
for _, tt := range encodingTests {
Expand All @@ -271,30 +200,6 @@ func TestDecoder(t *testing.T) {
}
}

func TestDecoderRecover(t *testing.T) {
t.Run("nil dst", func(t *testing.T) {
in := []byte("abc")
defer func(){
if v := recover(); v != nil {
println("recover:", v)
} else {
t.Fatal("not recover")
}
}()
b64decode(nil, unsafe.Pointer(&in[0]), len(in), int(StdEncoding))
})
t.Run("nil src", func(t *testing.T) {
out := make([]byte, 0, 10)
defer func(){
if v := recover(); v != nil {
println("recover:", v)
} else {
t.Fatal("not recover")
}
}()
b64decode(&out, nil, 5, int(StdEncoding))
})
}

func TestDecoderCRLF(t *testing.T) {
for _, p := range crlf_pairs {
Expand Down Expand Up @@ -350,31 +255,3 @@ func TestDecoderError(t *testing.T) {
panic(err)
}
}

func benchmarkStdlibDecoder(b *testing.B, v string) {
src := []byte(v)
dst := make([]byte, base64.StdEncoding.DecodedLen(len(v)))
b.SetBytes(int64(len(v)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = base64.StdEncoding.Decode(dst, src)
}
})
}

func benchmarkBase64xDecoder(b *testing.B, v string) {
src := []byte(v)
dst := make([]byte, StdEncoding.DecodedLen(len(v)))
b.SetBytes(int64(len(v)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = StdEncoding.Decode(dst, src)
}
})
}

var data = `////////////////////////////////////////////////////////////////`
func BenchmarkDecoderStdLib (b *testing.B) { benchmarkStdlibDecoder(b, data) }
func BenchmarkDecoderBase64x (b *testing.B) { benchmarkBase64xDecoder(b, data) }
101 changes: 101 additions & 0 deletions bench/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package bench

import (
"testing"
"encoding/base64"
`crypto/rand`
`io`

. "github.com/cloudwego/base64x"
cris "github.com/cristalhq/base64"
)

func benchmarkStdlibDecoder(b *testing.B, v string) {
src := []byte(v)
dst := make([]byte, base64.StdEncoding.DecodedLen(len(v)))
b.SetBytes(int64(len(v)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = base64.StdEncoding.Decode(dst, src)
}
})
}

func benchmarkBase64xDecoder(b *testing.B, v string) {
src := []byte(v)
dst := make([]byte, StdEncoding.DecodedLen(len(v)))
b.SetBytes(int64(len(v)))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = StdEncoding.Decode(dst, src)
}
})
}


func benchmarkStdlibWithSize(b *testing.B, nb int) {
buf := make([]byte, nb)
dst := make([]byte, base64.StdEncoding.EncodedLen(nb))
_, _ = io.ReadFull(rand.Reader, buf)
b.SetBytes(int64(nb))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
base64.StdEncoding.Encode(dst, buf)
}
})
}

func benchmarkBase64xWithSize(b *testing.B, nb int) {
buf := make([]byte, nb)
dst := make([]byte, StdEncoding.EncodedLen(nb))
_, _ = io.ReadFull(rand.Reader, buf)
b.SetBytes(int64(nb))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
StdEncoding.Encode(dst, buf)
}
})
}


func benchmarkCrisWithSize(b *testing.B, nb int) {
buf := make([]byte, nb)
dst := make([]byte, cris.StdEncoding.EncodedLen(nb))
_, _ = io.ReadFull(rand.Reader, buf)
b.SetBytes(int64(nb))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
cris.StdEncoding.Encode(dst, buf)
}
})
}

func BenchmarkEncoderStdlib_16B (b *testing.B) { benchmarkStdlibWithSize(b, 16) }
func BenchmarkEncoderStdlib_56B (b *testing.B) { benchmarkStdlibWithSize(b, 56) }
func BenchmarkEncoderStdlib_128B (b *testing.B) { benchmarkStdlibWithSize(b, 128) }
func BenchmarkEncoderStdlib_4kB (b *testing.B) { benchmarkStdlibWithSize(b, 4 * 1024) }
func BenchmarkEncoderStdlib_256kB (b *testing.B) { benchmarkStdlibWithSize(b, 256 * 1024) }
func BenchmarkEncoderStdlib_1MB (b *testing.B) { benchmarkStdlibWithSize(b, 1024 * 1024) }

func BenchmarkEncoderBase64x_16B (b *testing.B) { benchmarkBase64xWithSize(b, 16) }
func BenchmarkEncoderBase64x_56B (b *testing.B) { benchmarkBase64xWithSize(b, 56) }
func BenchmarkEncoderBase64x_128B (b *testing.B) { benchmarkBase64xWithSize(b, 128) }
func BenchmarkEncoderBase64x_4kB (b *testing.B) { benchmarkBase64xWithSize(b, 4 * 1024) }
func BenchmarkEncoderBase64x_256kB (b *testing.B) { benchmarkBase64xWithSize(b, 256 * 1024) }
func BenchmarkEncoderBase64x_1MB (b *testing.B) { benchmarkBase64xWithSize(b, 1024 * 1024) }

func BenchmarkEncoderCris_16B (b *testing.B) { benchmarkCrisWithSize(b, 16) }
func BenchmarkEncoderCris_56B (b *testing.B) { benchmarkCrisWithSize(b, 56) }
func BenchmarkEncoderCris_128B (b *testing.B) { benchmarkCrisWithSize(b, 128) }
func BenchmarkEncoderCris_4kB (b *testing.B) { benchmarkCrisWithSize(b, 4 * 1024) }
func BenchmarkEncoderCris_256kB (b *testing.B) { benchmarkCrisWithSize(b, 256 * 1024) }
func BenchmarkEncoderCris_1MB (b *testing.B) { benchmarkCrisWithSize(b, 1024 * 1024) }

var data = `////////////////////////////////////////////////////////////////`
func BenchmarkDecoderStdLib (b *testing.B) { benchmarkStdlibDecoder(b, data) }
func BenchmarkDecoderBase64x (b *testing.B) { benchmarkBase64xDecoder(b, data) }
18 changes: 18 additions & 0 deletions bench/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module bench

go 1.22.0

require (
github.com/cloudwego/base64x v0.1.4
github.com/cristalhq/base64 v0.1.2
github.com/davecgh/go-spew v1.1.1
github.com/stretchr/testify v1.10.0
)

require (
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
31 changes: 31 additions & 0 deletions bench/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cristalhq/base64 v0.1.2 h1:edsefYyYDiac7Ytdh2xdaiiSSJzcI2f0yIkdGEf1qY0=
github.com/cristalhq/base64 v0.1.2/go.mod h1:sy4+2Hale2KbtSqkzpdMeYTP/IrB+HCvxVHWsh2VSYk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3z
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cristalhq/base64 v0.1.2 h1:edsefYyYDiac7Ytdh2xdaiiSSJzcI2f0yIkdGEf1qY0=
github.com/cristalhq/base64 v0.1.2/go.mod h1:sy4+2Hale2KbtSqkzpdMeYTP/IrB+HCvxVHWsh2VSYk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
Loading
Loading