Adds tests for multiple goroutines (#331)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
package wazero
|
package wazero
|
||||||
|
|
||||||
|
const JITSupported = true
|
||||||
|
|
||||||
// NewRuntimeConfig returns NewRuntimeConfigJIT
|
// NewRuntimeConfig returns NewRuntimeConfigJIT
|
||||||
func NewRuntimeConfig() *RuntimeConfig {
|
func NewRuntimeConfig() *RuntimeConfig {
|
||||||
return NewRuntimeConfigJIT()
|
return NewRuntimeConfigJIT()
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
package wazero
|
package wazero
|
||||||
|
|
||||||
|
const JITSupported = false
|
||||||
|
|
||||||
// NewRuntimeConfig returns NewRuntimeConfigInterpreter
|
// NewRuntimeConfig returns NewRuntimeConfigInterpreter
|
||||||
func NewRuntimeConfig() *RuntimeConfig {
|
func NewRuntimeConfig() *RuntimeConfig {
|
||||||
return NewRuntimeConfigInterpreter()
|
return NewRuntimeConfigInterpreter()
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -19,15 +17,15 @@ import (
|
|||||||
// ctx is a default context used to avoid lint warnings even though these tests don't use any context data.
|
// ctx is a default context used to avoid lint warnings even though these tests don't use any context data.
|
||||||
var ctx = context.Background()
|
var ctx = context.Background()
|
||||||
|
|
||||||
func TestJIT(t *testing.T) {
|
func TestJITAdhoc(t *testing.T) {
|
||||||
if runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" {
|
if !wazero.JITSupported {
|
||||||
t.Skip()
|
t.Skip()
|
||||||
}
|
}
|
||||||
runTests(t, wazero.NewRuntimeConfigJIT)
|
runAdhocTests(t, wazero.NewRuntimeConfigJIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInterpreter(t *testing.T) {
|
func TestInterpreterAdhoc(t *testing.T) {
|
||||||
runTests(t, wazero.NewRuntimeConfigInterpreter)
|
runAdhocTests(t, wazero.NewRuntimeConfigInterpreter)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -45,7 +43,7 @@ var (
|
|||||||
hugestackWasm []byte
|
hugestackWasm []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
func runTests(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
func runAdhocTests(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
||||||
t.Run("huge stack", func(t *testing.T) {
|
t.Run("huge stack", func(t *testing.T) {
|
||||||
testHugeStack(t, newRuntimeConfig)
|
testHugeStack(t, newRuntimeConfig)
|
||||||
})
|
})
|
||||||
@@ -73,35 +71,18 @@ func runTests(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testHugeStack(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
func testHugeStack(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
||||||
// We execute 1000 times in order to ensure the JIT engine is stable under high concurrency
|
|
||||||
// and we have no conflict with Go's runtime.
|
|
||||||
const goroutines = 1000
|
|
||||||
|
|
||||||
r := wazero.NewRuntimeWithConfig(newRuntimeConfig())
|
r := wazero.NewRuntimeWithConfig(newRuntimeConfig())
|
||||||
|
|
||||||
module, err := r.NewModuleFromSource(hugestackWasm)
|
module, err := r.NewModuleFromSource(hugestackWasm)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
fn := module.Function("main")
|
fn := module.Function("main")
|
||||||
require.NotNil(t, fn)
|
require.NotNil(t, fn)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
_, err = fn.Call(ctx)
|
||||||
wg.Add(goroutines)
|
require.NoError(t, err)
|
||||||
for i := 0; i < goroutines; i++ {
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
_, err = fn.Call(ctx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFibonacci(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
func testFibonacci(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
||||||
// We execute 1000 times in order to ensure the JIT engine is stable under high concurrency
|
|
||||||
// and we have no conflict with Go's runtime.
|
|
||||||
const goroutines = 1000
|
|
||||||
|
|
||||||
r := wazero.NewRuntimeWithConfig(newRuntimeConfig())
|
r := wazero.NewRuntimeWithConfig(newRuntimeConfig())
|
||||||
module, err := r.NewModuleFromSource(fibWasm)
|
module, err := r.NewModuleFromSource(fibWasm)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -109,17 +90,9 @@ func testFibonacci(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig)
|
|||||||
fib := module.Function("fib")
|
fib := module.Function("fib")
|
||||||
require.NotNil(t, fib)
|
require.NotNil(t, fib)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
results, err := fib.Call(ctx, 20)
|
||||||
wg.Add(goroutines)
|
require.NoError(t, err)
|
||||||
for i := 0; i < goroutines; i++ {
|
require.Equal(t, uint64(10946), results[0])
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
results, err := fib.Call(ctx, 20)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, uint64(10946), results[0])
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFac(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
func testFac(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
||||||
|
|||||||
68
tests/engine/concurrency_test.go
Normal file
68
tests/engine/concurrency_test.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package adhoc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJITConcurrency(t *testing.T) {
|
||||||
|
if !wazero.JITSupported {
|
||||||
|
t.Skip()
|
||||||
|
}
|
||||||
|
runAdhocTestsUnderHighConcurrency(t, wazero.NewRuntimeConfigJIT)
|
||||||
|
// TODO: Add conccurent instantiation, invocation and release on a single store test case in https://github.com/tetratelabs/wazero/issues/293
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInterpreterConcurrency(t *testing.T) {
|
||||||
|
runAdhocTestsUnderHighConcurrency(t, wazero.NewRuntimeConfigInterpreter)
|
||||||
|
// TODO: Add conccurent instantiation, invocation and release on a single store test case in https://github.com/tetratelabs/wazero/issues/293
|
||||||
|
}
|
||||||
|
|
||||||
|
func runAdhocTestsUnderHighConcurrency(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig) {
|
||||||
|
t.Run("huge stack", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testHugeStack)
|
||||||
|
})
|
||||||
|
t.Run("fibonacci", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testFibonacci)
|
||||||
|
})
|
||||||
|
t.Run("fac", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testFac)
|
||||||
|
})
|
||||||
|
t.Run("unreachable", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testUnreachable)
|
||||||
|
})
|
||||||
|
t.Run("memory", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testMemory)
|
||||||
|
})
|
||||||
|
t.Run("recursive entry", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testRecursiveEntry)
|
||||||
|
})
|
||||||
|
t.Run("imported-and-exported func", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runAdhocTestUnderHighConcurrency(t, newRuntimeConfig, testImportedAndExportedFunc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// runAdhocTestUnderHighConcurrency runs a test case in adhoc_test.go with multiple goroutines.
|
||||||
|
func runAdhocTestUnderHighConcurrency(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig,
|
||||||
|
adhocTest func(t *testing.T, newRuntimeConfig func() *wazero.RuntimeConfig)) {
|
||||||
|
const goroutinesPerCase = 1000
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(goroutinesPerCase)
|
||||||
|
for i := 0; i < goroutinesPerCase; i++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
adhocTest(t, newRuntimeConfig)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user