├── .gitignore ├── plug ├── gen.sh ├── plugin.proto ├── plugin │ └── main.go ├── plugin.plug.pb.go └── plugin.pb.go ├── wazero └── main.go ├── goloader └── main.go ├── golangplugin └── main.go ├── pingo └── main.go ├── pie └── main.go ├── Dockerfile ├── LICENSE ├── hashicorp-go-plugin └── main.go ├── go.mod ├── plugin.go ├── README.md ├── plugin_test.go └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | hashicorpgoplugin 2 | plugin.so 3 | pieplugin 4 | pingoplugin 5 | plugplugin 6 | goloader.o 7 | -------------------------------------------------------------------------------- /plug/gen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | protoc -I=. --go_out=. --go_opt=module=uberswe/go-plugin-benchmark/plug --plug_out=. --plug_opt=module=uberswe/go-plugin-benchmark/plug plugin.proto 4 | -------------------------------------------------------------------------------- /wazero/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | ) 6 | 7 | func main() {} 8 | 9 | //export RandInt 10 | func RandInt() int { 11 | return rand.Int() 12 | } 13 | -------------------------------------------------------------------------------- /goloader/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | ) 6 | 7 | // RandInt uses math/rand to return a random integer 8 | func RandInt() int { 9 | return rand.Int() 10 | } 11 | -------------------------------------------------------------------------------- /golangplugin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | ) 6 | 7 | // RandInt uses math/rand to return a random integer 8 | func RandInt() int { 9 | return rand.Int() 10 | } 11 | -------------------------------------------------------------------------------- /plug/plugin.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package plugin; 4 | option go_package = "uberswe/go-plugin-benchmark/plug"; 5 | 6 | message RandIntRequest { 7 | int64 key = 1; 8 | } 9 | 10 | message RandIntResponse { 11 | int64 value = 1; 12 | } 13 | 14 | service RandomIntService { 15 | rpc Get(RandIntRequest) returns (RandIntResponse); 16 | } -------------------------------------------------------------------------------- /pingo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/dullgiulio/pingo" 5 | "math/rand" 6 | ) 7 | 8 | // MyPlugin is the plugin struct 9 | type MyPlugin struct{} 10 | 11 | // RandInt returns a random int 12 | func (p *MyPlugin) RandInt(in int, msg *int) error { 13 | *msg = rand.Int() 14 | return nil 15 | } 16 | 17 | func main() { 18 | plugin := &MyPlugin{} 19 | pingo.Register(plugin) 20 | _ = pingo.Run() 21 | } 22 | -------------------------------------------------------------------------------- /pie/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/natefinch/pie" 5 | "math/rand" 6 | "net/rpc/jsonrpc" 7 | ) 8 | 9 | func main() { 10 | p := pie.NewProvider() 11 | if err := p.RegisterName("Plugin", api{}); err != nil { 12 | panic(err) 13 | } 14 | p.ServeCodec(jsonrpc.NewServerCodec) 15 | } 16 | 17 | type api struct{} 18 | 19 | func (api) RandInt(in int, response *int) error { 20 | *response = rand.Int() 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /plug/plugin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/uberswe/go-plugin-benchmark/plug" 6 | "math/rand" 7 | ) 8 | 9 | type RandomIntService struct{} 10 | 11 | func (ris *RandomIntService) Get(in int64) (int64, error) { 12 | return int64(rand.Int()), nil 13 | } 14 | 15 | func main() { 16 | err := plug.RunRandomIntService(&RandomIntService{}) 17 | if err != nil { 18 | fmt.Println(err.Error(), ", exiting...") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.21 2 | 3 | WORKDIR /app 4 | 5 | ENV GO111MODULE=on 6 | ENV GOARCH=amd64 7 | 8 | RUN apt-get update 9 | RUN apt-get install gcc 10 | RUN wget https://github.com/tinygo-org/tinygo/releases/download/v0.30.0/tinygo_0.30.0_amd64.deb && dpkg -i tinygo_0.30.0_amd64.deb 11 | 12 | COPY . ./ 13 | 14 | RUN go get 15 | RUN cp -r /usr/local/go/src/cmd/internal /usr/local/go/src/cmd/objfile 16 | RUN go build -buildmode=plugin -o plugin.so golangplugin/main.go 17 | RUN go build -o ./hashicorpgoplugin ./hashicorp-go-plugin/main.go 18 | RUN go build -o ./pieplugin ./pie/main.go 19 | RUN go build -o ./pingoplugin ./pingo/main.go 20 | RUN go build -o ./plugplugin ./plug/plugin/main.go 21 | RUN tinygo build -o ./wazero.wasm -target wasi ./wazero/main.go 22 | RUN go list -export -f '{{if .Export}}packagefile {{.ImportPath}}={{.Export}}{{end}}' std `go list -f {{.Imports}} ./goloader/main.go | awk '{sub(/^\[/, ""); print }' | awk '{sub(/\]$/, ""); print }'` > importcfg 23 | RUN CGO_ENABLED=0 go tool compile -importcfg importcfg -o ./goloader.o ./goloader/main.go 24 | 25 | CMD ["go", "test", "-bench=."] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Markus Tenghamn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /hashicorp-go-plugin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/go-hclog" 5 | "github.com/hashicorp/go-plugin" 6 | benchmark "github.com/uberswe/go-plugin-benchmark" 7 | "math/rand" 8 | "os" 9 | ) 10 | 11 | // RandIntResponder is a plugin struct 12 | type RandIntResponder struct{} 13 | 14 | // Respond is a plugin function returning a random int 15 | func (g *RandIntResponder) Respond() int { 16 | return rand.Int() 17 | } 18 | 19 | var handshakeConfig = plugin.HandshakeConfig{ 20 | ProtocolVersion: 1, 21 | MagicCookieKey: "RAND_PLUGIN", 22 | MagicCookieValue: "int", 23 | } 24 | 25 | func main() { 26 | logger := hclog.New(&hclog.LoggerOptions{ 27 | Name: "plugin", 28 | Output: os.Stdout, 29 | Level: hclog.Off, 30 | }) 31 | 32 | responder := &RandIntResponder{} 33 | // pluginMap is the map of plugins we can dispense. 34 | var pluginMap = map[string]plugin.Plugin{ 35 | "responder": &benchmark.RandIntPlugin{Impl: responder}, 36 | } 37 | 38 | plugin.Serve(&plugin.ServeConfig{ 39 | HandshakeConfig: handshakeConfig, 40 | Plugins: pluginMap, 41 | Logger: logger, 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/uberswe/go-plugin-benchmark 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/dullgiulio/pingo v0.0.0-20151111190101-8b1949e35b5a 7 | github.com/elliotmr/plug v0.0.3 8 | github.com/golang/protobuf v1.5.3 9 | github.com/hashicorp/go-hclog v1.5.0 10 | github.com/hashicorp/go-plugin v1.5.2 11 | github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007 12 | github.com/pkujhd/goloader v0.0.0-20230918021236-475614750c78 13 | github.com/tetratelabs/wazero v1.5.0 14 | github.com/traefik/yaegi v0.9.19 15 | google.golang.org/protobuf v1.31.0 16 | ) 17 | 18 | require ( 19 | github.com/fatih/color v1.15.0 // indirect 20 | github.com/hashicorp/yamux v0.1.1 // indirect 21 | github.com/mattn/go-colorable v0.1.13 // indirect 22 | github.com/mattn/go-isatty v0.0.19 // indirect 23 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 24 | github.com/oklog/run v1.1.0 // indirect 25 | github.com/stretchr/testify v1.8.0 // indirect 26 | golang.org/x/net v0.16.0 // indirect 27 | golang.org/x/sys v0.13.0 // indirect 28 | golang.org/x/text v0.13.0 // indirect 29 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect 30 | google.golang.org/grpc v1.58.2 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /plugin.go: -------------------------------------------------------------------------------- 1 | package benchmark 2 | 3 | import ( 4 | "github.com/hashicorp/go-plugin" 5 | "net/rpc" 6 | ) 7 | 8 | // RandIntResponder is a responder for hashicorp/go-plugin 9 | type RandIntResponder interface { 10 | Respond() int 11 | } 12 | 13 | // RandIntRPC is a struct used for hashicorp/go-plugin 14 | type RandIntRPC struct{ client *rpc.Client } 15 | 16 | // Respond is a function used while benchmarking hashicorp/go-plugin 17 | func (g *RandIntRPC) Respond() int { 18 | var resp int 19 | err := g.client.Call("Plugin.Respond", new(interface{}), &resp) 20 | if err != nil { 21 | panic(err) 22 | } 23 | 24 | return resp 25 | } 26 | 27 | // RandIntRPCServer is the RPC server used when benchmarking hashicorp/go-plugin 28 | type RandIntRPCServer struct { 29 | Impl RandIntResponder 30 | } 31 | 32 | // Respond is a function used while benchmarking hashicorp/go-plugin 33 | func (s *RandIntRPCServer) Respond(args interface{}, resp *int) error { 34 | *resp = s.Impl.Respond() 35 | return nil 36 | } 37 | 38 | // RandIntPlugin is a struct used while benchmarking hashicorp/go-plugin 39 | type RandIntPlugin struct { 40 | Impl RandIntResponder 41 | } 42 | 43 | // Server is the server used while benchmarking hashicorp/go-plugin 44 | func (p *RandIntPlugin) Server(*plugin.MuxBroker) (interface{}, error) { 45 | return &RandIntRPCServer{Impl: p.Impl}, nil 46 | } 47 | 48 | // Client is the client used while benchmarking hashicorp/go-plugin 49 | func (RandIntPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { 50 | return &RandIntRPC{client: c}, nil 51 | } 52 | 53 | type plug struct { 54 | client *rpc.Client 55 | } 56 | 57 | // RandInt is a function used for testing natefinch/pie 58 | func (p plug) RandInt(in int) (result int, err error) { 59 | err = p.client.Call("Plugin.RandInt", in, &result) 60 | return result, err 61 | } 62 | -------------------------------------------------------------------------------- /plug/plugin.plug.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-plug. DO NOT EDIT. 2 | 3 | package plug 4 | 5 | import ( 6 | fmt "fmt" 7 | runtime "github.com/elliotmr/plug/pkg/runtime" 8 | proto "google.golang.org/protobuf/proto" 9 | ) 10 | 11 | const ( 12 | RandomIntServiceGetService runtime.Service = 0x0000 13 | RandomIntServiceHandshakeService runtime.Service = 0x00FF 14 | ) 15 | 16 | type RandomIntService interface { 17 | Get(key int64) (int64, error) 18 | } 19 | 20 | type randomintservicePlugin struct { 21 | Impl RandomIntService 22 | } 23 | 24 | func RunRandomIntService(impl RandomIntService) error { 25 | s := &randomintservicePlugin{Impl: impl} 26 | return runtime.Run(s, "magic", 1, 0) 27 | } 28 | 29 | func (x *randomintservicePlugin) Link(srv runtime.Service) (proto.Message, runtime.GenPluginMethod, error) { 30 | switch srv { 31 | case RandomIntServiceGetService: 32 | return &RandIntRequest{}, x.Get, nil 33 | } 34 | return nil, nil, fmt.Errorf("unknown service: %d", srv) 35 | } 36 | 37 | func (x *randomintservicePlugin) Get(req proto.Message) (proto.Message, error) { 38 | in, ok := req.(*RandIntRequest) 39 | if !ok { 40 | return nil, fmt.Errorf("invalid request type") 41 | } 42 | value, err := x.Impl.Get(in.Key) 43 | return &RandIntResponse{Value: value}, err 44 | } 45 | 46 | type randomintserviceHost struct { 47 | c *runtime.Host 48 | } 49 | 50 | func LoadRandomIntService(s string) (RandomIntService, error) { 51 | c, err := runtime.Load(s, "magic", 1, 0) 52 | if err != nil { 53 | return nil, fmt.Errorf("unable to load plugin: %w", err) 54 | } 55 | return &randomintserviceHost{c: c}, nil 56 | } 57 | 58 | func (x *randomintserviceHost) Get(key int64) (int64, error) { 59 | resp := &RandIntResponse{} 60 | err := x.c.SendRecv(RandomIntServiceGetService, &RandIntRequest{Key: key}, resp) 61 | return resp.Value, err 62 | } 63 | 64 | func TestRandomIntService(impl RandomIntService) (RandomIntService, error) { 65 | s := &randomintservicePlugin{Impl: impl} 66 | c, err := runtime.Test(s, "magic", 1, 0) 67 | if err != nil { 68 | return nil, fmt.Errorf("unable to load plugin: %w", err) 69 | } 70 | return &randomintserviceHost{c: c}, nil 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang Plugin Benchmark 2 | 3 | A comparison of the [go plugin package](https://golang.org/pkg/plugin/) and other plugin implementations for golang. The reason for this is to compare alternatives from a performance perspective. As [shown in a previous benchmark](https://github.com/uberswe/goplugins) there is basically no difference in performance of using go plugins to running a function directly in code. 4 | 5 | ## Benchmarks 6 | 7 | | Name | Operations (higher is better) | ns/op (lower is better) | type | 8 | |---------------------------------------------------------------|:-----------------------------:|------------------------:|:-----------:| 9 | | [go plugin package](https://golang.org/pkg/plugin/) | 44219324 | 30.35 ns/op | native | 10 | | [hashicorp/go-plugin](https://github.com/hashicorp/go-plugin) | 3682 | 413257 ns/op | rpc | 11 | | [natefinch/pie](https://github.com/natefinch/pie) | 3933 | 328025 ns/op | rpc | 12 | | [dullgiulio/pingo](https://github.com/dullgiulio/pingo) | 4197 | 329354 ns/op | tcp | 13 | | [dullgiulio/pingo](https://github.com/dullgiulio/pingo) | 3110 | 465628 ns/op | unix | 14 | | [elliotmr/plug](https://github.com/elliotmr/plug) | 7998 | 162677 ns/op | ipc | 15 | | [traefik/yaegi](https://github.com/traefik/yaegi) | 1000000 | 1184 ns/op | interpreter | 16 | | [pkujhd/goloader](https://github.com/pkujhd/goloader) | 68201743 | 19.11 ns/op | native | 17 | | [tetratelabs/wazero](https://github.com/tetratelabs/wazero) | 11401358 | 105.0 ns/op | native | 18 | 19 | Several of the other packages use RPC or similar methods instead of the go plugin package which gets around issues such as, but not limited to, [not being compatible with Windows](https://github.com/golang/go/issues/19282) and [package paths and GOPATH needing to be the same between apps and plugins](https://github.com/golang/go/issues/20481). 20 | 21 | With the addition of [Yaegi](https://github.com/traefik/yaegi), I am also benchmarking interpreters. 22 | 23 | **Do you know any other plugin packages?** Please open an [issue](https://github.com/uberswe/go-plugin-benchmark/issues/new) or pull request. 24 | 25 | **Found an issue with a benchmark?** Please open an [issue](https://github.com/uberswe/go-plugin-benchmark/issues/new) or pull request. 26 | 27 | ## Setup 28 | 29 | I have moved to using [Docker](https://www.docker.com/) to run these benchmarks to make them easier to reproduce. 30 | 31 | Build the docker image: 32 | 33 | ``` 34 | docker build --pull --no-cache --tag go-plugin-benchmark:local . 35 | ``` 36 | 37 | To run the benchmark run 38 | 39 | ``` 40 | docker run go-plugin-benchmark:local 41 | ``` 42 | 43 | ## Results 44 | 45 | Most plugins tested are using RPC which adds about 30 - 50 microseconds to plugin calls (or 0.03 - 0.05 milliseconds) over the golang plugin package. 46 | 47 | The [goloader](https://github.com/pkujhd/goloader) package is interesting and may provide a good alternative to the go plugin package. One drawback is that it uses internal packages which requires renaming the internal folder locally and I have not tested compatibility to see if it solves the problems with the go plugin package. 48 | 49 | ## Contributing 50 | 51 | If you have a plugin or interpreter written in go which you would like to benchmark feel free to [open an issue](https://github.com/uberswe/go-plugin-benchmark/issues/new). 52 | 53 | Would you like to add more benchmarks? Please feel free to fork this repository and open a pull request with the updated changes. Please make sure to add any needed code and also update the Readme. Your code belongs to you but it must fall under the same LICENSE as this repository to be included. -------------------------------------------------------------------------------- /plugin_test.go: -------------------------------------------------------------------------------- 1 | package benchmark 2 | 3 | import ( 4 | "fmt" 5 | "github.com/dullgiulio/pingo" 6 | "github.com/hashicorp/go-hclog" 7 | hashicorpplugin "github.com/hashicorp/go-plugin" 8 | "github.com/natefinch/pie" 9 | "github.com/pkujhd/goloader" 10 | "github.com/tetratelabs/wazero" 11 | "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" 12 | "github.com/traefik/yaegi/interp" 13 | "github.com/traefik/yaegi/stdlib" 14 | plugplugin "github.com/uberswe/go-plugin-benchmark/plug" 15 | "context" 16 | "net/rpc/jsonrpc" 17 | "os" 18 | "os/exec" 19 | "plugin" 20 | "runtime" 21 | "testing" 22 | "unsafe" 23 | ) 24 | 25 | // BenchmarkPluginRandInt uses a go plugin and tests math/rand for generating random integers 26 | func BenchmarkPluginRandInt(b *testing.B) { 27 | plug, err := plugin.Open("./plugin.so") 28 | if err != nil { 29 | panic(err) 30 | } 31 | 32 | randInt, err := plug.Lookup("RandInt") 33 | if err != nil { 34 | panic(err) 35 | } 36 | 37 | randFunc, ok := randInt.(func() int) 38 | if !ok { 39 | panic("unexpected type from module symbol") 40 | } 41 | 42 | b.Run("golang-plugin", func(b *testing.B) { 43 | for i := 0; i < b.N; i++ { 44 | randFunc() 45 | } 46 | }) 47 | } 48 | 49 | func BenchmarkHashicorpGoPluginRandInt(b *testing.B) { 50 | logger := hclog.New(&hclog.LoggerOptions{ 51 | Name: "plugin", 52 | Output: os.Stdout, 53 | Level: hclog.Off, 54 | }) 55 | 56 | var handshakeConfig = hashicorpplugin.HandshakeConfig{ 57 | ProtocolVersion: 1, 58 | MagicCookieKey: "RAND_PLUGIN", 59 | MagicCookieValue: "int", 60 | } 61 | 62 | // pluginMap is the map of plugins we can dispense. 63 | var pluginMap = map[string]hashicorpplugin.Plugin{ 64 | "responder": &RandIntPlugin{}, 65 | } 66 | 67 | // We're a host! Start by launching the plugin process. 68 | client := hashicorpplugin.NewClient(&hashicorpplugin.ClientConfig{ 69 | HandshakeConfig: handshakeConfig, 70 | Plugins: pluginMap, 71 | Cmd: exec.Command("./hashicorpgoplugin"), 72 | Logger: logger, 73 | }) 74 | defer client.Kill() 75 | 76 | // Connect via RPC 77 | rpcClient, err := client.Client() 78 | if err != nil { 79 | panic(err) 80 | } 81 | 82 | // Request the plugin 83 | raw, err := rpcClient.Dispense("responder") 84 | if err != nil { 85 | panic(err) 86 | } 87 | 88 | // We should have a Greeter now! This feels like a normal interface 89 | // implementation but is in fact over an RPC connection. 90 | intResponder := raw.(RandIntResponder) 91 | b.Run("hashicorp-go-plugin", func(b *testing.B) { 92 | for i := 0; i < b.N; i++ { 93 | intResponder.Respond() 94 | } 95 | }) 96 | } 97 | 98 | func BenchmarkPieRandInt(b *testing.B) { 99 | path := "./pieplugin" 100 | if runtime.GOOS == "windows" { 101 | path = path + ".exe" 102 | } 103 | 104 | client, err := pie.StartProviderCodec(jsonrpc.NewClientCodec, os.Stderr, path) 105 | if err != nil { 106 | panic(err) 107 | } 108 | defer client.Close() 109 | p := plug{client} 110 | b.Run("pie", func(b *testing.B) { 111 | for i := 0; i < b.N; i++ { 112 | _, _ = p.RandInt(i) 113 | } 114 | }) 115 | } 116 | 117 | func BenchmarkPingoTcpRandInt(b *testing.B) { 118 | p := pingo.NewPlugin("tcp", "./pingoplugin") 119 | p.Start() 120 | 121 | var resp int 122 | 123 | b.Run("pingo-tcp", func(b *testing.B) { 124 | for i := 0; i < b.N; i++ { 125 | _ = p.Call("MyPlugin.RandInt", 1, &resp) 126 | } 127 | }) 128 | p.Stop() 129 | 130 | p2 := pingo.NewPlugin("unix", "./pingoplugin") 131 | p2.SetSocketDirectory("./") 132 | 133 | p2.Start() 134 | 135 | b.Run("pingo-unix", func(b *testing.B) { 136 | for i := 0; i < b.N; i++ { 137 | _ = p2.Call("MyPlugin.RandInt", 1, &resp) 138 | } 139 | }) 140 | p2.Stop() 141 | } 142 | 143 | func BenchmarkPlugRandInt(b *testing.B) { 144 | service, _ := plugplugin.LoadRandomIntService("./plugplugin") 145 | b.Run("plug", func(b *testing.B) { 146 | for i := 0; i < b.N; i++ { 147 | _, _ = service.Get(1) 148 | } 149 | }) 150 | } 151 | 152 | func BenchmarkYaegiRandInt(b *testing.B) { 153 | var src = `package test 154 | import "math/rand" 155 | func RandInt(i int) int { return rand.Int() }` 156 | 157 | i := interp.New(interp.Options{}) 158 | 159 | // To handle import of "math/rand" 160 | i.Use(stdlib.Symbols) 161 | 162 | _, err := i.Eval(src) 163 | if err != nil { 164 | panic(err) 165 | } 166 | 167 | v, err := i.Eval("test.RandInt") 168 | if err != nil { 169 | panic(err) 170 | } 171 | 172 | randIntFunc := v.Interface().(func(int) int) 173 | b.Run("yaegi", func(b *testing.B) { 174 | for i := 0; i < b.N; i++ { 175 | _ = randIntFunc(1) 176 | } 177 | }) 178 | } 179 | 180 | func BenchmarkGoloaderRandInt(b *testing.B) { 181 | linker, err := goloader.ReadObjs([]string{"goloader.o"}, []string{"main"}) 182 | if err != nil { 183 | b.Error(err) 184 | return 185 | } 186 | 187 | run := "main.RandInt" 188 | 189 | symPtr := make(map[string]uintptr) 190 | err = goloader.RegSymbol(symPtr) 191 | if err != nil { 192 | b.Error(err) 193 | return 194 | } 195 | 196 | b.Run("goloader", func(b *testing.B) { 197 | codeModule, err := goloader.Load(linker, symPtr) 198 | if err != nil { 199 | fmt.Println("Load error:", err) 200 | return 201 | } 202 | runFuncPtr, ok := codeModule.Syms[run] 203 | if !ok || runFuncPtr == 0 { 204 | fmt.Println("Load error! not find function:", run) 205 | return 206 | } 207 | funcPtrContainer := (uintptr)(unsafe.Pointer(&runFuncPtr)) 208 | runFunc := *(*func() int)(unsafe.Pointer(&funcPtrContainer)) 209 | for i := 0; i < b.N; i++ { 210 | _ = runFunc() 211 | } 212 | 213 | os.Stdout.Sync() 214 | codeModule.Unload() 215 | }) 216 | } 217 | 218 | func BenchmarkWazeroRandInt(b *testing.B) { 219 | wasmFile, err := os.ReadFile("wazero.wasm") 220 | if err != nil { 221 | fmt.Println("failed to read file:", err) 222 | return 223 | } 224 | 225 | ctx := context.Background() 226 | runtime := wazero.NewRuntime(ctx) 227 | defer runtime.Close(ctx) 228 | 229 | wasi_snapshot_preview1.MustInstantiate(ctx, runtime) 230 | 231 | module, err := runtime.Instantiate(ctx, wasmFile) 232 | if err != nil { 233 | fmt.Println("failed to instantiate module:", err) 234 | return 235 | } 236 | 237 | b.Run("wazero", func(b *testing.B) { 238 | randIntFunction := module.ExportedFunction("RandInt") 239 | 240 | for i := 0; i < b.N; i++ { 241 | if _, err := randIntFunction.Call(ctx); err != nil { 242 | fmt.Println("failed to call function:", err) 243 | return 244 | } 245 | } 246 | }) 247 | } 248 | -------------------------------------------------------------------------------- /plug/plugin.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.25.0 4 | // protoc v3.10.1 5 | // source: plugin.proto 6 | 7 | package plug 8 | 9 | import ( 10 | proto "github.com/golang/protobuf/proto" 11 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 12 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 13 | reflect "reflect" 14 | sync "sync" 15 | ) 16 | 17 | const ( 18 | // Verify that this generated code is sufficiently up-to-date. 19 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 20 | // Verify that runtime/protoimpl is sufficiently up-to-date. 21 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 22 | ) 23 | 24 | // This is a compile-time assertion that a sufficiently up-to-date version 25 | // of the legacy proto package is being used. 26 | const _ = proto.ProtoPackageIsVersion4 27 | 28 | type RandIntRequest struct { 29 | state protoimpl.MessageState 30 | sizeCache protoimpl.SizeCache 31 | unknownFields protoimpl.UnknownFields 32 | 33 | Key int64 `protobuf:"varint,1,opt,name=key,proto3" json:"key,omitempty"` 34 | } 35 | 36 | func (x *RandIntRequest) Reset() { 37 | *x = RandIntRequest{} 38 | if protoimpl.UnsafeEnabled { 39 | mi := &file_plugin_proto_msgTypes[0] 40 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 41 | ms.StoreMessageInfo(mi) 42 | } 43 | } 44 | 45 | func (x *RandIntRequest) String() string { 46 | return protoimpl.X.MessageStringOf(x) 47 | } 48 | 49 | func (*RandIntRequest) ProtoMessage() {} 50 | 51 | func (x *RandIntRequest) ProtoReflect() protoreflect.Message { 52 | mi := &file_plugin_proto_msgTypes[0] 53 | if protoimpl.UnsafeEnabled && x != nil { 54 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 55 | if ms.LoadMessageInfo() == nil { 56 | ms.StoreMessageInfo(mi) 57 | } 58 | return ms 59 | } 60 | return mi.MessageOf(x) 61 | } 62 | 63 | // Deprecated: Use RandIntRequest.ProtoReflect.Descriptor instead. 64 | func (*RandIntRequest) Descriptor() ([]byte, []int) { 65 | return file_plugin_proto_rawDescGZIP(), []int{0} 66 | } 67 | 68 | func (x *RandIntRequest) GetKey() int64 { 69 | if x != nil { 70 | return x.Key 71 | } 72 | return 0 73 | } 74 | 75 | type RandIntResponse struct { 76 | state protoimpl.MessageState 77 | sizeCache protoimpl.SizeCache 78 | unknownFields protoimpl.UnknownFields 79 | 80 | Value int64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` 81 | } 82 | 83 | func (x *RandIntResponse) Reset() { 84 | *x = RandIntResponse{} 85 | if protoimpl.UnsafeEnabled { 86 | mi := &file_plugin_proto_msgTypes[1] 87 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 88 | ms.StoreMessageInfo(mi) 89 | } 90 | } 91 | 92 | func (x *RandIntResponse) String() string { 93 | return protoimpl.X.MessageStringOf(x) 94 | } 95 | 96 | func (*RandIntResponse) ProtoMessage() {} 97 | 98 | func (x *RandIntResponse) ProtoReflect() protoreflect.Message { 99 | mi := &file_plugin_proto_msgTypes[1] 100 | if protoimpl.UnsafeEnabled && x != nil { 101 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 102 | if ms.LoadMessageInfo() == nil { 103 | ms.StoreMessageInfo(mi) 104 | } 105 | return ms 106 | } 107 | return mi.MessageOf(x) 108 | } 109 | 110 | // Deprecated: Use RandIntResponse.ProtoReflect.Descriptor instead. 111 | func (*RandIntResponse) Descriptor() ([]byte, []int) { 112 | return file_plugin_proto_rawDescGZIP(), []int{1} 113 | } 114 | 115 | func (x *RandIntResponse) GetValue() int64 { 116 | if x != nil { 117 | return x.Value 118 | } 119 | return 0 120 | } 121 | 122 | var File_plugin_proto protoreflect.FileDescriptor 123 | 124 | var file_plugin_proto_rawDesc = []byte{ 125 | 0x0a, 0x0c, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 126 | 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x22, 0x0a, 0x0e, 0x52, 0x61, 0x6e, 0x64, 0x49, 0x6e, 127 | 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 128 | 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x27, 0x0a, 0x0f, 0x52, 0x61, 129 | 0x6e, 0x64, 0x49, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 130 | 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 131 | 0x6c, 0x75, 0x65, 0x32, 0x4a, 0x0a, 0x10, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x49, 0x6e, 0x74, 132 | 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x16, 133 | 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x52, 0x61, 0x6e, 0x64, 0x49, 0x6e, 0x74, 0x52, 134 | 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 135 | 0x52, 0x61, 0x6e, 0x64, 0x49, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 136 | 0x22, 0x5a, 0x20, 0x75, 0x62, 0x65, 0x72, 0x73, 0x77, 0x65, 0x2f, 0x67, 0x6f, 0x2d, 0x70, 0x6c, 137 | 0x75, 0x67, 0x69, 0x6e, 0x2d, 0x62, 0x65, 0x6e, 0x63, 0x68, 0x6d, 0x61, 0x72, 0x6b, 0x2f, 0x70, 138 | 0x6c, 0x75, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 139 | } 140 | 141 | var ( 142 | file_plugin_proto_rawDescOnce sync.Once 143 | file_plugin_proto_rawDescData = file_plugin_proto_rawDesc 144 | ) 145 | 146 | func file_plugin_proto_rawDescGZIP() []byte { 147 | file_plugin_proto_rawDescOnce.Do(func() { 148 | file_plugin_proto_rawDescData = protoimpl.X.CompressGZIP(file_plugin_proto_rawDescData) 149 | }) 150 | return file_plugin_proto_rawDescData 151 | } 152 | 153 | var file_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 154 | var file_plugin_proto_goTypes = []interface{}{ 155 | (*RandIntRequest)(nil), // 0: plugin.RandIntRequest 156 | (*RandIntResponse)(nil), // 1: plugin.RandIntResponse 157 | } 158 | var file_plugin_proto_depIdxs = []int32{ 159 | 0, // 0: plugin.RandomIntService.Get:input_type -> plugin.RandIntRequest 160 | 1, // 1: plugin.RandomIntService.Get:output_type -> plugin.RandIntResponse 161 | 1, // [1:2] is the sub-list for method output_type 162 | 0, // [0:1] is the sub-list for method input_type 163 | 0, // [0:0] is the sub-list for extension type_name 164 | 0, // [0:0] is the sub-list for extension extendee 165 | 0, // [0:0] is the sub-list for field type_name 166 | } 167 | 168 | func init() { file_plugin_proto_init() } 169 | func file_plugin_proto_init() { 170 | if File_plugin_proto != nil { 171 | return 172 | } 173 | if !protoimpl.UnsafeEnabled { 174 | file_plugin_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 175 | switch v := v.(*RandIntRequest); i { 176 | case 0: 177 | return &v.state 178 | case 1: 179 | return &v.sizeCache 180 | case 2: 181 | return &v.unknownFields 182 | default: 183 | return nil 184 | } 185 | } 186 | file_plugin_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 187 | switch v := v.(*RandIntResponse); i { 188 | case 0: 189 | return &v.state 190 | case 1: 191 | return &v.sizeCache 192 | case 2: 193 | return &v.unknownFields 194 | default: 195 | return nil 196 | } 197 | } 198 | } 199 | type x struct{} 200 | out := protoimpl.TypeBuilder{ 201 | File: protoimpl.DescBuilder{ 202 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 203 | RawDescriptor: file_plugin_proto_rawDesc, 204 | NumEnums: 0, 205 | NumMessages: 2, 206 | NumExtensions: 0, 207 | NumServices: 1, 208 | }, 209 | GoTypes: file_plugin_proto_goTypes, 210 | DependencyIndexes: file_plugin_proto_depIdxs, 211 | MessageInfos: file_plugin_proto_msgTypes, 212 | }.Build() 213 | File_plugin_proto = out.File 214 | file_plugin_proto_rawDesc = nil 215 | file_plugin_proto_goTypes = nil 216 | file_plugin_proto_depIdxs = nil 217 | } 218 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= 4 | github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= 5 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 6 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/dullgiulio/pingo v0.0.0-20151111190101-8b1949e35b5a h1:hxUGjnGTjWlrH+mG7wqwJYKtmKcZmmSYCjSf+nWgeTc= 11 | github.com/dullgiulio/pingo v0.0.0-20151111190101-8b1949e35b5a/go.mod h1:M1VZSWV1CHnqoST00aa9Ha4VL5btiDWraNL0yQwpUc8= 12 | github.com/elliotmr/plug v0.0.3 h1:Us4XqH5+IRnIu+bg5Y78nCDlsFT80bS303aqs6u6hrI= 13 | github.com/elliotmr/plug v0.0.3/go.mod h1:JbhjBG5U/+/DSfZK9EDigpySz9caG5P5YTNnPuMye8Y= 14 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 15 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 16 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 17 | github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= 18 | github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= 19 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 20 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 21 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 22 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 23 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 24 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 25 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 26 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 27 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 28 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 29 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 30 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 31 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 32 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 33 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 34 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 35 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 36 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 37 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 38 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 39 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 40 | github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= 41 | github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= 42 | github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= 43 | github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= 44 | github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= 45 | github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= 46 | github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= 47 | github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= 48 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 49 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 50 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 51 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 52 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 53 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 54 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 55 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 56 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 57 | github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= 58 | github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= 59 | github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007 h1:Ohgj9L0EYOgXxkDp+bczlMBiulwmqYzQpvQNUdtt3oc= 60 | github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007/go.mod h1:wKCOWMb6iNlvKiOToY2cNuaovSXvIiv1zDi9QDR7aGQ= 61 | github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= 62 | github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= 63 | github.com/pkujhd/goloader v0.0.0-20230918021236-475614750c78 h1:DXipSG6sizuYMpGvAo75P/8JqxQLIQEzt4PhKB69I3Q= 64 | github.com/pkujhd/goloader v0.0.0-20230918021236-475614750c78/go.mod h1:JQc0eCq8bTqZremrbWWBXTYAj/82bEnPl/9g+nKIsuA= 65 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 66 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 67 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 68 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 69 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 70 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 71 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 72 | github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 73 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= 74 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 75 | github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0= 76 | github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= 77 | github.com/traefik/yaegi v0.9.19 h1:ze01+pVtKmxSogy0wlAPSvm2LoDYuZj2LdH3S6GxHcQ= 78 | github.com/traefik/yaegi v0.9.19/go.mod h1:FAYnRlZyuVlEkvnkHq3bvJ1lW5be6XuwgLdkYgYG6Lk= 79 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 80 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 81 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 82 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 83 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 84 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 85 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 86 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 87 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 88 | golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= 89 | golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 90 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 91 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 92 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 93 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 94 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 95 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 96 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 97 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 98 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 99 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 100 | golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 101 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 102 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 103 | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= 104 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 105 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 106 | golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= 107 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 108 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 109 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 110 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 111 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 112 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 113 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 114 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 115 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 116 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 117 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 118 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= 119 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= 120 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 121 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 122 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 123 | google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= 124 | google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 125 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 126 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 127 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 128 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 129 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 130 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 131 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 132 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 133 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 134 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 135 | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= 136 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 137 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 138 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 139 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 140 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 141 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 142 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 143 | --------------------------------------------------------------------------------