From ae4954d09bc9697dfa4e0a97acb64830e9071970 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Fri, 12 May 2023 15:03:22 +0100 Subject: [PATCH] Profile with wzprof. --- go.mod | 6 ++ go.sum | 6 ++ .../tests/speedtest1/speedtest1_test.go | 94 +++++++++++++++++-- 3 files changed, 98 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 3722ad6..2f2745c 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,15 @@ go 1.19 require ( github.com/ncruces/julianday v0.1.5 github.com/psanford/httpreadat v0.1.0 + github.com/stealthrocket/wzprof v0.1.1 github.com/tetratelabs/wazero v1.1.1-0.20230511035210-78c35acd6e1c golang.org/x/sync v0.2.0 golang.org/x/sys v0.8.0 ) +require ( + github.com/google/pprof v0.0.0-20230406165453-00490a63f317 // indirect + golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect +) + retract v0.4.0 // tagged from the wrong branch diff --git a/go.sum b/go.sum index d0bbbca..84b4285 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,15 @@ +github.com/google/pprof v0.0.0-20230406165453-00490a63f317 h1:hFhpt7CTmR3DX+b4R19ydQFtofxT0Sv3QsKNMVQYTMQ= +github.com/google/pprof v0.0.0-20230406165453-00490a63f317/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk= github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIwZLUE= github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE= +github.com/stealthrocket/wzprof v0.1.1 h1:/qhSauOzXda4W5rEm+Gj2o2cKRZQqtGBPAulPflRwWk= +github.com/stealthrocket/wzprof v0.1.1/go.mod h1:UxCYAWsxjUKpIzJV8Pl5Yyo2QkQwsL29GdaoA38cXKU= github.com/tetratelabs/wazero v1.1.1-0.20230511035210-78c35acd6e1c h1:3vKw5AyUv+16qm9tIVfvm205aDIpDmrjxPydJ87GBKY= github.com/tetratelabs/wazero v1.1.1-0.20230511035210-78c35acd6e1c/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= +golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= +golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= diff --git a/sqlite3vfs/tests/speedtest1/speedtest1_test.go b/sqlite3vfs/tests/speedtest1/speedtest1_test.go index e5467ba..575c6f6 100644 --- a/sqlite3vfs/tests/speedtest1/speedtest1_test.go +++ b/sqlite3vfs/tests/speedtest1/speedtest1_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/rand" + "flag" "io" "os" "path/filepath" @@ -14,7 +15,9 @@ import ( _ "embed" + "github.com/stealthrocket/wzprof" "github.com/tetratelabs/wazero" + "github.com/tetratelabs/wazero/experimental" "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" "github.com/ncruces/go-sqlite3/sqlite3vfs" @@ -28,10 +31,17 @@ var ( module wazero.CompiledModule output bytes.Buffer options []string + cpuprof string + memprof string ) -func init() { - ctx := context.TODO() +const defaultSampleRate = 1.0 / 19 + +func TestMain(m *testing.M) { + initFlags() + + ctx := context.Background() + ctx, cpu, mem := setupProfiling(ctx) rt = wazero.NewRuntime(ctx) wasi_snapshot_preview1.MustInstantiate(ctx, rt) @@ -45,24 +55,92 @@ func init() { if err != nil { panic(err) } + + code := m.Run() + defer os.Exit(code) + io.Copy(os.Stderr, &output) + saveProfiles(module, cpu, mem) } -func TestMain(m *testing.M) { +func initFlags() { i := 1 + wzprof := false options = append(options, "speedtest1") for _, arg := range os.Args[1:] { - if strings.HasPrefix(arg, "-test.") { + switch { + case strings.HasPrefix(arg, "-test."): + // keep test flags os.Args[i] = arg i++ - } else { + case arg == "-wzprof": + // collect guest profile + wzprof = true + default: + // collect everything else options = append(options, arg) } } os.Args = os.Args[:i] + flag.Parse() - code := m.Run() - io.Copy(os.Stderr, &output) - os.Exit(code) + if wzprof { + var f *flag.Flag + f = flag.Lookup("test.cpuprofile") + cpuprof = f.Value.String() + f.Value.Set("") + f = flag.Lookup("test.memprofile") + memprof = f.Value.String() + f.Value.Set("") + } +} + +func setupProfiling(ctx context.Context) (context.Context, *wzprof.CPUProfiler, *wzprof.MemoryProfiler) { + var cpu *wzprof.CPUProfiler + var mem *wzprof.MemoryProfiler + + var listeners []experimental.FunctionListenerFactory + if cpuprof != "" { + cpu = wzprof.NewCPUProfiler() + listeners = append(listeners, wzprof.Sample(defaultSampleRate, cpu)) + cpu.StartProfile() + } + if memprof != "" { + mem = wzprof.NewMemoryProfiler() + listeners = append(listeners, wzprof.Sample(defaultSampleRate, mem)) + } + if listeners != nil { + ctx = context.WithValue(ctx, + experimental.FunctionListenerFactoryKey{}, + experimental.MultiFunctionListenerFactory(listeners...)) + } + return ctx, cpu, mem +} + +func saveProfiles(module wazero.CompiledModule, cpu *wzprof.CPUProfiler, mem *wzprof.MemoryProfiler) { + if cpu == nil && mem == nil { + return + } + + symbols, err := wzprof.BuildDwarfSymbolizer(module) + if err != nil { + panic(err) + } + + if cpu != nil { + prof := cpu.StopProfile(defaultSampleRate, symbols) + err := wzprof.WriteProfile(cpuprof, prof) + if err != nil { + panic(err) + } + } + + if mem != nil { + prof := mem.NewProfile(defaultSampleRate, symbols) + err := wzprof.WriteProfile(memprof, prof) + if err != nil { + panic(err) + } + } } func Benchmark_speedtest1(b *testing.B) {