Skip to content

Commit

Permalink
add performance (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
huykingsofm authored Dec 18, 2024
1 parent e5dbef1 commit e367a3c
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 18 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,30 @@ func (r Role) HasPermission() bool {
return r == RoleMod || r == RoleAdmin
}
```


## Performance

While it's true that the `xybor-x/enum` approach will generally be slower than the code generation approach, I still want to highlight the difference.

The benchmark results are based on defining an enum with 10 values at [bench](./bench).

| | `xybor-x/enum` | Code generation |
| --------------- | -------------: | --------------: |
| ToString | 17 ns | 6 ns |
| FromString | 22 ns | 15 ns |
| json.Marshal | 148 ns | 113 ns |
| json.Unmarshal | 144 ns | 147 ns |
| SQL Value | 38 ns | 29 ns |
| SQL Scan bytes | 41 ns | 29 ns |
| SQL Scan string | 22 ns | 15 ns |


## V2 roadmap

- Switch from `json.Marshaler` to `encoding.TextMarshaler` for better performance.
- New function allocates from 1 instead 0.
- Allow defining which enum supports default value or nil value.
- Remove deprecated items.

**Contributions and suggestions to refine the roadmap are welcome!**
119 changes: 119 additions & 0 deletions bench/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package bench_test

import (
"encoding/json"
"testing"

"github.com/xybor-x/enum"
"github.com/xybor-x/enum/bench"
)

func BenchmarkGen10ToString(b *testing.B) {
b.Run("Gen", func(b *testing.B) {
enum := bench.GenEnumTypeT9
for i := 0; i < b.N; i++ {
_ = enum.String()
}
})

b.Run("XyborX", func(b *testing.B) {
enum := bench.XyborEnumTypeT9
for i := 0; i < b.N; i++ {
_ = enum.String()
}
})
}

func BenchmarkGen10FromString(b *testing.B) {
b.Run("Gen", func(b *testing.B) {
for i := 0; i < b.N; i++ {
bench.ParseGenEnumType("t9")
}
})

b.Run("XyborX", func(b *testing.B) {
for i := 0; i < b.N; i++ {
enum.FromString[bench.XyborEnumType]("t9")
}
})
}

func BenchmarkGen10JsonMarshal(b *testing.B) {
b.Run("Gen", func(b *testing.B) {
enum := bench.GenEnumTypeT9
for i := 0; i < b.N; i++ {
json.Marshal(enum)
}
})

b.Run("XyborX", func(b *testing.B) {
enum := bench.XyborEnumTypeT9
for i := 0; i < b.N; i++ {
json.Marshal(enum)
}
})
}

func BenchmarkGen10JsonUnmarshal(b *testing.B) {
b.Run("Gen", func(b *testing.B) {
var enum bench.GenEnumType
for i := 0; i < b.N; i++ {
json.Unmarshal([]byte(`"t9"`), &enum)
}
})

b.Run("XyborX", func(b *testing.B) {
var enum bench.XyborEnumType
for i := 0; i < b.N; i++ {
json.Unmarshal([]byte(`"t9"`), &enum)
}
})
}

func BenchmarkGen10SqlValue(b *testing.B) {
b.Run("Gen", func(b *testing.B) {
enum := bench.GenEnumTypeT9
for i := 0; i < b.N; i++ {
enum.Value()
}
})

b.Run("XyborX", func(b *testing.B) {
enum := bench.XyborEnumTypeT9
for i := 0; i < b.N; i++ {
enum.Value()
}
})
}

func BenchmarkGen10SqlScanByte(b *testing.B) {
b.Run("Gen", func(b *testing.B) {
var enum bench.GenEnumType
for i := 0; i < b.N; i++ {
enum.Scan([]byte(`t9`))
}
})

b.Run("XyborX", func(b *testing.B) {
var enum bench.XyborEnumType
for i := 0; i < b.N; i++ {
enum.Scan([]byte(`t9`))
}
})
}

func BenchmarkSqlScanString(b *testing.B) {
b.Run("Gen", func(b *testing.B) {
var enum bench.GenEnumType
for i := 0; i < b.N; i++ {
enum.Scan("t9")
}
})

b.Run("XyborX", func(b *testing.B) {
var enum bench.XyborEnumType
for i := 0; i < b.N; i++ {
enum.Scan("t9")
}
})
}
6 changes: 6 additions & 0 deletions bench/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package bench

//go:generate go-enum --marshal --sql

// ENUM(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9)
type GenEnumType int
178 changes: 178 additions & 0 deletions bench/gen_enum.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions bench/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/xybor-x/enum/bench

go 1.22.1
Empty file added bench/go.sum
Empty file.
32 changes: 32 additions & 0 deletions bench/xybor_x_enum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package bench

import "github.com/xybor-x/enum"

type xyborEnumType int
type XyborEnumType = enum.WrapEnum[xyborEnumType]

const (
XyborEnumTypeT0 XyborEnumType = iota
XyborEnumTypeT1
XyborEnumTypeT2
XyborEnumTypeT3
XyborEnumTypeT4
XyborEnumTypeT5
XyborEnumTypeT6
XyborEnumTypeT7
XyborEnumTypeT8
XyborEnumTypeT9
)

var (
_ = enum.Map(XyborEnumTypeT0, "t0")
_ = enum.Map(XyborEnumTypeT1, "t1")
_ = enum.Map(XyborEnumTypeT2, "t2")
_ = enum.Map(XyborEnumTypeT3, "t3")
_ = enum.Map(XyborEnumTypeT4, "t4")
_ = enum.Map(XyborEnumTypeT5, "t5")
_ = enum.Map(XyborEnumTypeT6, "t6")
_ = enum.Map(XyborEnumTypeT7, "t7")
_ = enum.Map(XyborEnumTypeT8, "t8")
_ = enum.Map(XyborEnumTypeT9, "t9")
)
Loading

0 comments on commit e367a3c

Please sign in to comment.