This is an automated email from the ASF dual-hosted git repository. yuchanns pushed a commit to branch benchmark-go-binding in repository https://gitbox.apache.org/repos/asf/opendal.git
commit bd71aa13b25fa7770903dde01a8b01654e8e47d9 Author: Hanchin Hsieh <m...@yuchanns.xyz> AuthorDate: Sat Jun 28 18:38:59 2025 +0800 feat(bindings/go): add comprehensive benchmark testing with Makefile target and CI integration - Add 'bench' target to Go bindings Makefile for running performance benchmarks - Enhance benchmark tests to compare OpenDAL performance against AWS S3 SDK - Integrate benchmark execution into CI pipeline for S3 service testing - Update help documentation to include new benchmark target usage examples --- .../actions/test_behavior_binding_go/action.yaml | 3 + bindings/go/Makefile | 13 +- bindings/go/tests/behavior_tests/benchmark_test.go | 150 ++++++++++++++++----- bindings/go/tests/behavior_tests/go.mod | 4 + bindings/go/tests/behavior_tests/go.sum | 14 +- bindings/go/tests/behavior_tests/scheme_test.go | 3 +- 6 files changed, 151 insertions(+), 36 deletions(-) diff --git a/.github/actions/test_behavior_binding_go/action.yaml b/.github/actions/test_behavior_binding_go/action.yaml index 21c9ef7e5..3f48d5674 100644 --- a/.github/actions/test_behavior_binding_go/action.yaml +++ b/.github/actions/test_behavior_binding_go/action.yaml @@ -47,6 +47,9 @@ runs: fi cp bindings/go/Makefile . make tests + if [ "${{ inputs.setup }}" == "0_minio_s3"]; then + make bench + fi env: OPENDAL_TEST: ${{ inputs.service }} CGO_ENABLE: 0 diff --git a/bindings/go/Makefile b/bindings/go/Makefile index a415bc058..094b9356d 100644 --- a/bindings/go/Makefile +++ b/bindings/go/Makefile @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -.PHONY: tests clean help check-env generate-services run-tests +.PHONY: tests bench clean help check-env generate-services run-tests run-bench # Detect current OS and architecture OS := $(shell uname -s | tr '[:upper:]' '[:lower:]') @@ -139,10 +139,19 @@ run-tests: generate-services @echo "Running behavior tests..." go test ./opendal/bindings/go/tests/behavior_tests -v -run TestBehavior +# Run benchmarks +run-bench: generate-services + @echo "Running benchmark tests..." + go test ./opendal/bindings/go/tests/behavior_tests -v -bench=. -run=^$$ -count=6 -benchmem + # Main target: run all tests tests: check-env run-tests @echo "All tests completed successfully!" +# Main target: run benchmarks only +bench: check-env run-bench + @echo "All benchmarks completed successfully!" + # Clean all generated files clean: @echo "Cleaning all generated files..." @@ -157,6 +166,7 @@ clean: help: @echo "Available targets:" @echo " tests - Run all tests (requires OPENDAL_TEST environment variable)" + @echo " bench - Run benchmarks only (requires OPENDAL_TEST environment variable)" @echo " clean - Clean all generated files" @echo " help - Show this help message" @echo "" @@ -165,4 +175,5 @@ help: @echo "" @echo "Example usage:" @echo " OPENDAL_TEST=fs make tests" + @echo " OPENDAL_TEST=fs make bench" diff --git a/bindings/go/tests/behavior_tests/benchmark_test.go b/bindings/go/tests/behavior_tests/benchmark_test.go index f38dabc5a..2becdc3b3 100644 --- a/bindings/go/tests/behavior_tests/benchmark_test.go +++ b/bindings/go/tests/behavior_tests/benchmark_test.go @@ -20,8 +20,17 @@ package opendal_test import ( + "bytes" + "fmt" + "io" + "os" "testing" + opendal "github.com/apache/opendal/bindings/go" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" "github.com/google/uuid" ) @@ -45,7 +54,92 @@ func (s Size) Bytes() uint64 { return uint64(s) } -func runBenchmarkWrite(b *testing.B, size Size) { +func (s Size) String() string { + switch { + case s >= MiB: + return fmt.Sprintf("%dMiB", s.Bytes()/MiB) + case s >= KiB: + return fmt.Sprintf("%dKiB", s.Bytes()/KiB) + default: + return fmt.Sprintf("%dB", s.Bytes()) + } +} + +var sizes = []Size{ + fromKibibytes(4), + fromKibibytes(256), + fromMebibytes(4), + fromMebibytes(16), +} + +type ReadWriter interface { + Write(path string, data []byte) error + Read(path string) ([]byte, error) + + Name() string +} + +type S3ReadWriter struct { + client *s3.S3 +} + +func NewS3ReadWriter() ReadWriter { + s3 := s3.New(session.Must(session.NewSession(&aws.Config{ + Credentials: credentials.NewStaticCredentials(os.Getenv("OPENDAL_S3_ACCESS_KEY_ID"), os.Getenv("OPENDAL_S3_SECRET_ACCESS_KEY"), ""), + Endpoint: aws.String(os.Getenv("OPENDAL_S3_ENDPOINT")), + Region: aws.String(os.Getenv("OPENDAL_S3_BUCKET")), + DisableSSL: aws.Bool(true), + }))) + return &S3ReadWriter{ + client: s3, + } +} + +func (rw *S3ReadWriter) Write(path string, data []byte) error { + _, err := rw.client.PutObject(&s3.PutObjectInput{ + Bucket: aws.String(os.Getenv("OPENDAL_S3_BUCKET")), + Key: aws.String(path), + Body: aws.ReadSeekCloser(bytes.NewReader(data)), + }) + return err +} + +func (rw *S3ReadWriter) Read(path string) ([]byte, error) { + resp, err := rw.client.GetObject(&s3.GetObjectInput{ + Bucket: aws.String(os.Getenv("OPENDAL_S3_BUCKET")), + Key: aws.String(path), + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return data, nil +} + +func (rw *S3ReadWriter) Name() string { + return "AWS S3" +} + +type OpenDALReadWriter struct { + *opendal.Operator +} + +func NewOpenDALReadWriter(op *opendal.Operator) ReadWriter { + return &OpenDALReadWriter{ + Operator: op, + } +} + +func (rw *OpenDALReadWriter) Name() string { + return "OpenDAL" +} + +func runBenchmarkWrite(b *testing.B, size Size, op ReadWriter) { path := uuid.NewString() data := genFixedBytes(uint(size.Bytes())) @@ -60,23 +154,21 @@ func runBenchmarkWrite(b *testing.B, size Size) { } } -func BenchmarkWrite4KiB(b *testing.B) { - runBenchmarkWrite(b, fromKibibytes(4)) -} - -func BenchmarkWrite256KiB(b *testing.B) { - runBenchmarkWrite(b, fromKibibytes(256)) -} - -func BenchmarkWrite4MiB(b *testing.B) { - runBenchmarkWrite(b, fromMebibytes(4)) -} - -func BenchmarkWrite16MiB(b *testing.B) { - runBenchmarkWrite(b, fromMebibytes(16)) +func BenchmarkWrite(b *testing.B) { + var ops = []ReadWriter{NewOpenDALReadWriter(op)} + if os.Getenv("OPENDAL_TEST") == "s3" { + ops = append(ops, NewS3ReadWriter()) + } + for _, size := range sizes { + for _, op := range ops { + b.Run(fmt.Sprintf("%s/%s", size, op.Name()), func(b *testing.B) { + runBenchmarkWrite(b, size, op) + }) + } + } } -func runBenchmarkRead(b *testing.B, size Size) { +func runBenchmarkRead(b *testing.B, size Size, op ReadWriter) { path := uuid.NewString() data := genFixedBytes(uint(size.Bytes())) @@ -97,18 +189,16 @@ func runBenchmarkRead(b *testing.B, size Size) { } } -func BenchmarkRead4KiB(b *testing.B) { - runBenchmarkRead(b, fromKibibytes(4)) -} - -func BenchmarkRead256KiB(b *testing.B) { - runBenchmarkRead(b, fromKibibytes(256)) -} - -func BenchmarkRead4MiB(b *testing.B) { - runBenchmarkRead(b, fromMebibytes(4)) -} - -func BenchmarkRead16MiB(b *testing.B) { - runBenchmarkRead(b, fromMebibytes(16)) +func BenchmarkRead(b *testing.B) { + var ops = []ReadWriter{NewOpenDALReadWriter(op)} + if os.Getenv("OPENDAL_TEST") == "s3" { + ops = append(ops, NewS3ReadWriter()) + } + for _, size := range sizes { + for _, op := range ops { + b.Run(fmt.Sprintf("%s/%s", size, op.Name()), func(b *testing.B) { + runBenchmarkRead(b, size, op) + }) + } + } } diff --git a/bindings/go/tests/behavior_tests/go.mod b/bindings/go/tests/behavior_tests/go.mod index fcaba00ec..e6662c2f3 100644 --- a/bindings/go/tests/behavior_tests/go.mod +++ b/bindings/go/tests/behavior_tests/go.mod @@ -22,6 +22,7 @@ go 1.22.5 require ( github.com/apache/opendal-go-services/fs v0.1.3 github.com/apache/opendal/bindings/go v0.0.0-20240719044908-d9d4279b3a24 + github.com/aws/aws-sdk-go v1.55.7 github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.9.0 ) @@ -29,9 +30,12 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.7.1 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jupiterrider/ffi v0.1.0-beta.9 // indirect github.com/klauspost/compress v1.17.10 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/sys v0.22.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/apache/opendal-go-services/fs => /Users/yuchanns/Coding/github/opendal_workspace/opendal-go-services/fs diff --git a/bindings/go/tests/behavior_tests/go.sum b/bindings/go/tests/behavior_tests/go.sum index d9f6957f1..c1473d33c 100644 --- a/bindings/go/tests/behavior_tests/go.sum +++ b/bindings/go/tests/behavior_tests/go.sum @@ -1,21 +1,25 @@ -github.com/apache/opendal-go-services/fs v0.1.3 h1:k5pA73gKbQ3MHH2envsKhr1cec2spLm2tl/bCyU53j8= -github.com/apache/opendal-go-services/fs v0.1.3/go.mod h1:7EnuyeXRuQh+L47rZ7y2OrhYJLlUYvgvFPItM98XJ5s= -github.com/apache/opendal-go-services/memory v0.1.3 h1:lUe4n4Y9AmwS6a1KV/ZTLyWLtWpRSSuNZHchcW2s+LQ= -github.com/apache/opendal-go-services/memory v0.1.3/go.mod h1:vldOQuikErKA1wfGnqvjAYB9MON/PWTuFIulMCKIQqM= github.com/apache/opendal/bindings/go v0.0.0-20240719044908-d9d4279b3a24 h1:2fAl+WS/lZMTtP6onlrmDbb3pltf+5xNTc0Aeu9nYWE= github.com/apache/opendal/bindings/go v0.0.0-20240719044908-d9d4279b3a24/go.mod h1:jyMN6M6h0jMDZitnjvB3KPobM+oZiESrFb3XUplLxhI= +github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= +github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +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/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jupiterrider/ffi v0.1.0-beta.9 h1:HCeAPTsTFgwvcfavyJwy1L2ANz0c85W+ZE7LfzjZi3A= github.com/jupiterrider/ffi v0.1.0-beta.9/go.mod h1:sOp6VJGFaYyr4APi8gwy6g20QNHv5F8Iq1CVbtC900s= github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= 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/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuchanns/opendal-go-services v0.0.1 h1:qeKv0mOhypQNm97g+u94DnijJK5bdEAp5pdjBGf8N7w= @@ -24,5 +28,7 @@ golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/bindings/go/tests/behavior_tests/scheme_test.go b/bindings/go/tests/behavior_tests/scheme_test.go index 7702e1517..54134d8a0 100644 --- a/bindings/go/tests/behavior_tests/scheme_test.go +++ b/bindings/go/tests/behavior_tests/scheme_test.go @@ -16,12 +16,13 @@ * specific language governing permissions and limitations * under the License. */ +// generated by github.com/apache/opendal/bindings/go package opendal_test import ( - "github.com/apache/opendal-go-services/fs" opendal "github.com/apache/opendal/bindings/go" + "github.com/apache/opendal-go-services/fs" ) // Add more schemes for behavior tests here.