testing: pass N, P into Run of hammer (#2146)

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
Takeshi Yoneda
2024-03-12 10:34:42 +09:00
committed by GitHub
parent 4242b5e211
commit c4532da719
7 changed files with 33 additions and 19 deletions

View File

@@ -97,7 +97,7 @@ func closeModuleWhileInUse(t *testing.T, r wazero.Runtime, closeFn func(imported
// As this is a blocking function call, only run 1 per goroutine. // As this is a blocking function call, only run 1 per goroutine.
i := importing // pin the module used inside goroutines i := importing // pin the module used inside goroutines
hammer.NewHammer(t, P, 1).Run(func(name string) { hammer.NewHammer(t, P, 1).Run(func(p, n int) {
// In all cases, the importing module is closed, so the error should have that as its module name. // In all cases, the importing module is closed, so the error should have that as its module name.
requireFunctionCallExits(t, i.ExportedFunction("call_return_input")) requireFunctionCallExits(t, i.ExportedFunction("call_return_input"))
}, func() { // When all functions are in-flight, re-assign the modules. }, func() { // When all functions are in-flight, re-assign the modules.

View File

@@ -100,8 +100,9 @@ func incrementGuardedByMutex(t *testing.T, r wazero.Runtime) {
mod, err := r.Instantiate(testCtx, mutexWasm) mod, err := r.Instantiate(testCtx, mutexWasm)
require.NoError(t, err) require.NoError(t, err)
hammer.NewHammer(t, P, 30000).Run(func(name string) { fns := make([]api.Function, P)
_, err := mod.ExportedFunction(tt.fn).Call(testCtx) hammer.NewHammer(t, P, 30000).Run(func(p, n int) {
_, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx)
require.NoError(t, err) require.NoError(t, err)
}, func() {}) }, func() {})
@@ -161,8 +162,9 @@ func atomicAdd(t *testing.T, r wazero.Runtime) {
mod, err := r.Instantiate(testCtx, addWasm) mod, err := r.Instantiate(testCtx, addWasm)
require.NoError(t, err) require.NoError(t, err)
hammer.NewHammer(t, P, 30000).Run(func(name string) { fns := make([]api.Function, P)
_, err := mod.ExportedFunction(tt.fn).Call(testCtx) hammer.NewHammer(t, P, 30000).Run(func(p, n int) {
_, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx)
require.NoError(t, err) require.NoError(t, err)
}, func() {}) }, func() {})
@@ -222,8 +224,9 @@ func atomicSub(t *testing.T, r wazero.Runtime) {
mod, err := r.Instantiate(testCtx, subWasm) mod, err := r.Instantiate(testCtx, subWasm)
require.NoError(t, err) require.NoError(t, err)
hammer.NewHammer(t, P, 30000).Run(func(name string) { fns := make([]api.Function, P)
_, err := mod.ExportedFunction(tt.fn).Call(testCtx) hammer.NewHammer(t, P, 30000).Run(func(p, n int) {
_, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx)
require.NoError(t, err) require.NoError(t, err)
}, func() {}) }, func() {})
@@ -273,8 +276,9 @@ func atomicXor(t *testing.T, r wazero.Runtime) {
mod.Memory().WriteUint32Le(0, 12345) mod.Memory().WriteUint32Le(0, 12345)
hammer.NewHammer(t, P, 30000).Run(func(name string) { fns := make([]api.Function, P)
_, err := mod.ExportedFunction(tt.fn).Call(testCtx) hammer.NewHammer(t, P, 30000).Run(func(p, n int) {
_, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx)
require.NoError(t, err) require.NoError(t, err)
}, func() {}) }, func() {})
@@ -286,3 +290,14 @@ func atomicXor(t *testing.T, r wazero.Runtime) {
}) })
} }
} }
// mustGetFn is a helper to get a function from a module, caching the result to avoid repeated allocations.
//
// Creating ExportedFunction per invocation costs a lot here since each time the runtime allocates the execution stack,
// so only do it once per goroutine of the hammer.
func mustGetFn(m api.Module, name string, fns []api.Function, p int) api.Function {
if fns[p] == nil {
fns[p] = m.ExportedFunction(name)
}
return fns[p]
}

View File

