diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index ec8918c634..2e38564d65 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -128,9 +128,8 @@ jobs: go-version: ${{ matrix.go-version }} - name: Build test binaries - # Exclude benchmarks as we don't run those in Docker run: | - go list -f '{{.Dir}}' ./... | egrep -v '(bench|vs|spectest)' | xargs -Ipkg go test pkg -c -o pkg.test + go list -f '{{.Dir}}' ./... | egrep -v '(vs|spectest)' | xargs -Ipkg go test pkg -c -o pkg.test go build -o wazerocli ./cmd/wazero env: GOARCH: ${{ matrix.arch }} @@ -167,28 +166,6 @@ jobs: - run: tinygo build ./cmd/wazero - run: tinygo build -size short -target pico -stack-size=8kb ./cmd/wazero - bench: - name: Benchmark - runs-on: ubuntu-22.04 - - steps: - # Unlike the other CGO libraries, WasmEdge requires offline installation. - - name: Install WasmEdge - run: | - wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -p /usr/local -v ${WASMEDGE_VERSION} - # The version here is coupled to internal/integration_test/go.mod, but it - # isn't always the same as sometimes the Go layer has a broken release. - env: - WASMEDGE_VERSION: 0.12.1 - - - uses: actions/checkout@v3 - - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - - run: make bench - # This ensures that internal/integration_test/fuzz is runnable, and is not intended to # run full-length fuzzing while trying to find low-hanging frontend bugs. fuzz: diff --git a/.github/workflows/examples.yaml b/.github/workflows/examples.yaml index 40f02f7702..36fecedb9b 100644 --- a/.github/workflows/examples.yaml +++ b/.github/workflows/examples.yaml @@ -104,9 +104,5 @@ jobs: source ./emsdk/emsdk_env.sh make build.examples.emscripten - - name: Build bench cases - run: make build.bench - if: matrix.go-version != '1.20' # fails with TinyGo v0.32.0 - - name: Run example tests run: make test.examples diff --git a/Makefile b/Makefile index e5ae8a2619..0f60d2d5ff 100644 --- a/Makefile +++ b/Makefile @@ -20,22 +20,6 @@ main_packages := $(sort $(foreach f,$(dir $(main_sources)),$(if $(findstring ./, go_test_options ?= -timeout 300s -ensureCompilerFastest := -ldflags '-X github.com/tetratelabs/wazero/internal/integration_test/vs.ensureCompilerFastest=true' -.PHONY: bench -bench: - @go build ./internal/integration_test/bench/... - @# Don't use -test.benchmem as it isn't accurate when comparing against CGO libs - @for d in vs/time vs/wasmedge vs/wasmtime ; do \ - cd ./internal/integration_test/$$d ; \ - go test -bench=. . -tags='wasmedge' $(ensureCompilerFastest) ; \ - cd - ;\ - done - -bench_testdata_dir := internal/integration_test/bench/testdata -.PHONY: build.bench -build.bench: - @tinygo build -o $(bench_testdata_dir)/case.wasm -scheduler=none --no-debug -target=wasi $(bench_testdata_dir)/case.go - .PHONY: test.examples test.examples: @go test $(go_test_options) ./examples/... ./imports/assemblyscript/example/... ./imports/emscripten/... ./imports/wasi_snapshot_preview1/example/... diff --git a/cache_test.go b/cache_test.go index 628adff93a..1953ab91f9 100644 --- a/cache_test.go +++ b/cache_test.go @@ -14,10 +14,10 @@ import ( "github.com/tetratelabs/wazero/internal/wasm" ) -//go:embed internal/integration_test/vs/testdata/fac.wasm +//go:embed testdata/fac.wasm var facWasm []byte -//go:embed internal/integration_test/vs/testdata/mem_grow.wasm +//go:embed testdata/mem_grow.wasm var memGrowWasm []byte func TestCompilationCache(t *testing.T) { diff --git a/internal/integration_test/vs/README.md b/internal/integration_test/vs/README.md deleted file mode 100644 index 183842567e..0000000000 --- a/internal/integration_test/vs/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# VS - -This directory contains tests which compare against other runtimes. As all -known alternatives use CGO, this contains its own [go.mod](go.mod), as -otherwise project dependencies are tainted and multi-platform tests more -difficult to manage. - -Examples of portability issues besides CGO -* Wasmtime can only be used in amd64 -* Wasmer doesn't link on Windows diff --git a/internal/integration_test/vs/bench.go b/internal/integration_test/vs/bench.go deleted file mode 100644 index 767f19deca..0000000000 --- a/internal/integration_test/vs/bench.go +++ /dev/null @@ -1,187 +0,0 @@ -package vs - -import ( - "context" - "fmt" - "os" - "path" - "runtime" - "sort" - "testing" - "text/tabwriter" - - "github.com/tetratelabs/wazero/internal/testing/require" -) - -// testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors. -var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary") - -// ensureCompilerFastest is overridable via ldflags. e.g. -// -// -ldflags '-X github.com/tetratelabs/wazero/internal/integration_test/vs.ensureCompilerFastest=true' -var ensureCompilerFastest = "false" - -const compilerRuntime = "wazero-compiler" - -// runTestBenchmark_Call_CompilerFastest ensures that Compiler is the fastest engine for function invocations. -// This is disabled by default, and can be run with -ldflags '-X github.com/tetratelabs/wazero/vs.ensureCompilerFastest=true'. -func runTestBenchmark_Call_CompilerFastest(t *testing.T, rtCfg *RuntimeConfig, name string, call func(Module, int) error, vsRuntime Runtime) { - if ensureCompilerFastest != "true" { - t.Skip() - } - - type benchResult struct { - name string - nsOp float64 - } - - results := make([]benchResult, 0, 2) - // Add the result for Compiler - compilerNsOp := runCallBenchmark(NewWazeroCompilerRuntime(), rtCfg, call) - results = append(results, benchResult{name: compilerRuntime, nsOp: compilerNsOp}) - - // Add a result for the runtime we're comparing against - vsNsOp := runCallBenchmark(vsRuntime, rtCfg, call) - results = append(results, benchResult{name: vsRuntime.Name(), nsOp: vsNsOp}) - - sort.Slice(results, func(i, j int) bool { - return results[i].nsOp < results[j].nsOp - }) - - // Print results before deciding if this failed - w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0) - _, _ = fmt.Fprintf(w, "Benchmark%s/Call-16\n", name) - for _, result := range results { - _, _ = fmt.Fprintf(w, "%s\t%.2f\tns/op\n", result.name, result.nsOp) - } - _ = w.Flush() - - // Fail if compiler wasn't fastest! - require.Equal(t, compilerRuntime, results[0].name, "%s is faster than %s. "+ - "Run with ensureCompilerFastest=false instead to see the detailed result", - results[0].name, compilerRuntime) -} - -func runCallBenchmark(rt Runtime, rtCfg *RuntimeConfig, call func(Module, int) error) float64 { - result := testing.Benchmark(func(b *testing.B) { - benchmarkCall(b, rt, rtCfg, call) - }) - // https://github.com/golang/go/blob/go1.20/src/testing/benchmark.go#L428-L432 - nsOp := float64(result.T.Nanoseconds()) / float64(result.N) - return nsOp -} - -func benchmark(b *testing.B, runtime func() Runtime, rtCfg *RuntimeConfig, call func(Module, int) error) { - rt := runtime() - b.Run("Compile", func(b *testing.B) { - b.ReportAllocs() - benchmarkCompile(b, rt, rtCfg) - }) - b.Run("Instantiate", func(b *testing.B) { - b.ReportAllocs() - benchmarkInstantiate(b, rt, rtCfg) - }) - - // Don't burn CPU when this is already going to be called in runTestBenchmark_Call_CompilerFastest - if call != nil && (ensureCompilerFastest != "true" || rt.Name() == compilerRuntime) { - b.Run("Call", func(b *testing.B) { - b.ReportAllocs() - benchmarkCall(b, rt, rtCfg, call) - }) - } -} - -func benchmarkCompile(b *testing.B, rt Runtime, rtCfg *RuntimeConfig) { - for i := 0; i < b.N; i++ { - if err := rt.Compile(testCtx, rtCfg); err != nil { - b.Fatal(err) - } - if err := rt.Close(testCtx); err != nil { - b.Fatal(err) - } - } -} - -func benchmarkInstantiate(b *testing.B, rt Runtime, rtCfg *RuntimeConfig) { - // Compile outside the benchmark loop - if err := rt.Compile(testCtx, rtCfg); err != nil { - b.Fatal(err) - } - defer rt.Close(testCtx) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - mod, err := rt.Instantiate(testCtx, rtCfg) - if err != nil { - b.Fatal(err) - } - err = mod.Close(testCtx) - if err != nil { - b.Fatal(err) - } - } -} - -func benchmarkCall(b *testing.B, rt Runtime, rtCfg *RuntimeConfig, call func(Module, int) error) { - // Initialize outside the benchmark loop - if err := rt.Compile(testCtx, rtCfg); err != nil { - b.Fatal(err) - } - defer rt.Close(testCtx) - mod, err := rt.Instantiate(testCtx, rtCfg) - if err != nil { - b.Fatal(err) - } - defer mod.Close(testCtx) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := call(mod, i); err != nil { - b.Fatal(err) - } - } -} - -func testCall(t *testing.T, runtime func() Runtime, rtCfg *RuntimeConfig, testCall func(*testing.T, Module, int, int)) { - rt := runtime() - err := rt.Compile(testCtx, rtCfg) - require.NoError(t, err) - defer rt.Close(testCtx) - - // Ensure the module can be re-instantiated times, even if not all runtimes allow renaming. - for i := 0; i < 10; i++ { - m, err := rt.Instantiate(testCtx, rtCfg) - require.NoError(t, err) - - // Large loop in test is only to show the function is stable (ex doesn't leak or crash on Nth use). - for j := 0; j < 1000; j++ { - testCall(t, m, i, j) - } - - require.NoError(t, m.Close(testCtx)) - } -} - -func testInstantiate(t *testing.T, runtime func() Runtime, rtCfg *RuntimeConfig) { - rt := runtime() - err := rt.Compile(testCtx, rtCfg) - require.NoError(t, err) - defer rt.Close(testCtx) - - // Ensure the module can be re-instantiated times, even if not all runtimes allow renaming. - for i := 0; i < 10; i++ { - m, err := rt.Instantiate(testCtx, rtCfg) - require.NoError(t, err) - require.NoError(t, m.Close(testCtx)) - } -} - -func readRelativeFile(relativePath string) []byte { - // We can't resolve relative paths as init() is called from each of its subdirs - _, source, _, _ := runtime.Caller(1) // 1 as this utility is in a different source than the caller. - realPath := path.Join(path.Dir(source), relativePath) - bytes, err := os.ReadFile(realPath) - if err != nil { - panic(err) - } - return bytes -} diff --git a/internal/integration_test/vs/bench_allocation.go b/internal/integration_test/vs/bench_allocation.go deleted file mode 100644 index 382b65d222..0000000000 --- a/internal/integration_test/vs/bench_allocation.go +++ /dev/null @@ -1,83 +0,0 @@ -package vs - -import ( - "bytes" - _ "embed" - "fmt" - "testing" - - "github.com/tetratelabs/wazero/internal/testing/require" -) - -var ( - // allocationWasm is compiled from ../../../examples/allocation/tinygo/testdata/src/greet.go - // We can't use go:embed as it is outside this directory. Copying it isn't ideal due to size and drift. - allocationWasmPath = "../../../examples/allocation/tinygo/testdata/greet.wasm" - allocationWasm []byte - allocationParam = "wazero" - allocationResult = []byte("wasm >> Hello, wazero!") - allocationConfig *RuntimeConfig -) - -func init() { - allocationWasm = readRelativeFile(allocationWasmPath) - allocationConfig = &RuntimeConfig{ - ModuleName: "greet", - ModuleWasm: allocationWasm, - FuncNames: []string{"malloc", "free", "greet"}, - NeedsWASI: true, // Needed for TinyGo - LogFn: func(buf []byte) error { - if !bytes.Equal(allocationResult, buf) { - return fmt.Errorf("expected %q, but was %q", allocationResult, buf) - } - return nil - }, - } -} - -func allocationCall(m Module, _ int) error { - nameSize := uint32(len(allocationParam)) - // Instead of an arbitrary memory offset, use TinyGo's allocator. Notice - // there is nothing string-specific in this allocation function. The same - // function could be used to pass binary serialized data to Wasm. - namePtr, err := m.CallI32_I32(testCtx, "malloc", nameSize) - if err != nil { - return err - } - - // The pointer is a linear memory offset, which is where we write the name. - if err = m.WriteMemory(namePtr, []byte(allocationParam)); err != nil { - return err - } - - // Now, we can call "greeting", which reads the string we wrote to memory! - fnErr := m.CallI32I32_V(testCtx, "greet", namePtr, nameSize) - if fnErr != nil { - return fnErr - } - - // This pointer was allocated by TinyGo, but owned by Go, So, we have to - // deallocate it when finished - if err := m.CallI32_V(testCtx, "free", namePtr); err != nil { - return err - } - - return nil -} - -func RunTestAllocation(t *testing.T, runtime func() Runtime) { - testCall(t, runtime, allocationConfig, testAllocationCall) -} - -func testAllocationCall(t *testing.T, m Module, instantiation, iteration int) { - err := allocationCall(m, iteration) - require.NoError(t, err, "instantiation[%d] iteration[%d] failed: %v", instantiation, iteration, err) -} - -func RunTestBenchmarkAllocation_Call_CompilerFastest(t *testing.T, vsRuntime Runtime) { - runTestBenchmark_Call_CompilerFastest(t, allocationConfig, "Allocation", allocationCall, vsRuntime) -} - -func RunBenchmarkAllocation(b *testing.B, runtime func() Runtime) { - benchmark(b, runtime, allocationConfig, allocationCall) -} diff --git a/internal/integration_test/vs/bench_factorial.go b/internal/integration_test/vs/bench_factorial.go deleted file mode 100644 index 7cb94284a8..0000000000 --- a/internal/integration_test/vs/bench_factorial.go +++ /dev/null @@ -1,48 +0,0 @@ -package vs - -import ( - _ "embed" - "testing" - - "github.com/tetratelabs/wazero/internal/testing/require" -) - -var ( - // catFS is an embedded filesystem limited to test.txt - //go:embed testdata/fac.wasm - factorialWasm []byte - factorialParam = uint64(30) - factorialResult = uint64(9682165104862298112) - factorialConfig *RuntimeConfig -) - -func init() { - factorialConfig = &RuntimeConfig{ - ModuleName: "math", - ModuleWasm: factorialWasm, - FuncNames: []string{"fac-ssa"}, - } -} - -func factorialCall(m Module, _ int) error { - _, err := m.CallI64_I64(testCtx, "fac-ssa", factorialParam) - return err -} - -func RunTestFactorial(t *testing.T, runtime func() Runtime) { - testCall(t, runtime, factorialConfig, testFactorialCall) -} - -func testFactorialCall(t *testing.T, m Module, instantiation, iteration int) { - res, err := m.CallI64_I64(testCtx, "fac-ssa", factorialParam) - require.NoError(t, err, "instantiation[%d] iteration[%d] failed", instantiation, iteration) - require.Equal(t, factorialResult, res) -} - -func RunTestBenchmarkFactorial_Call_CompilerFastest(t *testing.T, vsRuntime Runtime) { - runTestBenchmark_Call_CompilerFastest(t, factorialConfig, "Factorial", factorialCall, vsRuntime) -} - -func RunBenchmarkFactorial(b *testing.B, runtime func() Runtime) { - benchmark(b, runtime, factorialConfig, factorialCall) -} diff --git a/internal/integration_test/vs/bench_hostcall.go b/internal/integration_test/vs/bench_hostcall.go deleted file mode 100644 index 85502af358..0000000000 --- a/internal/integration_test/vs/bench_hostcall.go +++ /dev/null @@ -1,48 +0,0 @@ -package vs - -import ( - _ "embed" - "testing" - - "github.com/tetratelabs/wazero/internal/testing/require" -) - -var ( - //go:embed testdata/hostcall.wasm - hostCallWasm []byte - hostCallConfig *RuntimeConfig - hostCallFunction = "call_host_func" - hostCallParam = uint64(12345) -) - -func init() { - hostCallConfig = &RuntimeConfig{ - ModuleName: "hostcall", - ModuleWasm: hostCallWasm, - FuncNames: []string{hostCallFunction}, - EnvFReturnValue: 0xffff, - } -} - -func RunTestHostCall(t *testing.T, runtime func() Runtime) { - testCall(t, runtime, hostCallConfig, testHostCall) -} - -func testHostCall(t *testing.T, m Module, instantiation, iteration int) { - res, err := m.CallI64_I64(testCtx, hostCallFunction, hostCallParam) - require.NoError(t, err, "instantiation[%d] iteration[%d] failed", instantiation, iteration) - require.Equal(t, hostCallConfig.EnvFReturnValue, res) -} - -func RunTestBenchmarkHostCall_CompilerFastest(t *testing.T, vsRuntime Runtime) { - runTestBenchmark_Call_CompilerFastest(t, hostCallConfig, "HostCall_CrossBoundary", hostCall, vsRuntime) -} - -func RunBenchmarkHostCall(b *testing.B, runtime func() Runtime) { - benchmark(b, runtime, hostCallConfig, hostCall) -} - -func hostCall(m Module, _ int) error { - _, err := m.CallI64_I64(testCtx, hostCallFunction, hostCallParam) - return err -} diff --git a/internal/integration_test/vs/bench_memory.go b/internal/integration_test/vs/bench_memory.go deleted file mode 100644 index 4cc990366a..0000000000 --- a/internal/integration_test/vs/bench_memory.go +++ /dev/null @@ -1,98 +0,0 @@ -package vs - -import ( - _ "embed" - "encoding/binary" - "fmt" - "testing" - - "github.com/tetratelabs/wazero/internal/testing/require" -) - -const ( - i32 = "i32" - i32ValueMemoryOffset = 32 - i64 = "i64" - i64ValueMemoryOffset = 64 - inWasmIteration = 100 -) - -var ( - //go:embed testdata/memory.wasm - memoryWasm []byte - memoryConfig *RuntimeConfig - memoryFunctions = []string{i32, i64} -) - -func init() { - memoryConfig = &RuntimeConfig{ - ModuleName: "memory", - ModuleWasm: memoryWasm, - FuncNames: memoryFunctions, - NeedsMemoryExport: true, - } -} - -func RunTestMemory(t *testing.T, runtime func() Runtime) { - t.Run(i32, func(t *testing.T) { - testCall(t, runtime, memoryConfig, func(t *testing.T, m Module, instantiation int, iteration int) { - buf := m.Memory() - binary.LittleEndian.PutUint32(buf[i32ValueMemoryOffset:], inWasmIteration) - err := m.CallV_V(testCtx, i32) - require.NoError(t, err) - if 0 != binary.LittleEndian.Uint32(buf[i32ValueMemoryOffset:]) { - panic(fmt.Sprintf("BUG at iteration %d: %d", iteration, binary.LittleEndian.Uint32(buf[i32ValueMemoryOffset:]))) - } - }) - }) - - t.Run(i64, func(t *testing.T) { - testCall(t, runtime, memoryConfig, func(t *testing.T, m Module, instantiation int, iteration int) { - buf := m.Memory() - binary.LittleEndian.PutUint64(buf[i64ValueMemoryOffset:], inWasmIteration) - err := m.CallV_V(testCtx, i64) - require.NoError(t, err) - if 0 != binary.LittleEndian.Uint64(buf[i64ValueMemoryOffset:]) { - panic(fmt.Sprintf("BUG at iteration %d: %d", iteration, binary.LittleEndian.Uint64(buf[i32ValueMemoryOffset:]))) - } - }) - }) -} - -func RunTestBenchmarkMemory_CompilerFastest(t *testing.T, vsRuntime Runtime) { - t.Run(i32, func(t *testing.T) { - runTestBenchmark_Call_CompilerFastest(t, memoryConfig, "/memory.i32", memoryI32, vsRuntime) - }) - t.Run(i64, func(t *testing.T) { - runTestBenchmark_Call_CompilerFastest(t, memoryConfig, "/memory.i64", memoryI64, vsRuntime) - }) -} - -func RunBenchmarkMemory(b *testing.B, runtime func() Runtime) { - b.Run(i32, func(b *testing.B) { - benchmark(b, runtime, memoryConfig, memoryI32) - }) - b.Run(i64, func(b *testing.B) { - benchmark(b, runtime, memoryConfig, memoryI64) - }) -} - -func memoryI32(m Module, iteration int) (err error) { - buf := m.Memory() - binary.LittleEndian.PutUint32(buf[i32ValueMemoryOffset:], inWasmIteration) - err = m.CallV_V(testCtx, i32) - if 0 != binary.LittleEndian.Uint32(buf[i32ValueMemoryOffset:]) { - panic(fmt.Sprintf("BUG at iteration %d", iteration)) - } - return -} - -func memoryI64(m Module, iteration int) (err error) { - buf := m.Memory() - binary.LittleEndian.PutUint64(buf[i64ValueMemoryOffset:], inWasmIteration) - err = m.CallV_V(testCtx, i64) - if 0 != binary.LittleEndian.Uint64(buf[i64ValueMemoryOffset:]) { - panic(fmt.Sprintf("BUG at iteration %d", iteration)) - } - return -} diff --git a/internal/integration_test/vs/bench_shorthash.go b/internal/integration_test/vs/bench_shorthash.go deleted file mode 100644 index b5d112ba88..0000000000 --- a/internal/integration_test/vs/bench_shorthash.go +++ /dev/null @@ -1,33 +0,0 @@ -package vs - -import ( - _ "embed" - "testing" -) - -var ( - // shorthashWasm is a wasi binary which runs the same wasm function inside - // a loop. See https://github.com/tetratelabs/wazero/issues/947 - // - // Taken from https://github.com/jedisct1/webassembly-benchmarks/tree/master/2022-12/wasm - //go:embed testdata/shorthash.wasm - shorthashWasm []byte - shorthashConfig *RuntimeConfig -) - -func init() { - shorthashConfig = &RuntimeConfig{ - ModuleName: "shorthash", - ModuleWasm: shorthashWasm, - NeedsWASI: true, // runs as a _start function - } -} - -func RunTestShorthash(t *testing.T, runtime func() Runtime) { - // not testCall as there are no exported functions except _start - testInstantiate(t, runtime, shorthashConfig) -} - -func RunBenchmarkShorthash(b *testing.B, runtime func() Runtime) { - benchmark(b, runtime, shorthashConfig, nil) -} diff --git a/internal/integration_test/vs/compiler/compiler_test.go b/internal/integration_test/vs/compiler/compiler_test.go deleted file mode 100644 index 2c711f9e4d..0000000000 --- a/internal/integration_test/vs/compiler/compiler_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package compiler - -import ( - "testing" - - "github.com/tetratelabs/wazero/internal/integration_test/vs" -) - -var runtime = vs.NewWazeroCompilerRuntime - -func TestAllocation(t *testing.T) { - vs.RunTestAllocation(t, runtime) -} - -func BenchmarkAllocation(b *testing.B) { - vs.RunBenchmarkAllocation(b, runtime) -} - -func TestFactorial(t *testing.T) { - vs.RunTestFactorial(t, runtime) -} - -func BenchmarkFactorial(b *testing.B) { - vs.RunBenchmarkFactorial(b, runtime) -} - -func TestHostCall(t *testing.T) { - vs.RunTestHostCall(t, runtime) -} - -func BenchmarkHostCall(b *testing.B) { - vs.RunBenchmarkHostCall(b, runtime) -} - -func TestMemory(t *testing.T) { - vs.RunTestMemory(t, runtime) -} - -func BenchmarkMemory(b *testing.B) { - vs.RunBenchmarkMemory(b, runtime) -} - -func TestShorthash(t *testing.T) { - vs.RunTestShorthash(t, runtime) -} - -func BenchmarkShorthash(b *testing.B) { - vs.RunBenchmarkShorthash(b, runtime) -} diff --git a/internal/integration_test/vs/interpreter/interpreter_test.go b/internal/integration_test/vs/interpreter/interpreter_test.go deleted file mode 100644 index 84090af8bf..0000000000 --- a/internal/integration_test/vs/interpreter/interpreter_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package interpreter - -import ( - "testing" - - "github.com/tetratelabs/wazero/internal/integration_test/vs" -) - -var runtime = vs.NewWazeroInterpreterRuntime - -func TestAllocation(t *testing.T) { - vs.RunTestAllocation(t, runtime) -} - -func BenchmarkAllocation(b *testing.B) { - vs.RunBenchmarkAllocation(b, runtime) -} - -func TestBenchmarkAllocation_Call_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkAllocation_Call_CompilerFastest(t, runtime()) -} - -func TestFactorial(t *testing.T) { - vs.RunTestFactorial(t, runtime) -} - -func BenchmarkFactorial(b *testing.B) { - vs.RunBenchmarkFactorial(b, runtime) -} - -func TestBenchmarkFactorial_Call_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkFactorial_Call_CompilerFastest(t, runtime()) -} - -func TestHostCall(t *testing.T) { - vs.RunTestHostCall(t, runtime) -} - -func BenchmarkHostCall(b *testing.B) { - vs.RunBenchmarkHostCall(b, runtime) -} - -func TestBenchmarkHostCall_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkHostCall_CompilerFastest(t, runtime()) -} - -func TestMemory(t *testing.T) { - vs.RunTestMemory(t, runtime) -} - -func BenchmarkMemory(b *testing.B) { - vs.RunBenchmarkMemory(b, runtime) -} - -func TestBenchmarkMemory_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkMemory_CompilerFastest(t, runtime()) -} diff --git a/internal/integration_test/vs/runtime.go b/internal/integration_test/vs/runtime.go deleted file mode 100644 index 2c2a7b4e72..0000000000 --- a/internal/integration_test/vs/runtime.go +++ /dev/null @@ -1,220 +0,0 @@ -package vs - -import ( - "context" - "errors" - "fmt" - - "github.com/tetratelabs/wazero" - "github.com/tetratelabs/wazero/api" - "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" - "github.com/tetratelabs/wazero/internal/wasm" -) - -type RuntimeConfig struct { - Name string - ModuleName string - ModuleWasm []byte - FuncNames []string - NeedsWASI bool - NeedsMemoryExport bool - // LogFn requires the implementation to export a function "env.log" which accepts i32i32_v. - // The implementation invoke this with a byte slice allocated from the offset, length pair. - // This function simulates a host function that logs a message. - LogFn func([]byte) error - // EnvFReturnValue is set to non-zero if we want the runtime to instantiate "env" module with the function "f" - // which accepts one i64 value and returns the EnvFReturnValue as i64. This is mutually exclusive to LogFn. - EnvFReturnValue uint64 -} - -type Runtime interface { - Name() string - Compile(context.Context, *RuntimeConfig) error - Instantiate(context.Context, *RuntimeConfig) (Module, error) - Close(context.Context) error -} - -type Module interface { - CallI32_I32(ctx context.Context, funcName string, param uint32) (uint32, error) - CallI32I32_V(ctx context.Context, funcName string, x, y uint32) error - CallI32_V(ctx context.Context, funcName string, param uint32) error - CallV_V(ctx context.Context, funcName string) error - CallI64_I64(ctx context.Context, funcName string, param uint64) (uint64, error) - WriteMemory(offset uint32, bytes []byte) error - Memory() []byte - Close(context.Context) error -} - -func NewWazeroInterpreterRuntime() Runtime { - return newWazeroRuntime("wazero-interpreter", wazero.NewRuntimeConfigInterpreter()) -} - -func NewWazeroCompilerRuntime() Runtime { - return newWazeroRuntime(compilerRuntime, wazero.NewRuntimeConfigCompiler()) -} - -func newWazeroRuntime(name string, config wazero.RuntimeConfig) *wazeroRuntime { - return &wazeroRuntime{name: name, config: config} -} - -type wazeroRuntime struct { - name string - config wazero.RuntimeConfig - runtime wazero.Runtime - logFn func([]byte) error - env, compiled wazero.CompiledModule -} - -type wazeroModule struct { - wasi api.Closer - env, mod api.Module - funcs map[string]api.Function -} - -func (r *wazeroRuntime) Name() string { - return r.name -} - -func (m *wazeroModule) Memory() []byte { - return m.mod.Memory().(*wasm.MemoryInstance).Buffer -} - -func (r *wazeroRuntime) log(_ context.Context, mod api.Module, stack []uint64) { - offset, byteCount := uint32(stack[0]), uint32(stack[1]) - - buf, ok := mod.Memory().Read(offset, byteCount) - if !ok { - panic("out of memory reading log buffer") - } - if err := r.logFn(buf); err != nil { - panic(err) - } -} - -func (r *wazeroRuntime) Compile(ctx context.Context, cfg *RuntimeConfig) (err error) { - r.runtime = wazero.NewRuntimeWithConfig(ctx, r.config) - if cfg.LogFn != nil { - r.logFn = cfg.LogFn - if r.env, err = r.runtime.NewHostModuleBuilder("env"). - NewFunctionBuilder(). - WithGoModuleFunction(api.GoModuleFunc(r.log), []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{}). - Export("log"). - Compile(ctx); err != nil { - return err - } - } else if cfg.EnvFReturnValue != 0 { - if r.env, err = r.runtime.NewHostModuleBuilder("env"). - NewFunctionBuilder(). - WithGoFunction(api.GoFunc(func(ctx context.Context, stack []uint64) { - stack[0] = cfg.EnvFReturnValue - }), []api.ValueType{api.ValueTypeI64}, []api.ValueType{api.ValueTypeI64}). - Export("f"). - Compile(ctx); err != nil { - return err - } - } - r.compiled, err = r.runtime.CompileModule(ctx, cfg.ModuleWasm) - return -} - -func (r *wazeroRuntime) Instantiate(ctx context.Context, cfg *RuntimeConfig) (mod Module, err error) { - wazeroCfg := wazero.NewModuleConfig().WithName(cfg.ModuleName) - m := &wazeroModule{funcs: map[string]api.Function{}} - - // Instantiate WASI, if configured. - if cfg.NeedsWASI { - if m.wasi, err = wasi_snapshot_preview1.Instantiate(ctx, r.runtime); err != nil { - return - } - } - - // Instantiate the host module, "env", if configured. - if env := r.env; env != nil { - if m.env, err = r.runtime.InstantiateModule(ctx, env, wazero.NewModuleConfig()); err != nil { - return - } - } - - // Instantiate the module. - if m.mod, err = r.runtime.InstantiateModule(ctx, r.compiled, wazeroCfg); err != nil { - return - } - - // Ensure function exports exist. - for _, funcName := range cfg.FuncNames { - if fn := m.mod.ExportedFunction(funcName); fn == nil { - return nil, fmt.Errorf("%s is not an exported function", funcName) - } else { - m.funcs[funcName] = fn - } - } - mod = m - return -} - -func (r *wazeroRuntime) Close(ctx context.Context) (err error) { - if compiled := r.compiled; compiled != nil { - err = compiled.Close(ctx) - } - r.compiled = nil - if env := r.env; env != nil { - err = env.Close(ctx) - } - r.env = nil - return -} - -func (m *wazeroModule) CallV_V(ctx context.Context, funcName string) (err error) { - _, err = m.funcs[funcName].Call(ctx) - return -} - -func (m *wazeroModule) CallI32_I32(ctx context.Context, funcName string, param uint32) (uint32, error) { - if results, err := m.funcs[funcName].Call(ctx, uint64(param)); err != nil { - return 0, err - } else if len(results) > 0 { - return uint32(results[0]), nil - } - return 0, nil -} - -func (m *wazeroModule) CallI32I32_V(ctx context.Context, funcName string, x, y uint32) (err error) { - _, err = m.funcs[funcName].Call(ctx, uint64(x), uint64(y)) - return -} - -func (m *wazeroModule) CallI32_V(ctx context.Context, funcName string, param uint32) (err error) { - _, err = m.funcs[funcName].Call(ctx, uint64(param)) - return -} - -func (m *wazeroModule) CallI64_I64(ctx context.Context, funcName string, param uint64) (uint64, error) { - if results, err := m.funcs[funcName].Call(ctx, param); err != nil { - return 0, err - } else { - return results[0], nil - } -} - -func (m *wazeroModule) WriteMemory(offset uint32, bytes []byte) error { - if !m.mod.Memory().Write(offset, bytes) { - return errors.New("out of memory writing name") - } - return nil -} - -func (m *wazeroModule) Close(ctx context.Context) (err error) { - if mod := m.mod; mod != nil { - err = mod.Close(ctx) - } - m.mod = nil - if env := m.env; env != nil { - err = env.Close(ctx) - } - m.env = nil - if wasi := m.wasi; wasi != nil { - err = wasi.Close(ctx) - } - m.wasi = nil - return -} diff --git a/internal/integration_test/vs/testdata/hostcall.wasm b/internal/integration_test/vs/testdata/hostcall.wasm deleted file mode 100644 index 79c8494084..0000000000 Binary files a/internal/integration_test/vs/testdata/hostcall.wasm and /dev/null differ diff --git a/internal/integration_test/vs/testdata/hostcall.wat b/internal/integration_test/vs/testdata/hostcall.wat deleted file mode 100644 index 8d4e7ec342..0000000000 --- a/internal/integration_test/vs/testdata/hostcall.wat +++ /dev/null @@ -1,9 +0,0 @@ -(module - ;; env.f must be a host function for benchmarks on the cost of host calls which cross the Wasm<>Go boundary. - (func $host_func (import "env" "f") (param i64) (result i64)) - ;; call_host_func calls "env.f" and returns the resut as-is. - (func (export "call_host_func") (param i64) (result i64) - local.get 0 - call $host_func - ) -) diff --git a/internal/integration_test/vs/testdata/mem_grow.wasm b/internal/integration_test/vs/testdata/mem_grow.wasm deleted file mode 100644 index a2c9f66d0f..0000000000 Binary files a/internal/integration_test/vs/testdata/mem_grow.wasm and /dev/null differ diff --git a/internal/integration_test/vs/testdata/memory.wasm b/internal/integration_test/vs/testdata/memory.wasm deleted file mode 100644 index dc1be3d3f3..0000000000 Binary files a/internal/integration_test/vs/testdata/memory.wasm and /dev/null differ diff --git a/internal/integration_test/vs/testdata/memory.wat b/internal/integration_test/vs/testdata/memory.wat deleted file mode 100644 index c32bf2d45f..0000000000 --- a/internal/integration_test/vs/testdata/memory.wat +++ /dev/null @@ -1,31 +0,0 @@ -(module - (memory (export "memory") 1) - - ;; Load the i32 value at the offset 32, decrement it, and store it back at the same position - ;; until the value becomes zero. - (func (export "i32") - (loop - i32.const 32 - (i32.load align=1 (i32.const 32)) - i32.const 1 - i32.sub - i32.store - (br_if 1 (i32.eqz (i32.load align=1 (i32.const 32)))) ;; exit. - (br 0) ;; continue loop. - ) - ) - - ;; Load the i64 value at the offset 64, decrement it, and store it back at the same position - ;; until the value becomes zero. - (func (export "i64") - (loop - i32.const 64 - (i64.load align=1 (i32.const 64)) - i64.const 1 - i64.sub - i64.store - (br_if 1 (i64.eqz (i64.load align=1 (i32.const 64)))) ;; exit. - (br 0) ;; continue loop. - ) - ) -) diff --git a/internal/integration_test/vs/testdata/shorthash.wasm b/internal/integration_test/vs/testdata/shorthash.wasm deleted file mode 100644 index 7e0c0e01ba..0000000000 Binary files a/internal/integration_test/vs/testdata/shorthash.wasm and /dev/null differ diff --git a/internal/integration_test/vs/time/go.mod b/internal/integration_test/vs/time/go.mod deleted file mode 100644 index bd65ba3b1a..0000000000 --- a/internal/integration_test/vs/time/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/tetratelabs/wazero/internal/integration_test/vs/clock - -go 1.20 - -require golang.org/x/sys v0.1.0 - -replace github.com/tetratelabs/wazero => ../../../.. diff --git a/internal/integration_test/vs/time/go.sum b/internal/integration_test/vs/time/go.sum deleted file mode 100644 index b69ea85753..0000000000 --- a/internal/integration_test/vs/time/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/integration_test/vs/time/time_test.go b/internal/integration_test/vs/time/time_test.go deleted file mode 100644 index 07de8e2977..0000000000 --- a/internal/integration_test/vs/time/time_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Package time benchmarks shows ways to implementing the platform clock more -// efficiently. As long as CGO is available, all platforms can use -// `runtime.nanotime` to more efficiently implement sys.Nanotime vs using -// time.Since or x/sys. -// -// While results would be more impressive, this doesn't show how to use -// `runtime.walltime` to avoid the double-performance vs using time.Now. The -// corresponding function only exists in darwin, so prevents this benchmark -// from running on other platforms. -package time - -import ( - "testing" - "time" - _ "unsafe" // for go:linkname - - "golang.org/x/sys/unix" -) - -//go:linkname nanotime runtime.nanotime -func nanotime() int64 - -func BenchmarkClock(b *testing.B) { - b.Run("time.Now", func(b *testing.B) { - for i := 0; i < b.N; i++ { - _ = time.Now() - } - }) - b.Run("ClockGettime(CLOCK_REALTIME)", func(b *testing.B) { - for i := 0; i < b.N; i++ { - var now unix.Timespec - if err := unix.ClockGettime(unix.CLOCK_REALTIME, &now); err != nil { - b.Fatal(err) - } - } - }) - - base := time.Now() - b.Run("time.Since", func(b *testing.B) { - for i := 0; i < b.N; i++ { - _ = time.Since(base) - } - }) - b.Run("runtime.nanotime", func(b *testing.B) { - for i := 0; i < b.N; i++ { - _ = nanotime() - } - }) - b.Run("ClockGettime(CLOCK_MONOTONIC)", func(b *testing.B) { - for i := 0; i < b.N; i++ { - var tick unix.Timespec - if err := unix.ClockGettime(unix.CLOCK_MONOTONIC, &tick); err != nil { - b.Fatal(err) - } - } - }) -} diff --git a/internal/integration_test/vs/wasmedge/go.mod b/internal/integration_test/vs/wasmedge/go.mod deleted file mode 100644 index a31d814535..0000000000 --- a/internal/integration_test/vs/wasmedge/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/tetratelabs/wazero/internal/integration_test/vs/wasmedge - -go 1.20 - -require ( - github.com/second-state/WasmEdge-go v0.12.1 - github.com/tetratelabs/wazero v0.0.0 -) - -replace github.com/tetratelabs/wazero => ../../../.. diff --git a/internal/integration_test/vs/wasmedge/go.sum b/internal/integration_test/vs/wasmedge/go.sum deleted file mode 100644 index 4241498b65..0000000000 --- a/internal/integration_test/vs/wasmedge/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/second-state/WasmEdge-go v0.12.1 h1:rIRiRF35+8CtcYTsiW4KfFNIh3faRb3LoG2c7cCqQyI= -github.com/second-state/WasmEdge-go v0.12.1/go.mod h1:HyBf9hVj1sRAjklsjc1Yvs9b5RcmthPG9z99dY78TKg= diff --git a/internal/integration_test/vs/wasmedge/wasmedge.go b/internal/integration_test/vs/wasmedge/wasmedge.go deleted file mode 100644 index 50798d3fa3..0000000000 --- a/internal/integration_test/vs/wasmedge/wasmedge.go +++ /dev/null @@ -1,200 +0,0 @@ -//go:build cgo && !windows && wasmedge - -// Note: WasmEdge depends on manual installation of a shared library. -// e.g. wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | \ -// sudo bash -s -- -p /usr/local -e none -v ${WASMEDGE_VERSION} - -package wasmedge - -import ( - "context" - "fmt" - "os" - - "github.com/second-state/WasmEdge-go/wasmedge" - - "github.com/tetratelabs/wazero/internal/integration_test/vs" -) - -func newWasmedgeRuntime() vs.Runtime { - return &wasmedgeRuntime{} -} - -type wasmedgeRuntime struct { - conf *wasmedge.Configure - logFn func([]byte) error -} - -type wasmedgeModule struct { - store *wasmedge.Store - vm *wasmedge.VM - env *wasmedge.Module -} - -func (r *wasmedgeRuntime) Name() string { - return "wasmedge" -} - -func (r *wasmedgeRuntime) log(_ interface{}, callframe *wasmedge.CallingFrame, params []interface{}) ([]interface{}, wasmedge.Result) { - offset := params[0].(int32) - byteCount := params[1].(int32) - mem := callframe.GetMemoryByIndex(0) - buf, err := mem.GetData(uint(offset), uint(byteCount)) - if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - return nil, wasmedge.Result_Fail - } - if err = r.logFn(buf); err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - panic(err) - } - return nil, wasmedge.Result_Success -} - -func (r *wasmedgeRuntime) Compile(_ context.Context, cfg *vs.RuntimeConfig) (err error) { - if cfg.NeedsWASI { - r.conf = wasmedge.NewConfigure(wasmedge.WASI) - } else { - r.conf = wasmedge.NewConfigure() - } - // We can't re-use a store because "module name conflict" occurs even after releasing a VM - return -} - -func (r *wasmedgeRuntime) Instantiate(_ context.Context, cfg *vs.RuntimeConfig) (mod vs.Module, err error) { - m := &wasmedgeModule{store: wasmedge.NewStore()} - m.vm = wasmedge.NewVMWithConfigAndStore(r.conf, m.store) - - // Instantiate WASI, if configured. - if cfg.NeedsWASI { - wasi := m.vm.GetImportModule(wasmedge.WASI) - wasi.InitWasi(nil, nil, nil) - } - - // Instantiate the host module, "env", if configured. - if cfg.LogFn != nil { - r.logFn = cfg.LogFn - m.env = wasmedge.NewModule("env") - logType := wasmedge.NewFunctionType([]wasmedge.ValType{wasmedge.ValType_I32, wasmedge.ValType_I32}, nil) - m.env.AddFunction("log", wasmedge.NewFunction(logType, r.log, nil, 0)) - if err = m.vm.RegisterModule(m.env); err != nil { - return nil, err - } - } else if cfg.EnvFReturnValue != 0 { - m.env = wasmedge.NewModule("env") - fType := wasmedge.NewFunctionType([]wasmedge.ValType{wasmedge.ValType_I64}, []wasmedge.ValType{wasmedge.ValType_I64}) - m.env.AddFunction("f", wasmedge.NewFunction(fType, func(interface{}, *wasmedge.CallingFrame, []interface{}) ([]interface{}, wasmedge.Result) { - return []interface{}{int64(cfg.EnvFReturnValue)}, wasmedge.Result_Success - }, nil, 0)) - if err = m.vm.RegisterModule(m.env); err != nil { - return nil, err - } - } - - // Instantiate the module. - if err = m.vm.RegisterWasmBuffer(cfg.ModuleName, cfg.ModuleWasm); err != nil { - return - } - if err = m.vm.LoadWasmBuffer(cfg.ModuleWasm); err != nil { - return - } - if err = m.vm.Validate(); err != nil { - return - } - if err = m.vm.Instantiate(); err != nil { - return - } - - // If WASI is needed, we have to go back and invoke the _start function. - if cfg.NeedsWASI { - if _, err = m.vm.Execute("_start"); err != nil { - return - } - } - - // Ensure function exports exist. - for _, funcName := range cfg.FuncNames { - if fn := m.vm.GetFunctionType(funcName); fn == nil { - err = fmt.Errorf("%s is not an exported function", funcName) - return - } - } - - mod = m - return -} - -func (r *wasmedgeRuntime) Close(context.Context) error { - if conf := r.conf; conf != nil { - conf.Release() - } - r.conf = nil - return nil -} - -func (m *wasmedgeModule) Memory() []byte { - mod := m.vm.GetActiveModule() - mem := mod.FindMemory("memory") - d, err := mem.GetData(0, mem.GetPageSize()*65536) - if err != nil { - panic(err) - } - return d -} - -func (m *wasmedgeModule) CallI32_I32(_ context.Context, funcName string, param uint32) (uint32, error) { - if result, err := m.vm.Execute(funcName, int32(param)); err != nil { - return 0, err - } else { - return uint32(result[0].(int32)), nil - } -} - -func (m *wasmedgeModule) CallI32I32_V(_ context.Context, funcName string, x, y uint32) (err error) { - _, err = m.vm.Execute(funcName, int32(x), int32(y)) - return -} - -func (m *wasmedgeModule) CallV_V(_ context.Context, funcName string) (err error) { - _, err = m.vm.Execute(funcName) - return -} - -func (m *wasmedgeModule) CallI32_V(_ context.Context, funcName string, param uint32) (err error) { - _, err = m.vm.Execute(funcName, int32(param)) - return -} - -func (m *wasmedgeModule) CallI64_I64(_ context.Context, funcName string, param uint64) (uint64, error) { - if result, err := m.vm.Execute(funcName, int64(param)); err != nil { - return 0, err - } else { - return uint64(result[0].(int64)), nil - } -} - -func (m *wasmedgeModule) WriteMemory(offset uint32, bytes []byte) error { - mod := m.vm.GetActiveModule() - mem := mod.FindMemory("memory") - if unsafeSlice, err := mem.GetData(uint(offset), uint(len(bytes))); err != nil { - return err - } else { - copy(unsafeSlice, bytes) - } - return nil -} - -func (m *wasmedgeModule) Close(context.Context) error { - if env := m.env; env != nil { - env.Release() - } - if vm := m.vm; vm != nil { - vm.Release() - } - m.vm = nil - if store := m.store; store != nil { - store.Release() - } - m.store = nil - return nil -} diff --git a/internal/integration_test/vs/wasmedge/wasmedge_test.go b/internal/integration_test/vs/wasmedge/wasmedge_test.go deleted file mode 100644 index 1f20c11d07..0000000000 --- a/internal/integration_test/vs/wasmedge/wasmedge_test.go +++ /dev/null @@ -1,61 +0,0 @@ -//go:build cgo && wasmedge - -// wasmedge depends on manual installation of a shared library, so is guarded by a flag by default. - -package wasmedge - -import ( - "testing" - - "github.com/tetratelabs/wazero/internal/integration_test/vs" -) - -var runtime = newWasmedgeRuntime - -func TestAllocation(t *testing.T) { - vs.RunTestAllocation(t, runtime) -} - -func BenchmarkAllocation(b *testing.B) { - vs.RunBenchmarkAllocation(b, runtime) -} - -func TestBenchmarkAllocation_Call_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkAllocation_Call_CompilerFastest(t, runtime()) -} - -func TestFactorial(t *testing.T) { - vs.RunTestFactorial(t, runtime) -} - -func BenchmarkFactorial(b *testing.B) { - vs.RunBenchmarkFactorial(b, runtime) -} - -func TestBenchmarkFactorial_Call_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkFactorial_Call_CompilerFastest(t, runtime()) -} - -func TestHostCall(t *testing.T) { - vs.RunTestHostCall(t, runtime) -} - -func BenchmarkHostCall(b *testing.B) { - vs.RunBenchmarkHostCall(b, runtime) -} - -func TestBenchmarkHostCall_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkHostCall_CompilerFastest(t, runtime()) -} - -func TestMemory(t *testing.T) { - vs.RunTestMemory(t, runtime) -} - -func BenchmarkMemory(b *testing.B) { - vs.RunBenchmarkMemory(b, runtime) -} - -func TestBenchmarkMemory_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkMemory_CompilerFastest(t, runtime()) -} diff --git a/internal/integration_test/vs/wasmtime/go.mod b/internal/integration_test/vs/wasmtime/go.mod deleted file mode 100644 index f886f6d140..0000000000 --- a/internal/integration_test/vs/wasmtime/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/tetratelabs/wazero/internal/integration_test/vs/wasmtime - -go 1.20 - -require ( - github.com/bytecodealliance/wasmtime-go/v9 v9.0.0 - github.com/tetratelabs/wazero v0.0.0 -) - -replace github.com/tetratelabs/wazero => ../../../.. diff --git a/internal/integration_test/vs/wasmtime/go.sum b/internal/integration_test/vs/wasmtime/go.sum deleted file mode 100644 index 70e6ef7f05..0000000000 --- a/internal/integration_test/vs/wasmtime/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -github.com/bytecodealliance/wasmtime-go/v9 v9.0.0 h1:lkyiPbbo++bSmDyJVxDQwxxaiu3LOFVm0iBHnTS1W5A= -github.com/bytecodealliance/wasmtime-go/v9 v9.0.0/go.mod h1:zpOxt1j5vj44AzXZVhS4H+hr39vMk4hDlyC42kGksbU= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/integration_test/vs/wasmtime/wasmtime.go b/internal/integration_test/vs/wasmtime/wasmtime.go deleted file mode 100644 index 9ba1794aec..0000000000 --- a/internal/integration_test/vs/wasmtime/wasmtime.go +++ /dev/null @@ -1,205 +0,0 @@ -//go:build cgo - -package wasmtime - -import ( - "context" - "fmt" - - wt "github.com/bytecodealliance/wasmtime-go/v9" - - "github.com/tetratelabs/wazero/internal/integration_test/vs" -) - -func newWasmtimeRuntime() vs.Runtime { - return &wasmtimeRuntime{} -} - -type wasmtimeRuntime struct { - engine *wt.Engine - module *wt.Module -} - -type wasmtimeModule struct { - store *wt.Store - // instance is here because there's no close/destroy function. The only thing is garbage collection. - instance *wt.Instance - funcs map[string]*wt.Func - logFn func([]byte) error - mem *wt.Memory -} - -func (r *wasmtimeRuntime) Name() string { - return "wasmtime" -} - -func (m *wasmtimeModule) log(_ *wt.Caller, args []wt.Val) ([]wt.Val, *wt.Trap) { - unsafeSlice := m.mem.UnsafeData(m.store) - offset := args[0].I32() - byteCount := args[1].I32() - if err := m.logFn(unsafeSlice[offset : offset+byteCount]); err != nil { - return nil, wt.NewTrap(err.Error()) - } - return []wt.Val{}, nil -} - -func (r *wasmtimeRuntime) Compile(_ context.Context, cfg *vs.RuntimeConfig) (err error) { - r.engine = wt.NewEngine() - if r.module, err = wt.NewModule(r.engine, cfg.ModuleWasm); err != nil { - return - } - return -} - -func (r *wasmtimeRuntime) Instantiate(_ context.Context, cfg *vs.RuntimeConfig) (mod vs.Module, err error) { - wm := &wasmtimeModule{funcs: map[string]*wt.Func{}} - - // We can't reuse a store because even if we call close, re-instantiating too many times leads to: - // >> resource limit exceeded: instance count too high at 10001 - wm.store = wt.NewStore(r.engine) - linker := wt.NewLinker(wm.store.Engine) - - // Instantiate WASI, if configured. - if cfg.NeedsWASI { - if err = linker.DefineWasi(); err != nil { - return - } - config := wt.NewWasiConfig() // defaults to toss stdout - config.InheritStderr() // see errors - wm.store.SetWasi(config) - } - - // Instantiate the host module, "env", if configured. - if cfg.LogFn != nil { - wm.logFn = cfg.LogFn - if err = linker.Define(wm.store, "env", "log", wt.NewFunc( - wm.store, - wt.NewFuncType( - []*wt.ValType{ - wt.NewValType(wt.KindI32), - wt.NewValType(wt.KindI32), - }, - []*wt.ValType{}, - ), - wm.log, - )); err != nil { - return - } - } else if cfg.EnvFReturnValue != 0 { - ret := []wt.Val{wt.ValI64(int64(cfg.EnvFReturnValue))} - if err = linker.Define(wm.store, "env", "f", wt.NewFunc( - wm.store, - wt.NewFuncType( - []*wt.ValType{ - wt.NewValType(wt.KindI64), - }, - []*wt.ValType{wt.NewValType(wt.KindI64)}, - ), - func(_ *wt.Caller, args []wt.Val) ([]wt.Val, *wt.Trap) { - return ret, nil - }, - )); err != nil { - return - } - } - - // Set the module name. - if err = linker.DefineModule(wm.store, cfg.ModuleName, r.module); err != nil { - return - } - - // Instantiate the module. - instance, instantiateErr := linker.Instantiate(wm.store, r.module) - if instantiateErr != nil { - err = instantiateErr - return - } - - if cfg.LogFn != nil || cfg.NeedsMemoryExport { - // Wasmtime does not allow a host function parameter for memory, so you have to manually propagate it. - if wm.mem = instance.GetExport(wm.store, "memory").Memory(); wm.mem == nil { - err = fmt.Errorf(`"memory" not exported`) - return - } - } - - // If WASI is needed, we have to go back and invoke the _start function. - if cfg.NeedsWASI { - start := instance.GetFunc(wm.store, "_start") - if _, err = start.Call(wm.store); err != nil { - return - } - } - - // Ensure function exports exist. - for _, funcName := range cfg.FuncNames { - if fn := instance.GetFunc(wm.store, funcName); fn == nil { - err = fmt.Errorf("%s is not an exported function", funcName) - return - } else { - wm.funcs[funcName] = fn - } - } - - mod = wm - return -} - -func (r *wasmtimeRuntime) Close(context.Context) error { - r.module = nil - r.engine = nil - return nil // wt only closes via finalizer -} - -func (m *wasmtimeModule) Memory() []byte { - return m.mem.UnsafeData(m.store) -} - -func (m *wasmtimeModule) CallI32_I32(_ context.Context, funcName string, param uint32) (uint32, error) { - fn := m.funcs[funcName] - if result, err := fn.Call(m.store, int32(param)); err != nil { - return 0, err - } else { - return uint32(result.(int32)), nil - } -} - -func (m *wasmtimeModule) CallI32I32_V(_ context.Context, funcName string, x, y uint32) (err error) { - fn := m.funcs[funcName] - _, err = fn.Call(m.store, int32(x), int32(y)) - return -} - -func (m *wasmtimeModule) CallV_V(_ context.Context, funcName string) (err error) { - fn := m.funcs[funcName] - _, err = fn.Call(m.store) - return -} - -func (m *wasmtimeModule) CallI32_V(_ context.Context, funcName string, param uint32) (err error) { - fn := m.funcs[funcName] - _, err = fn.Call(m.store, int32(param)) - return -} - -func (m *wasmtimeModule) CallI64_I64(_ context.Context, funcName string, param uint64) (uint64, error) { - fn := m.funcs[funcName] - if result, err := fn.Call(m.store, int64(param)); err != nil { - return 0, err - } else { - return uint64(result.(int64)), nil - } -} - -func (m *wasmtimeModule) WriteMemory(offset uint32, bytes []byte) error { - unsafeSlice := m.mem.UnsafeData(m.store) - copy(unsafeSlice[offset:], bytes) - return nil -} - -func (m *wasmtimeModule) Close(context.Context) error { - m.store = nil - m.instance = nil - m.funcs = nil - return nil // wt only closes via finalizer -} diff --git a/internal/integration_test/vs/wasmtime/wasmtime_test.go b/internal/integration_test/vs/wasmtime/wasmtime_test.go deleted file mode 100644 index 8e6235f8eb..0000000000 --- a/internal/integration_test/vs/wasmtime/wasmtime_test.go +++ /dev/null @@ -1,67 +0,0 @@ -//go:build cgo - -package wasmtime - -import ( - "testing" - - "github.com/tetratelabs/wazero/internal/integration_test/vs" -) - -var runtime = newWasmtimeRuntime - -func TestAllocation(t *testing.T) { - vs.RunTestAllocation(t, runtime) -} - -func BenchmarkAllocation(b *testing.B) { - vs.RunBenchmarkAllocation(b, runtime) -} - -func TestBenchmarkAllocation_Call_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkAllocation_Call_CompilerFastest(t, runtime()) -} - -func TestFactorial(t *testing.T) { - vs.RunTestFactorial(t, runtime) -} - -func BenchmarkFactorial(b *testing.B) { - vs.RunBenchmarkFactorial(b, runtime) -} - -func TestBenchmarkFactorial_Call_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkFactorial_Call_CompilerFastest(t, runtime()) -} - -func TestHostCall(t *testing.T) { - vs.RunTestHostCall(t, runtime) -} - -func BenchmarkHostCall(b *testing.B) { - vs.RunBenchmarkHostCall(b, runtime) -} - -func TestBenchmarkHostCall_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkHostCall_CompilerFastest(t, runtime()) -} - -func TestMemory(t *testing.T) { - vs.RunTestMemory(t, runtime) -} - -func BenchmarkMemory(b *testing.B) { - vs.RunBenchmarkMemory(b, runtime) -} - -func TestBenchmarkMemory_CompilerFastest(t *testing.T) { - vs.RunTestBenchmarkMemory_CompilerFastest(t, runtime()) -} - -func TestShorthash(t *testing.T) { - vs.RunTestShorthash(t, runtime) -} - -func BenchmarkShorthash(b *testing.B) { - vs.RunBenchmarkShorthash(b, runtime) -} diff --git a/internal/integration_test/vs/testdata/fac.wasm b/testdata/fac.wasm similarity index 100% rename from internal/integration_test/vs/testdata/fac.wasm rename to testdata/fac.wasm diff --git a/internal/integration_test/vs/testdata/fac.wat b/testdata/fac.wat similarity index 99% rename from internal/integration_test/vs/testdata/fac.wat rename to testdata/fac.wat index 9f80d8d6dc..860253ef9b 100644 --- a/internal/integration_test/vs/testdata/fac.wat +++ b/testdata/fac.wat @@ -27,4 +27,4 @@ (drop) (return) ) ) -) +) \ No newline at end of file diff --git a/testdata/mem_grow.wasm b/testdata/mem_grow.wasm new file mode 100644 index 0000000000..82f3fd8e38 Binary files /dev/null and b/testdata/mem_grow.wasm differ diff --git a/internal/integration_test/vs/testdata/mem_grow.wat b/testdata/mem_grow.wat similarity index 99% rename from internal/integration_test/vs/testdata/mem_grow.wat rename to testdata/mem_grow.wat index 743dca8826..4dff4a9b7b 100644 --- a/internal/integration_test/vs/testdata/mem_grow.wat +++ b/testdata/mem_grow.wat @@ -11,4 +11,4 @@ return ) (start $main) -) +) \ No newline at end of file