From 102ffcb030a54b143058a82be16aad279b68270e Mon Sep 17 00:00:00 2001 From: Rajiv Singh Date: Sat, 24 Aug 2024 16:20:16 +0530 Subject: [PATCH 1/5] functions will only proceed if prepare has been called Signed-off-by: Rajiv Singh --- cmd/wzprof/main.go | 11 +++++++++-- cpu_test.go | 15 ++++++++++++--- mem_test.go | 5 ++++- wzprof.go | 21 ++++++++++++++++----- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/cmd/wzprof/main.go b/cmd/wzprof/main.go index d16b8a7..b17b68b 100644 --- a/cmd/wzprof/main.go +++ b/cmd/wzprof/main.go @@ -59,8 +59,15 @@ func (prog *program) run(ctx context.Context) error { p := wzprof.ProfilingFor(wasmCode) - cpu := p.CPUProfiler(wzprof.HostTime(prog.hostTime)) - mem := p.MemoryProfiler(wzprof.InuseMemory(prog.inuseMemory)) + cpu, err := p.CPUProfiler(wzprof.HostTime(prog.hostTime)) + if err != nil { + return fmt.Errorf("creating cpu profiler: %w", err) + } + + mem, err := p.MemoryProfiler(wzprof.InuseMemory(prog.inuseMemory)) + if err != nil { + return fmt.Errorf("creating memory profiler: %w", err) + } var listeners []experimental.FunctionListenerFactory if prog.cpuProfile != "" || prog.pprofAddr != "" { diff --git a/cpu_test.go b/cpu_test.go index b1c188e..bd151dc 100644 --- a/cpu_test.go +++ b/cpu_test.go @@ -10,22 +10,31 @@ import ( ) func BenchmarkCPUProfilerOn(b *testing.B) { - p := ProfilingFor(nil).CPUProfiler() + p, err := ProfilingFor(nil).CPUProfiler() + if err != nil { + b.Fatal(err) + } p.StartProfile() benchmarkFunctionListener(b, p) } func BenchmarkCPUProfilerOff(b *testing.B) { - p := ProfilingFor(nil).CPUProfiler() + p, err := ProfilingFor(nil).CPUProfiler() + if err != nil { + b.Fatal(err) + } benchmarkFunctionListener(b, p) } func TestCPUProfilerTime(t *testing.T) { currentTime := int64(0) - p := ProfilingFor(nil).CPUProfiler( + p, err := ProfilingFor(nil).CPUProfiler( TimeFunc(func() int64 { return currentTime }), ) + if err != nil { + t.Fatal(err) + } module := wazerotest.NewModule(nil, wazerotest.NewFunction(func(context.Context, api.Module) {}), diff --git a/mem_test.go b/mem_test.go index 7d069b1..678d4c5 100644 --- a/mem_test.go +++ b/mem_test.go @@ -5,6 +5,9 @@ import ( ) func BenchmarkMemoryProfiler(b *testing.B) { - p := ProfilingFor(nil).MemoryProfiler() + p, err := ProfilingFor(nil).MemoryProfiler() + if err != nil { + b.Fatal(err) + } benchmarkFunctionListener(b, p) } diff --git a/wzprof.go b/wzprof.go index 4261d40..b4bf0b6 100644 --- a/wzprof.go +++ b/wzprof.go @@ -27,7 +27,8 @@ type Profiling struct { symbols symbolizer stackIterator func(mod api.Module, def api.FunctionDefinition, wasmsi experimental.StackIterator) experimental.StackIterator - lang language + lang language + prepareCalled bool // Flag to indicate if Prepare has been called } type language int8 @@ -97,14 +98,20 @@ func ProfilingFor(wasm []byte) *Profiling { // CPUProfiler constructs a new instance of CPUProfiler using the given time // function to record the CPU time consumed. -func (p *Profiling) CPUProfiler(options ...CPUProfilerOption) *CPUProfiler { - return newCPUProfiler(p, options...) +func (p *Profiling) CPUProfiler(options ...CPUProfilerOption) (*CPUProfiler, error) { + if !p.prepareCalled { + return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a CPUProfiler") + } + return newCPUProfiler(p, options...), nil } // MemoryProfiler constructs a new instance of MemoryProfiler using the given // time function to record the profile execution time. -func (p *Profiling) MemoryProfiler(options ...MemoryProfilerOption) *MemoryProfiler { - return newMemoryProfiler(p, options...) +func (p *Profiling) MemoryProfiler(options ...MemoryProfilerOption) (*MemoryProfiler, error) { + if !p.prepareCalled { + return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a MemoryProfiler") + } + return newMemoryProfiler(p, options...), nil } // Prepare selects the most appropriate analysis functions for the guest @@ -147,6 +154,10 @@ func (p *Profiling) Prepare(mod wazero.CompiledModule) error { } p.symbols = buildDwarfSymbolizer(dwarf) } + + // Set the flag to true if Prepare succeeds + p.prepareCalled = true + return nil } From 8ea8086d56df68add88ccbc446f8400326ee23bb Mon Sep 17 00:00:00 2001 From: Rajiv Singh Date: Sat, 24 Aug 2024 16:53:00 +0530 Subject: [PATCH 2/5] functions will only proceed if prepare has been called Signed-off-by: Rajiv Singh --- cmd/wzprof/main.go | 33 ++++++++++++++------------------- wzprof.go | 37 +++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/cmd/wzprof/main.go b/cmd/wzprof/main.go index b17b68b..cf440ce 100644 --- a/cmd/wzprof/main.go +++ b/cmd/wzprof/main.go @@ -59,6 +59,20 @@ func (prog *program) run(ctx context.Context) error { p := wzprof.ProfilingFor(wasmCode) + runtime := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig(). + WithDebugInfoEnabled(true). + WithCustomSections(true)) + + stdout.Printf("compiling wasm module %s", prog.filePath) + compiledModule, err := runtime.CompileModule(ctx, wasmCode) + if err != nil { + return fmt.Errorf("compiling wasm module: %w", err) + } + err = p.Prepare(compiledModule) + if err != nil { + return fmt.Errorf("preparing wasm module: %w", err) + } + cpu, err := p.CPUProfiler(wzprof.HostTime(prog.hostTime)) if err != nil { return fmt.Errorf("creating cpu profiler: %w", err) @@ -85,25 +99,6 @@ func (prog *program) run(ctx context.Context) error { } } - ctx = context.WithValue(ctx, - experimental.FunctionListenerFactoryKey{}, - experimental.MultiFunctionListenerFactory(listeners...), - ) - - runtime := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig(). - WithDebugInfoEnabled(true). - WithCustomSections(true)) - - stdout.Printf("compiling wasm module %s", prog.filePath) - compiledModule, err := runtime.CompileModule(ctx, wasmCode) - if err != nil { - return fmt.Errorf("compiling wasm module: %w", err) - } - err = p.Prepare(compiledModule) - if err != nil { - return fmt.Errorf("preparing wasm module: %w", err) - } - if prog.pprofAddr != "" { u := &url.URL{Scheme: "http", Host: prog.pprofAddr, Path: "/debug/pprof"} stdout.Printf("starting prrof http sever at %s", u) diff --git a/wzprof.go b/wzprof.go index b4bf0b6..f12039f 100644 --- a/wzprof.go +++ b/wzprof.go @@ -96,27 +96,10 @@ func ProfilingFor(wasm []byte) *Profiling { return r } -// CPUProfiler constructs a new instance of CPUProfiler using the given time -// function to record the CPU time consumed. -func (p *Profiling) CPUProfiler(options ...CPUProfilerOption) (*CPUProfiler, error) { - if !p.prepareCalled { - return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a CPUProfiler") - } - return newCPUProfiler(p, options...), nil -} - -// MemoryProfiler constructs a new instance of MemoryProfiler using the given -// time function to record the profile execution time. -func (p *Profiling) MemoryProfiler(options ...MemoryProfilerOption) (*MemoryProfiler, error) { - if !p.prepareCalled { - return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a MemoryProfiler") - } - return newMemoryProfiler(p, options...), nil -} - // Prepare selects the most appropriate analysis functions for the guest // code in the provided module. func (p *Profiling) Prepare(mod wazero.CompiledModule) error { + switch p.lang { case golang: s, err := preparePclntabSymbolizer(p.wasm, mod) @@ -161,6 +144,24 @@ func (p *Profiling) Prepare(mod wazero.CompiledModule) error { return nil } +// CPUProfiler constructs a new instance of CPUProfiler using the given time +// function to record the CPU time consumed. +func (p *Profiling) CPUProfiler(options ...CPUProfilerOption) (*CPUProfiler, error) { + if !p.prepareCalled { + return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a CPUProfiler") + } + return newCPUProfiler(p, options...), nil +} + +// MemoryProfiler constructs a new instance of MemoryProfiler using the given +// time function to record the profile execution time. +func (p *Profiling) MemoryProfiler(options ...MemoryProfilerOption) (*MemoryProfiler, error) { + if !p.prepareCalled { + return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a MemoryProfiler") + } + return newMemoryProfiler(p, options...), nil +} + // profilingListener wraps a FunctionListener to adapt its stack iterator to the // appropriate implementation according to the module support. type profilingListener struct { From 7a2d7da1ad67d51a1cd132efde35128672941ebf Mon Sep 17 00:00:00 2001 From: Rajiv Singh Date: Sun, 25 Aug 2024 05:22:47 +0530 Subject: [PATCH 3/5] panic if profilers are created before prepare Signed-off-by: Rajiv Singh --- cmd/wzprof/main.go | 11 ++--------- cpu_test.go | 15 +++------------ mem_test.go | 5 +---- wzprof.go | 12 ++++++------ 4 files changed, 12 insertions(+), 31 deletions(-) diff --git a/cmd/wzprof/main.go b/cmd/wzprof/main.go index cf440ce..ceff62a 100644 --- a/cmd/wzprof/main.go +++ b/cmd/wzprof/main.go @@ -73,15 +73,8 @@ func (prog *program) run(ctx context.Context) error { return fmt.Errorf("preparing wasm module: %w", err) } - cpu, err := p.CPUProfiler(wzprof.HostTime(prog.hostTime)) - if err != nil { - return fmt.Errorf("creating cpu profiler: %w", err) - } - - mem, err := p.MemoryProfiler(wzprof.InuseMemory(prog.inuseMemory)) - if err != nil { - return fmt.Errorf("creating memory profiler: %w", err) - } + cpu := p.CPUProfiler(wzprof.HostTime(prog.hostTime)) + mem := p.MemoryProfiler(wzprof.InuseMemory(prog.inuseMemory)) var listeners []experimental.FunctionListenerFactory if prog.cpuProfile != "" || prog.pprofAddr != "" { diff --git a/cpu_test.go b/cpu_test.go index bd151dc..b1c188e 100644 --- a/cpu_test.go +++ b/cpu_test.go @@ -10,31 +10,22 @@ import ( ) func BenchmarkCPUProfilerOn(b *testing.B) { - p, err := ProfilingFor(nil).CPUProfiler() - if err != nil { - b.Fatal(err) - } + p := ProfilingFor(nil).CPUProfiler() p.StartProfile() benchmarkFunctionListener(b, p) } func BenchmarkCPUProfilerOff(b *testing.B) { - p, err := ProfilingFor(nil).CPUProfiler() - if err != nil { - b.Fatal(err) - } + p := ProfilingFor(nil).CPUProfiler() benchmarkFunctionListener(b, p) } func TestCPUProfilerTime(t *testing.T) { currentTime := int64(0) - p, err := ProfilingFor(nil).CPUProfiler( + p := ProfilingFor(nil).CPUProfiler( TimeFunc(func() int64 { return currentTime }), ) - if err != nil { - t.Fatal(err) - } module := wazerotest.NewModule(nil, wazerotest.NewFunction(func(context.Context, api.Module) {}), diff --git a/mem_test.go b/mem_test.go index 678d4c5..7d069b1 100644 --- a/mem_test.go +++ b/mem_test.go @@ -5,9 +5,6 @@ import ( ) func BenchmarkMemoryProfiler(b *testing.B) { - p, err := ProfilingFor(nil).MemoryProfiler() - if err != nil { - b.Fatal(err) - } + p := ProfilingFor(nil).MemoryProfiler() benchmarkFunctionListener(b, p) } diff --git a/wzprof.go b/wzprof.go index f12039f..62d8352 100644 --- a/wzprof.go +++ b/wzprof.go @@ -146,20 +146,20 @@ func (p *Profiling) Prepare(mod wazero.CompiledModule) error { // CPUProfiler constructs a new instance of CPUProfiler using the given time // function to record the CPU time consumed. -func (p *Profiling) CPUProfiler(options ...CPUProfilerOption) (*CPUProfiler, error) { +func (p *Profiling) CPUProfiler(options ...CPUProfilerOption) *CPUProfiler { if !p.prepareCalled { - return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a CPUProfiler") + panic("Profiling.Prepare must be called before creating a CPU profiler") } - return newCPUProfiler(p, options...), nil + return newCPUProfiler(p, options...) } // MemoryProfiler constructs a new instance of MemoryProfiler using the given // time function to record the profile execution time. -func (p *Profiling) MemoryProfiler(options ...MemoryProfilerOption) (*MemoryProfiler, error) { +func (p *Profiling) MemoryProfiler(options ...MemoryProfilerOption) *MemoryProfiler { if !p.prepareCalled { - return nil, fmt.Errorf("Prepare must be called on the Profiling instance before creating a MemoryProfiler") + panic("Profiling.Prepare must be called before creating a Memory profiler") } - return newMemoryProfiler(p, options...), nil + return newMemoryProfiler(p, options...) } // profilingListener wraps a FunctionListener to adapt its stack iterator to the From 7fdee29bb2929a5dca997d200523fb8f75133310 Mon Sep 17 00:00:00 2001 From: Rajiv Singh Date: Tue, 27 Aug 2024 21:31:27 +0530 Subject: [PATCH 4/5] revert ctx cmd/main.go Signed-off-by: Rajiv Singh --- cmd/wzprof/main.go | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/cmd/wzprof/main.go b/cmd/wzprof/main.go index ceff62a..d16b8a7 100644 --- a/cmd/wzprof/main.go +++ b/cmd/wzprof/main.go @@ -59,20 +59,6 @@ func (prog *program) run(ctx context.Context) error { p := wzprof.ProfilingFor(wasmCode) - runtime := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig(). - WithDebugInfoEnabled(true). - WithCustomSections(true)) - - stdout.Printf("compiling wasm module %s", prog.filePath) - compiledModule, err := runtime.CompileModule(ctx, wasmCode) - if err != nil { - return fmt.Errorf("compiling wasm module: %w", err) - } - err = p.Prepare(compiledModule) - if err != nil { - return fmt.Errorf("preparing wasm module: %w", err) - } - cpu := p.CPUProfiler(wzprof.HostTime(prog.hostTime)) mem := p.MemoryProfiler(wzprof.InuseMemory(prog.inuseMemory)) @@ -92,6 +78,25 @@ func (prog *program) run(ctx context.Context) error { } } + ctx = context.WithValue(ctx, + experimental.FunctionListenerFactoryKey{}, + experimental.MultiFunctionListenerFactory(listeners...), + ) + + runtime := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig(). + WithDebugInfoEnabled(true). + WithCustomSections(true)) + + stdout.Printf("compiling wasm module %s", prog.filePath) + compiledModule, err := runtime.CompileModule(ctx, wasmCode) + if err != nil { + return fmt.Errorf("compiling wasm module: %w", err) + } + err = p.Prepare(compiledModule) + if err != nil { + return fmt.Errorf("preparing wasm module: %w", err) + } + if prog.pprofAddr != "" { u := &url.URL{Scheme: "http", Host: prog.pprofAddr, Path: "/debug/pprof"} stdout.Printf("starting prrof http sever at %s", u) From 7eff727405674dbbfdd1ba8c09e16afdd4700374 Mon Sep 17 00:00:00 2001 From: Rajiv Singh Date: Wed, 28 Aug 2024 06:23:01 +0530 Subject: [PATCH 5/5] remove extra line Signed-off-by: Rajiv Singh --- wzprof.go | 1 - 1 file changed, 1 deletion(-) diff --git a/wzprof.go b/wzprof.go index 62d8352..f62197d 100644 --- a/wzprof.go +++ b/wzprof.go @@ -99,7 +99,6 @@ func ProfilingFor(wasm []byte) *Profiling { // Prepare selects the most appropriate analysis functions for the guest // code in the provided module. func (p *Profiling) Prepare(mod wazero.CompiledModule) error { - switch p.lang { case golang: s, err := preparePclntabSymbolizer(p.wasm, mod)