@@ -1,7 +1,6 @@
package hammer package hammer
import ( import (
"fmt"
"runtime" "runtime"
"sync" "sync"
"testing" "testing"
@@ -38,7 +37,7 @@ type Hammer interface {
// if t.Failed() { // if t.Failed() {
// return // return
// } // }
Run(test func(name string), onRunning func()) Run(test func(p, n int), onRunning func())
} }
// NewHammer returns a Hammer initialized to indicated count of goroutines (P) and iterations per goroutine (N). // NewHammer returns a Hammer initialized to indicated count of goroutines (P) and iterations per goroutine (N).
@@ -58,7 +57,7 @@ type hammer struct {
} }
// Run implements Hammer.Run // Run implements Hammer.Run
func (h *hammer) Run(test func(name string), onRunning func()) { func (h *hammer) Run(test func(p, n int), onRunning func()) {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(h.P / 2)) // Ensure goroutines have to switch cores. defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(h.P / 2)) // Ensure goroutines have to switch cores.
// running track // running track
@@ -84,7 +83,7 @@ func (h *hammer) Run(test func(name string), onRunning func()) {
unblocked.Wait() // Wait to be unblocked unblocked.Wait() // Wait to be unblocked
for n := 0; n < h.N; n++ { // Invoke one test for n := 0; n < h.N; n++ { // Invoke one test
test(fmt.Sprintf("%s:%d-%d", h.t.Name(), p, n)) test(p, n)
} }
}() }()
} }

View File

@@ -269,7 +269,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
testName := tc.name + " (concurrent)" testName := tc.name + " (concurrent)"
t.Run(testName, func(t *testing.T) { t.Run(testName, func(t *testing.T) {
hammer.NewHammer(t, nGoroutines, nIterations). hammer.NewHammer(t, nGoroutines, nIterations).
Run(func(name string) { Run(func(p, n int) {
tc.m.buildFunctionDefinitions() tc.m.buildFunctionDefinitions()
}, nil) }, nil)

View File

@@ -127,7 +127,7 @@ func TestModuleInstance_Close(t *testing.T) {
require.True(t, ok, "sysCtx.openedFiles was empty") require.True(t, ok, "sysCtx.openedFiles was empty")
// Closing should not err even when concurrently closed. // Closing should not err even when concurrently closed.
hammer.NewHammer(t, 100, 10).Run(func(name string) { hammer.NewHammer(t, 100, 10).Run(func(p, n int) {
require.NoError(t, m.Close(testCtx)) require.NoError(t, m.Close(testCtx))
// closeWithExitCode is the one called during Store.CloseWithExitCode. // closeWithExitCode is the one called during Store.CloseWithExitCode.
require.NoError(t, m.closeWithExitCode(testCtx, 0)) require.NoError(t, m.closeWithExitCode(testCtx, 0))

View File

@@ -220,8 +220,8 @@ func TestStore_hammer(t *testing.T) {
P = 4 P = 4
N = 100 N = 100
} }
hammer.NewHammer(t, P, N).Run(func(name string) { hammer.NewHammer(t, P, N).Run(func(p, n int) {
mod, instantiateErr := s.Instantiate(testCtx, importingModule, name, sys.DefaultContext(nil), []FunctionTypeID{0}) mod, instantiateErr := s.Instantiate(testCtx, importingModule, fmt.Sprintf("%d:%d", p, n), sys.DefaultContext(nil), []FunctionTypeID{0})
require.NoError(t, instantiateErr) require.NoError(t, instantiateErr)
require.NoError(t, mod.Close(testCtx)) require.NoError(t, mod.Close(testCtx))
}, nil) }, nil)
@@ -279,7 +279,7 @@ func TestStore_hammer_close(t *testing.T) {
instances[i] = mod instances[i] = mod
} }
hammer.NewHammer(t, 100, 2).Run(func(name string) { hammer.NewHammer(t, 100, 2).Run(func(p, n int) {
for i := 0; i < instCount; i++ { for i := 0; i < instCount; i++ {
if i == instCount/2 { if i == instCount/2 {
// Close store concurrently as well. // Close store concurrently as well.

View File

@@ -61,7 +61,7 @@ func TestDWARFLines_Line_Zig(t *testing.T) {
tc := tc tc := tc
t.Run(fmt.Sprintf("%#x/%s", tc.offset, tc.exp), func(t *testing.T) { t.Run(fmt.Sprintf("%#x/%s", tc.offset, tc.exp), func(t *testing.T) {
// Ensures that DWARFLines.Line is goroutine-safe. // Ensures that DWARFLines.Line is goroutine-safe.
hammer.NewHammer(t, 100, 5).Run(func(name string) { hammer.NewHammer(t, 100, 5).Run(func(p, n int) {
actual := mod.DWARFLines.Line(tc.offset) actual := mod.DWARFLines.Line(tc.offset)
require.Equal(t, len(tc.exp), len(actual)) require.Equal(t, len(tc.exp), len(actual))
for i := range tc.exp { for i := range tc.exp {