From 023d47dc6b253e1fadecd3564b0690a8bd8cf7c3 Mon Sep 17 00:00:00 2001 From: Will Roden Date: Thu, 9 Nov 2023 13:42:37 -0600 Subject: [PATCH] refactor go --- base64/Makefile | 14 +-- base64/go.mod | 12 --- base64/go/base64/test.go | 13 +++ base64/go/base64x/test-base64x.go | 13 +++ base64/go/benchmark.go | 85 +++++++++++++++++ base64/go/go.mod | 18 ++++ base64/{ => go}/go.sum | 16 +++- base64/test-base64x.go | 72 -------------- base64/test.go | 71 -------------- brainfuck/Makefile | 8 +- brainfuck/go/benchmark.go | 64 +++++++++++++ brainfuck/{ => go/bf}/bf.go | 63 +++---------- brainfuck/go/go.mod | 7 ++ common/commands.mk | 26 ++++-- common/go/common.go | 73 +++++++++++++++ common/go/go.mod | 3 + json/Makefile | 32 +------ json/go.mod | 20 ---- json/go/benchmark.go | 71 ++++++++++++++ json/go/go.mod | 24 +++++ json/{ => go}/go.sum | 21 +++-- json/go/goccy/test_goccy.go | 22 +++++ json/go/json/test.go | 22 +++++ json/go/jsoniter/test_jsoniter.go | 24 +++++ .../rjson-custom}/test_rjson_custom.go | 52 +++-------- json/go/rjson/test_rjson.go | 48 ++++++++++ json/go/sonic/test_sonic.go | 22 +++++ json/test.go | 66 ------------- json/test_goccy.go | 65 ------------- json/test_jsoniter.go | 74 --------------- json/test_rjson.go | 93 ------------------- json/test_sonic.go | 66 ------------- matmul/Makefile | 9 +- matmul/go/benchmark.go | 34 +++++++ matmul/go/go.mod | 9 ++ matmul/{ => go/matmul}/matmul.go | 39 +++----- primes/Makefile | 5 +- 37 files changed, 648 insertions(+), 728 deletions(-) delete mode 100644 base64/go.mod create mode 100644 base64/go/base64/test.go create mode 100644 base64/go/base64x/test-base64x.go create mode 100644 base64/go/benchmark.go create mode 100644 base64/go/go.mod rename base64/{ => go}/go.sum (76%) delete mode 100644 base64/test-base64x.go delete mode 100644 base64/test.go create mode 100644 brainfuck/go/benchmark.go rename brainfuck/{ => go/bf}/bf.go (67%) create mode 100644 brainfuck/go/go.mod create mode 100644 common/go/common.go create mode 100644 common/go/go.mod delete mode 100644 json/go.mod create mode 100644 json/go/benchmark.go create mode 100644 json/go/go.mod rename json/{ => go}/go.sum (78%) create mode 100644 json/go/goccy/test_goccy.go create mode 100644 json/go/json/test.go create mode 100644 json/go/jsoniter/test_jsoniter.go rename json/{ => go/rjson-custom}/test_rjson_custom.go (57%) create mode 100644 json/go/rjson/test_rjson.go create mode 100644 json/go/sonic/test_sonic.go delete mode 100644 json/test.go delete mode 100644 json/test_goccy.go delete mode 100644 json/test_jsoniter.go delete mode 100644 json/test_rjson.go delete mode 100644 json/test_sonic.go create mode 100644 matmul/go/benchmark.go create mode 100644 matmul/go/go.mod rename matmul/{ => go/matmul}/matmul.go (65%) diff --git a/base64/Makefile b/base64/Makefile index 0cd443af..470cd7eb 100644 --- a/base64/Makefile +++ b/base64/Makefile @@ -3,8 +3,7 @@ include ../common/commands.mk executables := \ target/base64_cr \ - target/base64_go \ - target/base64_go_base64x \ + $(GO_TARGETS) \ target/base64_go_gccgo \ target/base64_cpp_gcc_crypto \ target/base64_cpp_clang_crypto \ @@ -56,14 +55,7 @@ build: $(artifacts) target/base64_cr: test.cr | target $(CRYSTAL_BUILD) -target/base64_go: test.go | $(gofmt) - $(GO_BUILD) - -target/base64_go_base64x: test-base64x.go | $(gofmt) - go mod tidy - $(GO_BUILD) - -target/base64_go_gccgo: test.go | $(gofmt) +target/base64_go_gccgo: go/base64 $(GO_SOURCE) | gofmt $(GCC_GO_BUILD) target/base64_cpp_gcc_crypto: test-crypto.cpp | target libnotify @@ -225,7 +217,7 @@ run[test.rkt]:: run[%]: % # Utilities .PHONY: clean -clean: +clean: clean-go if [ -d $(aklomp-base64-dir) ]; then \ $(MAKE) -C $(aklomp-base64-dir) clean; \ fi diff --git a/base64/go.mod b/base64/go.mod deleted file mode 100644 index d4c873ba..00000000 --- a/base64/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module base64 - -go 1.21.3 - -require github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d - -require ( - github.com/bytedance/sonic v1.10.1 // indirect - github.com/chenzhuoyu/iasm v0.9.0 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect -) diff --git a/base64/go/base64/test.go b/base64/go/base64/test.go new file mode 100644 index 00000000..60e4e7ac --- /dev/null +++ b/base64/go/base64/test.go @@ -0,0 +1,13 @@ +package main + +import ( + "benchmark" + "encoding/base64" +) + +func main() { + err := benchmark.Run("", base64.StdEncoding) + if err != nil { + panic(err) + } +} diff --git a/base64/go/base64x/test-base64x.go b/base64/go/base64x/test-base64x.go new file mode 100644 index 00000000..2746bad5 --- /dev/null +++ b/base64/go/base64x/test-base64x.go @@ -0,0 +1,13 @@ +package main + +import ( + "benchmark" + "github.com/chenzhuoyu/base64x" +) + +func main() { + err := benchmark.Run("base64x", base64x.StdEncoding) + if err != nil { + panic(err) + } +} diff --git a/base64/go/benchmark.go b/base64/go/benchmark.go new file mode 100644 index 00000000..ebe36977 --- /dev/null +++ b/base64/go/benchmark.go @@ -0,0 +1,85 @@ +package benchmark + +import ( + "fmt" + "strings" + "time" + + "benchmarks/common" +) + +const ( + strSize = 131_072 + tries = 8_192 +) + +type Encoding interface { + EncodeToString([]byte) string + DecodeString(string) ([]byte, error) +} + +func verify(encoding Encoding) error { + for _, fixture := range [][]string{ + {"hello", "aGVsbG8="}, + {"world", "d29ybGQ="}, + } { + src := fixture[0] + dst := fixture[1] + encoded := encoding.EncodeToString([]byte(src)) + if encoded != dst { + return fmt.Errorf("%+v != %+v\n", encoded, dst) + } + decoded, err := encoding.DecodeString(dst) + if err != nil { + return err + } + if string(decoded) != src { + return fmt.Errorf("%+v != %+v\n", decoded, src) + } + } + return nil +} + +func Run(name string, encoding Encoding) error { + err := verify(encoding) + if err != nil { + return err + } + + bytes := []byte(strings.Repeat("a", strSize)) + str2 := encoding.EncodeToString(bytes) + str3, err := encoding.DecodeString(str2) + if err != nil { + return err + } + + var encStart, encEnd, decStart, decEnd time.Time + sizeEncoded, sizeDecoded := 0, 0 + + err = common.RunBenchmark(name, func() { + encStart = time.Now() + for i := 0; i < tries; i += 1 { + sizeEncoded += len(encoding.EncodeToString(bytes)) + } + encEnd = time.Now() + + decStart = time.Now() + for i := 0; i < tries; i += 1 { + decoded, err := encoding.DecodeString(str2) + if err != nil { + return + } + sizeDecoded += len(decoded) + } + decEnd = time.Now() + }) + if err != nil { + return err + } + fmt.Printf("encode %s... to %s...: %d, %.4f\n", + string(bytes[:4]), str2[:4], sizeEncoded, encEnd.Sub(encStart).Seconds()) + fmt.Printf("decode %s... to %s...: %d, %.4f\n", + str2[:4], string(str3[:4]), sizeDecoded, decEnd.Sub(decStart).Seconds()) + + return nil +} diff --git a/base64/go/go.mod b/base64/go/go.mod new file mode 100644 index 00000000..b8b13c72 --- /dev/null +++ b/base64/go/go.mod @@ -0,0 +1,18 @@ +module benchmark + +go 1.21 + +require ( + benchmarks/common v0.0.0-00010101000000-000000000000 + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d +) + +require ( + github.com/bytedance/sonic v1.10.2 // indirect + github.com/chenzhuoyu/iasm v0.9.1 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/sys v0.14.0 // indirect +) + +replace benchmarks/common => ../../common/go diff --git a/base64/go.sum b/base64/go/go.sum similarity index 76% rename from base64/go.sum rename to base64/go/go.sum index db98965d..a5585ff4 100644 --- a/base64/go.sum +++ b/base64/go/go.sum @@ -1,18 +1,20 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= -github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= +github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= +github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= 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/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 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= @@ -25,8 +27,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= diff --git a/base64/test-base64x.go b/base64/test-base64x.go deleted file mode 100644 index efb01ebb..00000000 --- a/base64/test-base64x.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net" - "os" - "runtime" - "strings" - "time" - - "github.com/chenzhuoyu/base64x" -) - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func main() { - coder := base64x.StdEncoding - - for _, fixture := range [][]string{ - {"hello", "aGVsbG8="}, - {"world", "d29ybGQ="}, - } { - src := fixture[0] - dst := fixture[1] - encoded := coder.EncodeToString([]byte(src)) - if encoded != dst { - log.Fatalf("%+v != %+v\n", encoded, dst) - } - decoded, _ := coder.DecodeString(dst) - if string(decoded) != src { - log.Fatalf("%+v != %+v\n", decoded, src) - } - } - - STR_SIZE := 131072 - TRIES := 8192 - - bytes := []byte(strings.Repeat("a", STR_SIZE)) - str2 := coder.EncodeToString(bytes) - str3, _ := coder.DecodeString(str2) - - notify(fmt.Sprintf("%s\t%d", runtime.Compiler, os.Getpid())) - - t := time.Now() - s_encoded := 0 - for i := 0; i < TRIES; i += 1 { - s_encoded += len(coder.EncodeToString(bytes)) - } - t_encoded := time.Since(t).Seconds() - - t1 := time.Now() - s_decoded := 0 - for i := 0; i < TRIES; i += 1 { - decoded, _ := coder.DecodeString(str2) - s_decoded += len(decoded) - } - t_decoded := time.Since(t1).Seconds() - - notify("stop") - - fmt.Printf("encode %s... to %s...: %d, %.4f\n", - string(bytes[:4]), str2[:4], s_encoded, t_encoded) - fmt.Printf("decode %s... to %s...: %d, %.4f\n", - str2[:4], string(str3[:4]), s_decoded, t_decoded) -} diff --git a/base64/test.go b/base64/test.go deleted file mode 100644 index 30d41b36..00000000 --- a/base64/test.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "encoding/base64" - "fmt" - "log" - "net" - "os" - "runtime" - "strings" - "time" -) - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func main() { - coder := base64.StdEncoding - - for _, fixture := range [][]string{ - {"hello", "aGVsbG8="}, - {"world", "d29ybGQ="}, - } { - src := fixture[0] - dst := fixture[1] - encoded := coder.EncodeToString([]byte(src)) - if encoded != dst { - log.Fatalf("%+v != %+v\n", encoded, dst) - } - decoded, _ := coder.DecodeString(dst) - if string(decoded) != src { - log.Fatalf("%+v != %+v\n", decoded, src) - } - } - - STR_SIZE := 131072 - TRIES := 8192 - - bytes := []byte(strings.Repeat("a", STR_SIZE)) - str2 := coder.EncodeToString(bytes) - str3, _ := coder.DecodeString(str2) - - notify(fmt.Sprintf("%s\t%d", runtime.Compiler, os.Getpid())) - - t := time.Now() - s_encoded := 0 - for i := 0; i < TRIES; i += 1 { - s_encoded += len(coder.EncodeToString(bytes)) - } - t_encoded := time.Since(t).Seconds() - - t1 := time.Now() - s_decoded := 0 - for i := 0; i < TRIES; i += 1 { - decoded, _ := coder.DecodeString(str2) - s_decoded += len(decoded) - } - t_decoded := time.Since(t1).Seconds() - - notify("stop") - - fmt.Printf("encode %s... to %s...: %d, %.4f\n", - string(bytes[:4]), str2[:4], s_encoded, t_encoded) - fmt.Printf("decode %s... to %s...: %d, %.4f\n", - str2[:4], string(str3[:4]), s_decoded, t_decoded) -} diff --git a/brainfuck/Makefile b/brainfuck/Makefile index 04125318..5f4fbee5 100644 --- a/brainfuck/Makefile +++ b/brainfuck/Makefile @@ -18,6 +18,7 @@ executables := \ target/bin_hs_marray \ target/bin_ocaml \ target/bin_go \ + $(GO_TARGETS) \ target/bin_go_gccgo \ target/bin_vala_gcc \ target/bin_vala_clang \ @@ -103,10 +104,7 @@ fsharp/target/Release/net7.0/brainfuck: fsharp/brainfuck.fsproj | target target/bf2-kt.jar: bf2.kt | target $(KOTLINC_BUILD) -target/bin_go: bf.go | target - $(GO_BUILD) - -target/bin_go_gccgo: bf.go | target +target/bin_go_gccgo: go/bf $(GO_SOURCE) | gofmt $(GCC_GO_BUILD) target/bin_d: bf.d | $(dfmt) @@ -257,7 +255,7 @@ run[bf.php]:: run[%]: % # Utilities .PHONY: clean -clean: +clean: clean-go $(DOTNET_CLEAN) fsharp/brainfuck.fsproj -rm -rf target -rm -rf zig-cache diff --git a/brainfuck/go/benchmark.go b/brainfuck/go/benchmark.go new file mode 100644 index 00000000..436c9a0e --- /dev/null +++ b/brainfuck/go/benchmark.go @@ -0,0 +1,64 @@ +package benchmark + +import ( + "benchmarks/common" + "fmt" + "os" +) + +type Printer interface { + Reset(quiet bool) + Print(int) + GetChecksum() int +} + +type runFunc func(string, Printer) + +func verify(runProgram runFunc, printer Printer) error { + const input = `++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> +---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.` + const want = "Hello World!\n" + + printer.Reset(true) + runProgram(input, printer) + left := printer.GetChecksum() + + printer.Reset(true) + for _, c := range want { + printer.Print(int(c)) + } + right := printer.GetChecksum() + + if left != right { + return fmt.Errorf("%+v != %+v\n", left, right) + } + return nil +} + +func Run(runProgram runFunc, printer Printer) error { + err := verify(runProgram, printer) + if err != nil { + return err + } + + code, err := os.ReadFile(os.Args[1]) + if err != nil { + return err + } + text := string(code) + + _, quiet := os.LookupEnv("QUIET") + printer.Reset(quiet) + + err = common.RunBenchmark("", func() { + runProgram(text, printer) + }) + if err != nil { + return err + } + + if quiet { + fmt.Printf("Output checksum: %d\n", printer.GetChecksum()) + } + return nil +} diff --git a/brainfuck/bf.go b/brainfuck/go/bf/bf.go similarity index 67% rename from brainfuck/bf.go rename to brainfuck/go/bf/bf.go index 63ab9344..9316c040 100644 --- a/brainfuck/bf.go +++ b/brainfuck/go/bf/bf.go @@ -1,12 +1,8 @@ package main import ( + "benchmark" "fmt" - "io/ioutil" - "net" - "os" - "runtime" - "log" ) const ( @@ -77,8 +73,8 @@ func (t *Tape) Get() int { } type Printer struct { - sum1 int - sum2 int + sum1 int + sum2 int quiet bool } @@ -99,6 +95,12 @@ func (p *Printer) GetChecksum() int { return (p.sum2 << 8) | p.sum1 } +func (p *Printer) Reset(quiet bool) { + p.sum1 = 0 + p.sum2 = 0 + p.quiet = quiet +} + type Program struct { Ops []Op } @@ -107,7 +109,7 @@ func NewProgram(code string) *Program { return &Program{Ops: parse(NewStringIterator(code))} } -func (p *Program) Run(printer *Printer) { +func (p *Program) Run(printer benchmark.Printer) { _run(p.Ops, NewTape(), printer) } @@ -138,10 +140,9 @@ func parse(si *StringIterator) []Op { } res = append(res, op) } - return res } -func _run(program []Op, tape *Tape, p *Printer) { +func _run(program []Op, tape *Tape, p benchmark.Printer) { for i := 0; i < len(program); i++ { switch program[i].O { case INC: @@ -158,45 +159,11 @@ func _run(program []Op, tape *Tape, p *Printer) { } } -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func verify() { - text := `++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> ----.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.` - p_left := NewPrinter(true) - NewProgram(text).Run(p_left) - left := p_left.GetChecksum() - - p_right := NewPrinter(true) - for _, c := range "Hello World!\n" { - p_right.Print(int(c)) - } - right := p_right.GetChecksum() - if left != right { - log.Fatalf("%+v != %+v\n", left, right) - } -} - func main() { - verify() - code, err := ioutil.ReadFile(os.Args[1]) + err := benchmark.Run(func(s string, printer benchmark.Printer) { + NewProgram(s).Run(printer) + }, NewPrinter(true)) if err != nil { - panic(fmt.Sprintf("%v", err)) - } - text := string(code) - p := NewPrinter(os.Getenv("QUIET") != "") - - notify(fmt.Sprintf("%s\t%d", runtime.Compiler, os.Getpid())) - NewProgram(text).Run(p) - notify("stop") - - if p.quiet { - fmt.Printf("Output checksum: %d\n", p.GetChecksum()) + panic(err) } } diff --git a/brainfuck/go/go.mod b/brainfuck/go/go.mod new file mode 100644 index 00000000..7c90f10e --- /dev/null +++ b/brainfuck/go/go.mod @@ -0,0 +1,7 @@ +module benchmark + +go 1.21 + +require benchmarks/common v0.0.0-00010101000000-000000000000 + +replace benchmarks/common => ../../common/go diff --git a/common/commands.mk b/common/commands.mk index 9314c844..00ee5ac8 100644 --- a/common/commands.mk +++ b/common/commands.mk @@ -17,10 +17,11 @@ DOTNET_BUILD = dotnet build --nologo -v q $< -c Release DUB_BUILD = dub -q build --build=release-nobounds --compiler=ldc2 --single $^ GCC_BUILD = gcc $(GCC_FLAGS) -std=c2x -o $@ $^ $(LIBNOTIFY_FLAGS) GCC_CPP_BUILD = g++ $(GCC_FLAGS) -std=c++23 -o $@ $^ $(LIBNOTIFY_FLAGS) -GCC_GO_BUILD = gccgo $(GCC_FLAGS) -o $@ $^ +GCC_GO_BUILD = go build -C $< -compiler gccgo -gccgoflags="$(GCC_FLAGS)" -o $(abspath $@) . GDC_BUILD = gdc -o $@ -O3 -frelease -finline -fbounds-check=off $^ GHC_BUILD = ghc -v0 -O2 -fforce-recomp -Wall $^ -o $@ -outputdir $(@D) -GO_BUILD = GO111MODULE=auto go build -o $@ $^ +GO_BUILD = go build -C $(dir $(@D)) -ldflags="-s -w" -o $(abspath $@) . +GO_SUM = go -C $(@D) mod tidy && go -C $(@D) get -u ./... && touch $@ JAVAC_BUILD = javac --release 21 -Xlint:unchecked -d $(@D) $^ KOTLINC_BUILD = kotlinc -include-runtime -jvm-target 20 -d $@ $^ LDC2_BUILD = ldc2 -of$@ -O5 -release -boundscheck=off $^ @@ -95,10 +96,23 @@ $(julia_fmt): *.jl | target ../common/julia/julia_fmt.jl $^ @touch $@ -gofmt := target/.gofmt -$(gofmt): *.go | target - gofmt -s -w $^ - @touch $@ +.PHONY: gofmt +gofmt: + gofmt -s -w . + +GO_SOURCE = $(wildcard go/* go/*/*.go ../common/go/*) + +go/go.sum: $(filter-out go/go.sum, $(GO_SOURCE)) + $(GO_SUM) + +GO_TARGETS := $(patsubst %/,%/target/benchmark, $(shell ls -d go/*/)) + +$(GO_TARGETS): $(GO_SOURCE) | gofmt + $(GO_BUILD) + +.PHONY: clean-go +clean-go: + -rm -rf go/*/target rubocop := target/.rubocop $(rubocop): *.rb | target diff --git a/common/go/common.go b/common/go/common.go new file mode 100644 index 00000000..0d5e439d --- /dev/null +++ b/common/go/common.go @@ -0,0 +1,73 @@ +package common + +import ( + "errors" + "fmt" + "net" + "os" + "runtime" +) + +// creates a TCP connection to port 9001 +func createConn() (*net.TCPConn, error) { + notifyAddr := &net.TCPAddr{Port: 9001} + conn, err := net.DialTCP("tcp", nil, notifyAddr) + if err != nil { + var e *net.OpError + if errors.As(err, &e) && e.Op == "dial" { + return nil, nil + } + return nil, err + } + return conn, nil +} + +func benchName(sub string) string { + name := "Go" + if runtime.Compiler != "gc" { + name += "/" + runtime.Compiler + } + if sub != "" { + name += " (" + sub + ")" + } + return name +} + +// RunBenchmark runs the benchmark function and notifies xtime of the start and stop. +func RunBenchmark(name string, benchmark func()) error { + startConn, err := createConn() + if err != nil { + return err + } + stopConn, err := createConn() + if err != nil { + return err + } + startMsg := []byte(fmt.Sprintf("%s\t%d\n", benchName(name), os.Getpid())) + stopMsg := []byte("stop") + + if startConn != nil { + _, err = startConn.Write(startMsg) + if err != nil { + return err + } + err = startConn.Close() + if err != nil { + return err + } + } + + benchmark() + + if stopConn != nil { + _, err = stopConn.Write(stopMsg) + if err != nil { + return err + } + err = stopConn.Close() + if err != nil { + return err + } + } + return nil +} diff --git a/common/go/go.mod b/common/go/go.mod new file mode 100644 index 00000000..a8297296 --- /dev/null +++ b/common/go/go.mod @@ -0,0 +1,3 @@ +module benchmarks/common + +go 1.21 diff --git a/json/Makefile b/json/Makefile index dca7021a..8809cc34 100644 --- a/json/Makefile +++ b/json/Makefile @@ -14,6 +14,7 @@ executables := \ target/json_pull_cr \ target/json_schema_cr \ $(json-rs-targets) \ + $(GO_TARGETS) \ target/json_d \ target/json_d_gdc \ target/json_d_ldc \ @@ -153,10 +154,7 @@ target/jsony_nim_gcc: test_jsony.nim | target jsony target/jsony_nim_clang: test_jsony.nim | target jsony $(NIM_CLANG_BUILD) -target/json_go: test.go | $(gofmt) - $(GO_BUILD) - -target/json_go_gccgo: test.go | $(gofmt) +target/json_go_gccgo: go/json $(GO_SOURCE) | gofmt $(GCC_GO_BUILD) # NOTE: quite time consuming @@ -326,30 +324,6 @@ target/json_vala_gcc: test.vala | target target/json_vala_clang: test.vala | target $(VALAC_CLANG_BUILD) --pkg json-glib-1.0 -.PHONY: json-iterator -json-iterator: - GO111MODULE=auto go get github.com/json-iterator/go - -target/json_iter_go: test_jsoniter.go | json-iterator - $(GO_BUILD) - -.PHONY: goccy -goccy: - GO111MODULE=auto go get github.com/goccy/go-json - -target/json_goccy: test_goccy.go | goccy - $(GO_BUILD) - -target/json_sonic: test_sonic.go | $(gofmt) - go mod tidy - $(GO_BUILD) - -target/json_rjson: test_rjson.go - $(GO_BUILD) - -target/json_rjson_custom: test_rjson_custom.go - $(GO_BUILD) - json-fsharp/target/Release/net7.0/json-fsharp: json-fsharp/json-fsharp.fsproj json-fsharp/Program.fs $(DOTNET_BUILD) @@ -451,7 +425,7 @@ run[test.rkt]:: run[%]: % # Utilities .PHONY: clean -clean: +clean: clean-go $(MAKE) -C json-scala clean $(MAKE) -C json-java clean $(MAKE) -C json-hs clean diff --git a/json/go.mod b/json/go.mod deleted file mode 100644 index a356cfd7..00000000 --- a/json/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module json - -go 1.21.3 - -require ( - github.com/bytedance/sonic v1.10.1 - github.com/goccy/go-json v0.10.2 - github.com/json-iterator/go v1.1.12 - github.com/willabides/rjson v0.2.0 -) - -require ( - github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect - github.com/chenzhuoyu/iasm v0.9.0 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect -) diff --git a/json/go/benchmark.go b/json/go/benchmark.go new file mode 100644 index 00000000..1a4e47a4 --- /dev/null +++ b/json/go/benchmark.go @@ -0,0 +1,71 @@ +package benchmark + +import ( + "fmt" + "os" + + "benchmarks/common" +) + +type Coordinate struct { + X, Y, Z float64 +} + +type TestStruct struct { + Coordinates []Coordinate +} + +func (t TestStruct) Average() Coordinate { + var coord Coordinate + for i := range t.Coordinates { + coord.X += t.Coordinates[i].X + coord.Y += t.Coordinates[i].Y + coord.Z += t.Coordinates[i].Z + } + count := float64(len(t.Coordinates)) + coord.X /= count + coord.Y /= count + coord.Z /= count + return coord +} + +func verify(calc func([]byte) (Coordinate, error)) error { + right := Coordinate{2.0, 0.5, 0.25} + for _, v := range []string{ + `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, + `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}`} { + left, err := calc([]byte(v)) + if err != nil { + return err + } + if left != right { + return fmt.Errorf("%+v != %+v\n", left, right) + } + } + return nil +} + +func Run(name string, calc func([]byte) (Coordinate, error)) error { + err := verify(calc) + if err != nil { + return err + } + + data, err := os.ReadFile("/tmp/1.json") + if err != nil { + return err + } + var result Coordinate + var calcErr error + err = common.RunBenchmark(name, func() { + result, calcErr = calc(data) + }) + if err != nil { + return err + } + if calcErr != nil { + return calcErr + } + fmt.Printf("%+v\n", result) + return nil +} diff --git a/json/go/go.mod b/json/go/go.mod new file mode 100644 index 00000000..f856ce5d --- /dev/null +++ b/json/go/go.mod @@ -0,0 +1,24 @@ +module benchmark + +go 1.21 + +require ( + benchmarks/common v0.0.0-00010101000000-000000000000 + github.com/bytedance/sonic v1.10.2 + github.com/goccy/go-json v0.10.2 + github.com/json-iterator/go v1.1.12 + github.com/willabides/rjson v0.2.0 +) + +require ( + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.1 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/sys v0.14.0 // indirect +) + +replace benchmarks/common => ../../common/go diff --git a/json/go.sum b/json/go/go.sum similarity index 78% rename from json/go.sum rename to json/go/go.sum index 2f39607a..32d551d7 100644 --- a/json/go.sum +++ b/json/go/go.sum @@ -1,13 +1,14 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= -github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= +github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= +github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= 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= @@ -16,11 +17,13 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -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/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -37,12 +40,14 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/willabides/rjson v0.1.0 h1:RsKCjyFqCNjj4P6G8kJcddjLLqeyxYMs9ZiT1uU/ZUA= -github.com/willabides/rjson v0.1.0/go.mod h1:9fWQED96t+VlaF7GPwf/qRHLdNbAjjBkaPxmmjyuW5E= github.com/willabides/rjson v0.2.0 h1:cgBIzis7l9ugUTtaLMcl12pJBu1m62oTBGf/XXBHhJI= github.com/willabides/rjson v0.2.0/go.mod h1:9fWQED96t+VlaF7GPwf/qRHLdNbAjjBkaPxmmjyuW5E= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= diff --git a/json/go/goccy/test_goccy.go b/json/go/goccy/test_goccy.go new file mode 100644 index 00000000..e41f7850 --- /dev/null +++ b/json/go/goccy/test_goccy.go @@ -0,0 +1,22 @@ +package main + +import ( + "benchmark" + "github.com/goccy/go-json" +) + +func calc(bytes []byte) (benchmark.Coordinate, error) { + obj := benchmark.TestStruct{} + err := json.Unmarshal(bytes, &obj) + if err != nil { + return benchmark.Coordinate{}, err + } + return obj.Average(), nil +} + +func main() { + err := benchmark.Run("goccy/go-json", calc) + if err != nil { + panic(err) + } +} diff --git a/json/go/json/test.go b/json/go/json/test.go new file mode 100644 index 00000000..c58a57c7 --- /dev/null +++ b/json/go/json/test.go @@ -0,0 +1,22 @@ +package main + +import ( + "benchmark" + "encoding/json" +) + +func calc(bytes []byte) (benchmark.Coordinate, error) { + obj := benchmark.TestStruct{} + err := json.Unmarshal(bytes, &obj) + if err != nil { + return benchmark.Coordinate{}, err + } + return obj.Average(), nil +} + +func main() { + err := benchmark.Run("", calc) + if err != nil { + panic(err) + } +} diff --git a/json/go/jsoniter/test_jsoniter.go b/json/go/jsoniter/test_jsoniter.go new file mode 100644 index 00000000..de64efa8 --- /dev/null +++ b/json/go/jsoniter/test_jsoniter.go @@ -0,0 +1,24 @@ +package main + +import ( + "benchmark" + jsoniter "github.com/json-iterator/go" +) + +func calc(bytes []byte) (benchmark.Coordinate, error) { + var json = jsoniter.ConfigCompatibleWithStandardLibrary + + obj := benchmark.TestStruct{} + err := json.Unmarshal(bytes, &obj) + if err != nil { + return benchmark.Coordinate{}, err + } + return obj.Average(), nil +} + +func main() { + err := benchmark.Run("jsoniter", calc) + if err != nil { + panic(err) + } +} diff --git a/json/test_rjson_custom.go b/json/go/rjson-custom/test_rjson_custom.go similarity index 57% rename from json/test_rjson_custom.go rename to json/go/rjson-custom/test_rjson_custom.go index 486ee6b5..4654c1c5 100644 --- a/json/test_rjson_custom.go +++ b/json/go/rjson-custom/test_rjson_custom.go @@ -1,30 +1,13 @@ package main import ( - "fmt" - "io/ioutil" - "log" - "net" - "os" - + "benchmark" "github.com/willabides/rjson" ) -type Coordinate struct { - X, Y, Z float64 -} - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - type handler struct { buffer rjson.Buffer - coord Coordinate + coord benchmark.Coordinate count float64 // used to calculate the running average } @@ -57,35 +40,22 @@ func (h *handler) HandleObjectValue(fieldname, data []byte) (int, error) { return p, nil } -func calc(bytes []byte) Coordinate { +func calc(bytes []byte) (benchmark.Coordinate, error) { h := &handler{} - rjson.HandleObjectValues(bytes, h, &h.buffer) - return Coordinate{ + _, err := rjson.HandleObjectValues(bytes, h, &h.buffer) + if err != nil { + return benchmark.Coordinate{}, err + } + return benchmark.Coordinate{ X: h.coord.X / h.count, Y: h.coord.Y / h.count, Z: h.coord.Z / h.count, - } + }, nil } func main() { - right := Coordinate{2.0, 0.5, 0.25} - for _, v := range []string{ - `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, - `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}`} { - left := calc([]byte(v)) - if left != right { - log.Fatalf("%+v != %+v\n", left, right) - } - } - - bytes, err := ioutil.ReadFile("/tmp/1.json") + err := benchmark.Run("rjson custom", calc) if err != nil { - panic(fmt.Sprintf("%v", err)) + panic(err) } - - notify(fmt.Sprintf("Go (rjson custom)\t%d", os.Getpid())) - results := calc(bytes) - notify("stop") - - fmt.Printf("%+v\n", results) } diff --git a/json/go/rjson/test_rjson.go b/json/go/rjson/test_rjson.go new file mode 100644 index 00000000..2dd96d62 --- /dev/null +++ b/json/go/rjson/test_rjson.go @@ -0,0 +1,48 @@ +package main + +import ( + "benchmark" + "github.com/willabides/rjson" +) + +func calc(bytes []byte) (benchmark.Coordinate, error) { + obj := benchmark.TestStruct{} + var buffer rjson.Buffer + var currentCoord *benchmark.Coordinate + + coordHandler := rjson.ObjectValueHandlerFunc(func(fieldname, data []byte) (int, error) { + switch string(fieldname) { + case "x": + return rjson.DecodeFloat64(data, ¤tCoord.X) + case "y": + return rjson.DecodeFloat64(data, ¤tCoord.Y) + case "z": + return rjson.DecodeFloat64(data, ¤tCoord.Z) + } + return rjson.SkipValueFast(data, &buffer) + }) + + coordsHandler := rjson.ArrayValueHandlerFunc(func(data []byte) (int, error) { + obj.Coordinates = append(obj.Coordinates, benchmark.Coordinate{}) + currentCoord = &obj.Coordinates[len(obj.Coordinates)-1] + return rjson.HandleObjectValues(data, coordHandler, &buffer) + }) + + _, err := rjson.HandleObjectValues(bytes, rjson.ObjectValueHandlerFunc(func(fieldname, data []byte) (int, error) { + if string(fieldname) != "coordinates" { + return rjson.SkipValueFast(data, &buffer) + } + return rjson.HandleArrayValues(data, coordsHandler, &buffer) + }), &buffer) + if err != nil { + return benchmark.Coordinate{}, err + } + return obj.Average(), nil +} + +func main() { + err := benchmark.Run("rjson", calc) + if err != nil { + panic(err) + } +} diff --git a/json/go/sonic/test_sonic.go b/json/go/sonic/test_sonic.go new file mode 100644 index 00000000..574b3930 --- /dev/null +++ b/json/go/sonic/test_sonic.go @@ -0,0 +1,22 @@ +package main + +import ( + "benchmark" + "github.com/bytedance/sonic" +) + +func calc(bytes []byte) (benchmark.Coordinate, error) { + obj := benchmark.TestStruct{} + err := sonic.Unmarshal(bytes, &obj) + if err != nil { + return benchmark.Coordinate{}, err + } + return obj.Average(), nil +} + +func main() { + err := benchmark.Run("Sonic", calc) + if err != nil { + panic(err) + } +} diff --git a/json/test.go b/json/test.go deleted file mode 100644 index 351ff595..00000000 --- a/json/test.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log" - "net" - "os" - "runtime" -) - -type Coordinate struct { - X, Y, Z float64 -} - -type TestStruct struct { - Coordinates []Coordinate -} - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func calc(bytes []byte) Coordinate { - jobj := TestStruct{} - json.Unmarshal(bytes, &jobj) - - x, y, z := 0.0, 0.0, 0.0 - - for _, coord := range jobj.Coordinates { - x += coord.X - y += coord.Y - z += coord.Z - } - - len := float64(len(jobj.Coordinates)) - return Coordinate{x / len, y / len, z / len} -} - -func main() { - right := Coordinate{2.0, 0.5, 0.25} - for _, v := range []string{ - `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, - `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}`} { - left := calc([]byte(v)) - if left != right { - log.Fatalf("%+v != %+v\n", left, right) - } - } - - bytes, err := ioutil.ReadFile("/tmp/1.json") - if err != nil { - panic(fmt.Sprintf("%v", err)) - } - - notify(fmt.Sprintf("%s\t%d", runtime.Compiler, os.Getpid())) - results := calc(bytes) - notify("stop") - - fmt.Printf("%+v\n", results) -} diff --git a/json/test_goccy.go b/json/test_goccy.go deleted file mode 100644 index 008b13d8..00000000 --- a/json/test_goccy.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "fmt" - "github.com/goccy/go-json" - "io/ioutil" - "log" - "net" - "os" -) - -type Coordinate struct { - X, Y, Z float64 -} - -type TestStruct struct { - Coordinates []Coordinate -} - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func calc(bytes []byte) Coordinate { - jobj := TestStruct{} - json.Unmarshal(bytes, &jobj) - - x, y, z := 0.0, 0.0, 0.0 - - for _, coord := range jobj.Coordinates { - x += coord.X - y += coord.Y - z += coord.Z - } - - len := float64(len(jobj.Coordinates)) - return Coordinate{x / len, y / len, z / len} -} - -func main() { - right := Coordinate{2.0, 0.5, 0.25} - for _, v := range []string{ - `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, - `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}`} { - left := calc([]byte(v)) - if left != right { - log.Fatalf("%+v != %+v\n", left, right) - } - } - - bytes, err := ioutil.ReadFile("/tmp/1.json") - if err != nil { - panic(fmt.Sprintf("%v", err)) - } - - notify(fmt.Sprintf("Go (goccy/go-json)\t%d", os.Getpid())) - results := calc(bytes) - notify("stop") - - fmt.Printf("%+v\n", results) -} diff --git a/json/test_jsoniter.go b/json/test_jsoniter.go deleted file mode 100644 index 23ce9c47..00000000 --- a/json/test_jsoniter.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "fmt" - jsoniter "github.com/json-iterator/go" - "io/ioutil" - "log" - "net" - "os" - "strings" -) - -type Coordinate struct { - X, Y, Z float64 -} - -type TestStruct struct { - Coordinates []Coordinate -} - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func calc(reader *strings.Reader) Coordinate { - // Add jsoniter - var json = jsoniter.ConfigCompatibleWithStandardLibrary - - jobj := TestStruct{} - err := json.NewDecoder(reader).Decode(&jobj) - if err != nil { - panic(err) - } - - x, y, z := 0.0, 0.0, 0.0 - - for _, coord := range jobj.Coordinates { - x += coord.X - y += coord.Y - z += coord.Z - } - - len := float64(len(jobj.Coordinates)) - return Coordinate{x / len, y / len, z / len} -} - -func main() { - right := Coordinate{2.0, 0.5, 0.25} - for _, v := range []string{ - `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, - `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}`} { - left := calc(strings.NewReader(v)) - if left != right { - log.Fatalf("%+v != %+v\n", left, right) - } - } - - bytes, err := ioutil.ReadFile("/tmp/1.json") - if err != nil { - panic(fmt.Sprintf("%v", err)) - } - content := string(bytes) - reader := strings.NewReader(content) - - notify(fmt.Sprintf("Go (jsoniter)\t%d", os.Getpid())) - results := calc(reader) - notify("stop") - - fmt.Printf("%+v\n", results) -} diff --git a/json/test_rjson.go b/json/test_rjson.go deleted file mode 100644 index d3e9729b..00000000 --- a/json/test_rjson.go +++ /dev/null @@ -1,93 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log" - "net" - "os" - - "github.com/willabides/rjson" -) - -type Coordinate struct { - X, Y, Z float64 -} - -type TestStruct struct { - Coordinates []Coordinate -} - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func calc(bytes []byte) Coordinate { - jobj := TestStruct{} - - var buffer rjson.Buffer - var currentCoord *Coordinate - - coordHandler := rjson.ObjectValueHandlerFunc(func(fieldname, data []byte) (int, error) { - switch string(fieldname) { - case "x": - return rjson.DecodeFloat64(data, ¤tCoord.X) - case "y": - return rjson.DecodeFloat64(data, ¤tCoord.Y) - case "z": - return rjson.DecodeFloat64(data, ¤tCoord.Z) - } - return rjson.SkipValueFast(data, &buffer) - }) - - coordsHandler := rjson.ArrayValueHandlerFunc(func(data []byte) (int, error) { - jobj.Coordinates = append(jobj.Coordinates, Coordinate{}) - currentCoord = &jobj.Coordinates[len(jobj.Coordinates)-1] - return rjson.HandleObjectValues(data, coordHandler, &buffer) - }) - - rjson.HandleObjectValues(bytes, rjson.ObjectValueHandlerFunc(func(fieldname, data []byte) (int, error) { - if string(fieldname) != "coordinates" { - return rjson.SkipValueFast(data, &buffer) - } - return rjson.HandleArrayValues(data, coordsHandler, &buffer) - }), &buffer) - - x, y, z := 0.0, 0.0, 0.0 - - for _, coord := range jobj.Coordinates { - x += coord.X - y += coord.Y - z += coord.Z - } - - len := float64(len(jobj.Coordinates)) - return Coordinate{x / len, y / len, z / len} -} - -func main() { - right := Coordinate{2.0, 0.5, 0.25} - for _, v := range []string{ - `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, - `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}`} { - left := calc([]byte(v)) - if left != right { - log.Fatalf("%+v != %+v\n", left, right) - } - } - - bytes, err := ioutil.ReadFile("/tmp/1.json") - if err != nil { - panic(fmt.Sprintf("%v", err)) - } - - notify(fmt.Sprintf("Go (rjson)\t%d", os.Getpid())) - results := calc(bytes) - notify("stop") - - fmt.Printf("%+v\n", results) -} diff --git a/json/test_sonic.go b/json/test_sonic.go deleted file mode 100644 index b0df2b31..00000000 --- a/json/test_sonic.go +++ /dev/null @@ -1,66 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log" - "net" - "os" - - "github.com/bytedance/sonic" -) - -type Coordinate struct { - X, Y, Z float64 -} - -type TestStruct struct { - Coordinates []Coordinate -} - -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - -func calc(bytes []byte) Coordinate { - jobj := TestStruct{} - sonic.Unmarshal(bytes, &jobj) - - x, y, z := 0.0, 0.0, 0.0 - - for _, coord := range jobj.Coordinates { - x += coord.X - y += coord.Y - z += coord.Z - } - - len := float64(len(jobj.Coordinates)) - return Coordinate{x / len, y / len, z / len} -} - -func main() { - right := Coordinate{2.0, 0.5, 0.25} - for _, v := range []string{ - `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, - `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}`} { - left := calc([]byte(v)) - if left != right { - log.Fatalf("%+v != %+v\n", left, right) - } - } - - bytes, err := ioutil.ReadFile("/tmp/1.json") - if err != nil { - panic(fmt.Sprintf("%v", err)) - } - - notify(fmt.Sprintf("Go (Sonic)\t%d", os.Getpid())) - results := calc(bytes) - notify("stop") - - fmt.Printf("%+v\n", results) -} diff --git a/matmul/Makefile b/matmul/Makefile index 8dd4ca2f..e5f8e93e 100644 --- a/matmul/Makefile +++ b/matmul/Makefile @@ -13,7 +13,7 @@ executables := \ target/matmul_nim_arraymancer_gcc \ target/matmul_nim_arraymancer_clang \ target/matmul_cr \ - target/matmul_go \ + $(GO_TARGETS) \ target/matmul_go_gccgo \ target/matmul_c_gcc \ target/matmul_c_clang \ @@ -68,10 +68,7 @@ build: $(artifacts) target/matmul_cr: matmul.cr | target $(CRYSTAL_BUILD) -target/matmul_go: matmul.go | $(gofmt) - $(GO_BUILD) - -target/matmul_go_gccgo: matmul.go | $(gofmt) +target/matmul_go_gccgo: go/matmul $(GO_SOURCE) | gofmt $(GCC_GO_BUILD) matmul-rs-toml := matmul.rs/Cargo.toml @@ -253,7 +250,7 @@ run[jruby][matmul.rb]:: run[jruby][%]: % | $(rubocop) # Utilities .PHONY: clean -clean: +clean: clean-go -rm -rf target $(MAKE) -C java-nd4j clean cargo clean --manifest-path $(rust-ndarray-toml) diff --git a/matmul/go/benchmark.go b/matmul/go/benchmark.go new file mode 100644 index 00000000..59bb24a3 --- /dev/null +++ b/matmul/go/benchmark.go @@ -0,0 +1,34 @@ +package benchmark + +import ( + "benchmarks/common" + "fmt" + "math" +) + +func verify(calc func(int) float64) error { + left := calc(101) + right := -18.67 + if math.Abs(left-right) > 0.1 { + return fmt.Errorf("%+v != %+v\n", left, right) + } + return nil +} + +func Run(name string, n int, calc func(int) float64) error { + err := verify(calc) + if err != nil { + return err + } + + var result float64 + err = common.RunBenchmark(name, func() { + result = calc(n) + }) + if err != nil { + return err + } + + fmt.Printf("%+v\n", result) + return nil +} diff --git a/matmul/go/go.mod b/matmul/go/go.mod new file mode 100644 index 00000000..6650e9da --- /dev/null +++ b/matmul/go/go.mod @@ -0,0 +1,9 @@ +module benchmark + +go 1.21 + +require ( + benchmarks/common v0.0.0-00010101000000-000000000000 +) + +replace benchmarks/common => ../../common/go diff --git a/matmul/matmul.go b/matmul/go/matmul/matmul.go similarity index 65% rename from matmul/matmul.go rename to matmul/go/matmul/matmul.go index d548e3d7..9df05726 100644 --- a/matmul/matmul.go +++ b/matmul/go/matmul/matmul.go @@ -3,13 +3,8 @@ package main import ( - "flag" - "fmt" - "log" - "math" - "net" + "benchmark" "os" - "runtime" "strconv" ) @@ -50,14 +45,6 @@ func matmul(a [][]float64, b [][]float64) [][]float64 { return x } -func notify(msg string) { - conn, err := net.Dial("tcp", "localhost:9001") - if err == nil { - fmt.Fprintf(conn, msg) - conn.Close() - } -} - func calc(n int) float64 { n = n / 2 * 2 a := matgen(n, 1.0) @@ -67,21 +54,17 @@ func calc(n int) float64 { } func main() { - n := int(100) - flag.Parse() - if flag.NArg() > 0 { - n, _ = strconv.Atoi(flag.Arg(0)) + n := 100 + var err error + if len(os.Args) > 1 { + n, err = strconv.Atoi(os.Args[1]) + if err != nil { + panic(err) + } } - left := calc(101) - right := -18.67 - if math.Abs(left-right) > 0.1 { - log.Fatalf("%f != %f\n", left, right) + err = benchmark.Run("", n, calc) + if err != nil { + panic(err) } - - notify(fmt.Sprintf("%s\t%d", runtime.Compiler, os.Getpid())) - results := calc(n) - notify("stop") - - fmt.Printf("%f\n", results) } diff --git a/primes/Makefile b/primes/Makefile index be86533d..2c2fd8fb 100644 --- a/primes/Makefile +++ b/primes/Makefile @@ -10,7 +10,8 @@ executables := \ target/primes_v_clang \ target/primes_zig \ target/primes_nim_clang \ - target/primes_nim_gcc + target/primes_nim_gcc \ + $(GO_TARGETS) artifacts := $(executables) \ target/primes_scala.jar \ @@ -130,6 +131,6 @@ run[primes.rkt]:: run[%]: % # Utilities .PHONY: clean -clean: +clean: clean-go -rm -rf target -rm -rf zig-cache