Skip to content

Commit

Permalink
feat(bidings/go): add benchmark.
Browse files Browse the repository at this point in the history
Signed-off-by: Hanchin Hsieh <[email protected]>
  • Loading branch information
yuchanns committed Jul 14, 2024
1 parent 062a663 commit b474e1d
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 13 deletions.
90 changes: 89 additions & 1 deletion bindings/go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"os"

"github.com/yuchanns/opendal-go-services/memory"
"github.com/apache/opendal/bindings/go"
opendal "github.com/apache/opendal/bindings/go"
)

func main() {
Expand Down Expand Up @@ -89,7 +89,11 @@ func main() {

## Run Tests

### Behavior Tests

```bash
# Test a specific backend
export OPENDAL_TEST=memory
# Run all tests
CGO_ENABLE=0 go test -v -run TestBehavior
# Run specific test
Expand All @@ -98,6 +102,90 @@ CGO_ENABLE=0 go test -v -run TestBehavior/Write
CGO_ENABLE=0 GOMAXPROCS=1 go test -v -run TestBehavior
```

### Benchmark

```bash
# Benchmark a specific backend
export OPENDAL_TEST=memory

go test -bench .
```

<details>
<summary>
A benchmark between [purego+libffi](https://github.com/apache/opendal/commit/bf15cecd5e3be6ecaa7056b5594589c9f4d85673) vs [CGO](https://github.com/apache/opendal/commit/9ef494d6df2e9a13c4e5b9b03bcb36ec30c0a7c0)
</summary>

**purego+libffi** (as `new.txt`)
```
goos: linux
goarch: arm64
pkg: github.com/apache/opendal/bindings/go
BenchmarkWrite4KiB-10 1000000 2844 ns/op
BenchmarkWrite256KiB-10 163346 10092 ns/op
BenchmarkWrite4MiB-10 12900 99161 ns/op
BenchmarkWrite16MiB-10 1785 658210 ns/op
BenchmarkRead4KiB-10 194529 6387 ns/op
BenchmarkRead256KiB-10 14228 82704 ns/op
BenchmarkRead4MiB-10 981 1227872 ns/op
BenchmarkRead16MiB-10 328 3617185 ns/op
PASS
ok
```

**CGO** (as `old.txt`)
```
go test -bench=. -tags dynamic .
goos: linux
goarch: arm64
pkg: opendal.apache.org/go
BenchmarkWrite4KiB-10 241981 4240 ns/op
BenchmarkWrite256KiB-10 126464 10105 ns/op
BenchmarkWrite4MiB-10 13443 89578 ns/op
BenchmarkWrite16MiB-10 1737 646155 ns/op
BenchmarkRead4KiB-10 53535 20939 ns/op
BenchmarkRead256KiB-10 9008 132738 ns/op
BenchmarkRead4MiB-10 576 1846683 ns/op
BenchmarkRead16MiB-10 230 6305322 ns/op
PASS
ok
```

**Diff** with [benchstat](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat)
```
benchstat old.txt new.txt
goos: linux
goarch: arm64
pkg: github.com/apache/opendal/bindings/go
│ new.txt │
│ sec/op │
Write4KiB-10 2.844µ ± ∞ ¹
Write256KiB-10 10.09µ ± ∞ ¹
Write4MiB-10 99.16µ ± ∞ ¹
Write16MiB-10 658.2µ ± ∞ ¹
Read4KiB-10 6.387µ ± ∞ ¹
Read256KiB-10 82.70µ ± ∞ ¹
Read4MiB-10 1.228m ± ∞ ¹
Read16MiB-10 3.617m ± ∞ ¹
geomean 90.23µ
¹ need >= 6 samples for confidence interval at level 0.95
pkg: opendal.apache.org/go
│ old.txt │
│ sec/op │
Write4KiB-10 4.240µ ± ∞ ¹
Write256KiB-10 10.11µ ± ∞ ¹
Write4MiB-10 89.58µ ± ∞ ¹
Write16MiB-10 646.2µ ± ∞ ¹
Read4KiB-10 20.94µ ± ∞ ¹
Read256KiB-10 132.7µ ± ∞ ¹
Read4MiB-10 1.847m ± ∞ ¹
Read16MiB-10 6.305m ± ∞ ¹
geomean 129.7µ
¹ need >= 6 samples for confidence interval at level 0.95
```
</details>

## Capabilities

- [x] OperatorInfo
Expand Down
114 changes: 114 additions & 0 deletions bindings/go/benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package opendal_test

import (
"testing"

"github.com/google/uuid"
)

type Size uint64

const (
_ = iota
KiB = 1 << (10 * iota)
MiB
)

func fromKibibytes(kib uint64) Size {
return Size(kib * KiB)
}

func fromMebibytes(mib uint64) Size {
return Size(mib * MiB)
}

func (s Size) Bytes() uint64 {
return uint64(s)
}

func runBenchmarkWrite(b *testing.B, size Size) {
path := uuid.NewString()

data := genFixedBytes(uint(size.Bytes()))

b.ResetTimer()

for n := 0; n < b.N; n++ {
err := op.Write(path, data)
if err != nil {
b.Fatalf("%s", err)
}
}
}

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 runBenchmarkRead(b *testing.B, size Size) {
path := uuid.NewString()

data := genFixedBytes(uint(size.Bytes()))

err := op.Write(path, data)

if err != nil {
b.Fatalf("%s", err)
}

b.ResetTimer()

for n := 0; n < b.N; n++ {
_, err := op.Read(path)
if err != nil {
b.Fatalf("%s", err)
}
}
}

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))
}
35 changes: 23 additions & 12 deletions bindings/go/opendal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
"sync"
"testing"

"github.com/apache/opendal/bindings/go"
opendal "github.com/apache/opendal/bindings/go"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/yuchanns/opendal-go-services/aliyun_drive"
Expand All @@ -43,14 +43,27 @@ var schemes = []opendal.Scheme{
memory.Scheme,
}

var op *opendal.Operator

func TestMain(m *testing.M) {
var (
closeFunc func()
err error
)
op, closeFunc, err = newOperator()
if err != nil {
panic(err)
}
defer closeFunc()

m.Run()
}

type behaviorTest = func(assert *require.Assertions, op *opendal.Operator, fixture *fixture)

func TestBehavior(t *testing.T) {
assert := require.New(t)

op, closeFunc, err := newOperator()
assert.Nil(err)

cap := op.Info().GetFullCapability()

var tests []behaviorTest
Expand All @@ -68,11 +81,6 @@ func TestBehavior(t *testing.T) {

t.Cleanup(func() {
fixture.Cleanup(assert)
op.Close()

if closeFunc != nil {
closeFunc()
}
})

for i := range tests {
Expand Down Expand Up @@ -104,9 +112,6 @@ func newOperator() (op *opendal.Operator, closeFunc func(), err error) {
if err != nil {
return
}
closeFunc = func() {
os.Remove(s.Path())
}
scheme = s
break
}
Expand Down Expand Up @@ -136,6 +141,12 @@ func newOperator() (op *opendal.Operator, closeFunc func(), err error) {
err = fmt.Errorf("create operator must succeed: %s", err)
}

closeFunc = func() {
op.Close()

os.Remove(scheme.Path())
}

return
}

Expand Down

0 comments on commit b474e1d

Please sign in to comment.