From c4532da719f566f43009f81271fb9c049714c1f5 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Tue, 12 Mar 2024 10:34:42 +0900 Subject: [PATCH] testing: pass N, P into Run of hammer (#2146) Signed-off-by: Takeshi Yoneda --- .../integration_test/engine/hammer_test.go | 2 +- .../integration_test/engine/threads_test.go | 31 ++++++++++++++----- internal/testing/hammer/hammer.go | 7 ++--- internal/wasm/function_definition_test.go | 2 +- internal/wasm/module_instance_test.go | 2 +- internal/wasm/store_test.go | 6 ++-- internal/wasmdebug/dwarf_test.go | 2 +- 7 files changed, 33 insertions(+), 19 deletions(-) diff --git a/internal/integration_test/engine/hammer_test.go b/internal/integration_test/engine/hammer_test.go index 7aa961bf..be2338ac 100644 --- a/internal/integration_test/engine/hammer_test.go +++ b/internal/integration_test/engine/hammer_test.go @@ -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. 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. requireFunctionCallExits(t, i.ExportedFunction("call_return_input")) }, func() { // When all functions are in-flight, re-assign the modules. diff --git a/internal/integration_test/engine/threads_test.go b/internal/integration_test/engine/threads_test.go index 338b3975..d075e3db 100644 --- a/internal/integration_test/engine/threads_test.go +++ b/internal/integration_test/engine/threads_test.go @@ -100,8 +100,9 @@ func incrementGuardedByMutex(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(testCtx, mutexWasm) require.NoError(t, err) - hammer.NewHammer(t, P, 30000).Run(func(name string) { - _, err := mod.ExportedFunction(tt.fn).Call(testCtx) + fns := make([]api.Function, P) + hammer.NewHammer(t, P, 30000).Run(func(p, n int) { + _, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx) require.NoError(t, err) }, func() {}) @@ -161,8 +162,9 @@ func atomicAdd(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(testCtx, addWasm) require.NoError(t, err) - hammer.NewHammer(t, P, 30000).Run(func(name string) { - _, err := mod.ExportedFunction(tt.fn).Call(testCtx) + fns := make([]api.Function, P) + hammer.NewHammer(t, P, 30000).Run(func(p, n int) { + _, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx) require.NoError(t, err) }, func() {}) @@ -222,8 +224,9 @@ func atomicSub(t *testing.T, r wazero.Runtime) { mod, err := r.Instantiate(testCtx, subWasm) require.NoError(t, err) - hammer.NewHammer(t, P, 30000).Run(func(name string) { - _, err := mod.ExportedFunction(tt.fn).Call(testCtx) + fns := make([]api.Function, P) + hammer.NewHammer(t, P, 30000).Run(func(p, n int) { + _, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx) require.NoError(t, err) }, func() {}) @@ -273,8 +276,9 @@ func atomicXor(t *testing.T, r wazero.Runtime) { mod.Memory().WriteUint32Le(0, 12345) - hammer.NewHammer(t, P, 30000).Run(func(name string) { - _, err := mod.ExportedFunction(tt.fn).Call(testCtx) + fns := make([]api.Function, P) + hammer.NewHammer(t, P, 30000).Run(func(p, n int) { + _, err := mustGetFn(mod, tt.fn, fns, p).Call(testCtx) require.NoError(t, err) }, 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] +} diff --git a/internal/testing/hammer/hammer.go b/internal/testing/hammer/hammer.go index 82e86961..c3d30363 100644 --- a/internal/testing/hammer/hammer.go +++ b/internal/testing/hammer/hammer.go @@ -1,7 +1,6 @@ package hammer import ( - "fmt" "runtime" "sync" "testing" @@ -38,7 +37,7 @@ type Hammer interface { // if t.Failed() { // 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). @@ -58,7 +57,7 @@ type hammer struct { } // 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. // running track @@ -84,7 +83,7 @@ func (h *hammer) Run(test func(name string), onRunning func()) { unblocked.Wait() // Wait to be unblocked for n := 0; n < h.N; n++ { // Invoke one test - test(fmt.Sprintf("%s:%d-%d", h.t.Name(), p, n)) + test(p, n) } }() } diff --git a/internal/wasm/function_definition_test.go b/internal/wasm/function_definition_test.go index 6e6e92f2..c547e8f0 100644 --- a/internal/wasm/function_definition_test.go +++ b/internal/wasm/function_definition_test.go @@ -269,7 +269,7 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) { testName := tc.name + " (concurrent)" t.Run(testName, func(t *testing.T) { hammer.NewHammer(t, nGoroutines, nIterations). - Run(func(name string) { + Run(func(p, n int) { tc.m.buildFunctionDefinitions() }, nil) diff --git a/internal/wasm/module_instance_test.go b/internal/wasm/module_instance_test.go index 89b5a231..981f0b71 100644 --- a/internal/wasm/module_instance_test.go +++ b/internal/wasm/module_instance_test.go @@ -127,7 +127,7 @@ func TestModuleInstance_Close(t *testing.T) { require.True(t, ok, "sysCtx.openedFiles was empty") // 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)) // closeWithExitCode is the one called during Store.CloseWithExitCode. require.NoError(t, m.closeWithExitCode(testCtx, 0)) diff --git a/internal/wasm/store_test.go b/internal/wasm/store_test.go index a4d0207e..68cd3a39 100644 --- a/internal/wasm/store_test.go +++ b/internal/wasm/store_test.go @@ -220,8 +220,8 @@ func TestStore_hammer(t *testing.T) { P = 4 N = 100 } - hammer.NewHammer(t, P, N).Run(func(name string) { - mod, instantiateErr := s.Instantiate(testCtx, importingModule, name, sys.DefaultContext(nil), []FunctionTypeID{0}) + hammer.NewHammer(t, P, N).Run(func(p, n int) { + mod, instantiateErr := s.Instantiate(testCtx, importingModule, fmt.Sprintf("%d:%d", p, n), sys.DefaultContext(nil), []FunctionTypeID{0}) require.NoError(t, instantiateErr) require.NoError(t, mod.Close(testCtx)) }, nil) @@ -279,7 +279,7 @@ func TestStore_hammer_close(t *testing.T) { 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++ { if i == instCount/2 { // Close store concurrently as well. diff --git a/internal/wasmdebug/dwarf_test.go b/internal/wasmdebug/dwarf_test.go index fb0d72c4..f309ebb8 100644 --- a/internal/wasmdebug/dwarf_test.go +++ b/internal/wasmdebug/dwarf_test.go @@ -61,7 +61,7 @@ func TestDWARFLines_Line_Zig(t *testing.T) { tc := tc t.Run(fmt.Sprintf("%#x/%s", tc.offset, tc.exp), func(t *testing.T) { // 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) require.Equal(t, len(tc.exp), len(actual)) for i := range tc.exp {