Skip to content

Commit

Permalink
sweet: add support for execution traces and refactor profile plumbing
Browse files Browse the repository at this point in the history
This change does a lot at once, but it's mostly refactoring. First, it
moves most of the profile abstraction out of benchmarks/internal/driver
and into a new shared package called diagnostics. It also renames
profiles to diagnostics to better capture the breadth of what this
mechanism collects. Then, it adds support for turning on diagnostics
from configuration files. Next, it adds support for generating
additional configurations to capture the overhead of collecting
diagnostics, starting with CPU profiling. Lastly, it adds support for
the new Trace diagnostic.

In the future, core dumps could easily be folded into this new
diagnostics abstraction.

For golang/go#57175.

Change-Id: I999773e8be28c46fb5d4f6a79a94d542491e3754
  • Loading branch information
mknyszek committed Feb 7, 2023
1 parent 555ee2b commit b30e46e
Show file tree
Hide file tree
Showing 11 changed files with 536 additions and 185 deletions.
59 changes: 39 additions & 20 deletions sweet/benchmarks/go-build/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"golang.org/x/benchmarks/sweet/benchmarks/internal/cgroups"
"golang.org/x/benchmarks/sweet/benchmarks/internal/driver"
"golang.org/x/benchmarks/sweet/common"
"golang.org/x/benchmarks/sweet/common/diagnostics"
sprofile "golang.org/x/benchmarks/sweet/common/profile"
)

Expand Down Expand Up @@ -76,7 +77,7 @@ func run(pkgPath string) error {

cmdArgs = append(cmdArgs, "-toolexec", strings.Join(selfCmd, " "))
var baseCmd *exec.Cmd
if driver.ProfilingEnabled(driver.ProfilePerf) {
if driver.DiagnosticEnabled(diagnostics.Perf) {
baseCmd = exec.Command("perf", append([]string{"record", "-o", filepath.Join(tmpDir, "perf.data"), goTool}, cmdArgs...)...)
} else {
baseCmd = exec.Command(goTool, cmdArgs...)
Expand All @@ -98,41 +99,55 @@ func run(pkgPath string) error {

// Handle any CPU profiles produced, and merge them.
// Then, write them out to the canonical profiles above.
if driver.ProfilingEnabled(driver.ProfileCPU) {
compileProfile, err := mergeProfiles(tmpDir, profilePrefix("compile", driver.ProfileCPU))
if driver.DiagnosticEnabled(diagnostics.CPUProfile) {
compileProfile, err := mergePprofProfiles(tmpDir, profilePrefix("compile", diagnostics.CPUProfile))
if err != nil {
return err
}
if err := driver.WriteProfile(compileProfile, driver.ProfileCPU, name+"Compile"); err != nil {
if err := driver.WritePprofProfile(compileProfile, diagnostics.CPUProfile, name+"Compile"); err != nil {
return err
}

linkProfile, err := mergeProfiles(tmpDir, profilePrefix("link", driver.ProfileCPU))
linkProfile, err := mergePprofProfiles(tmpDir, profilePrefix("link", diagnostics.CPUProfile))
if err != nil {
return err
}
if err := driver.WriteProfile(linkProfile, driver.ProfileCPU, name+"Link"); err != nil {
if err := driver.WritePprofProfile(linkProfile, diagnostics.CPUProfile, name+"Link"); err != nil {
return err
}
}
if driver.ProfilingEnabled(driver.ProfileMem) {
if err := copyProfiles(tmpDir, "compile", driver.ProfileMem, name+"Compile"); err != nil {
if driver.DiagnosticEnabled(diagnostics.MemProfile) {
if err := copyPprofProfiles(tmpDir, "compile", diagnostics.MemProfile, name+"Compile"); err != nil {
return err
}
if err := copyProfiles(tmpDir, "link", driver.ProfileMem, name+"Link"); err != nil {
if err := copyPprofProfiles(tmpDir, "link", diagnostics.MemProfile, name+"Link"); err != nil {
return err
}
}
if driver.ProfilingEnabled(driver.ProfilePerf) {
if err := driver.CopyProfile(filepath.Join(tmpDir, "perf.data"), driver.ProfilePerf, name); err != nil {
if driver.DiagnosticEnabled(diagnostics.Perf) {
if err := driver.CopyDiagnosticData(filepath.Join(tmpDir, "perf.data"), diagnostics.Perf, name); err != nil {
return err
}
}
if driver.DiagnosticEnabled(diagnostics.Trace) {
entries, err := os.ReadDir(tmpDir)
if err != nil {
return err
}
for _, entry := range entries {
if !strings.HasPrefix(entry.Name(), profilePrefix("compile", diagnostics.Trace)) {
continue
}
if err := driver.CopyDiagnosticData(filepath.Join(tmpDir, entry.Name()), diagnostics.Trace, name+"Compile"); err != nil {
return err
}
}
}
return printOtherResults(tmpResultsDir())
}

func mergeProfiles(dir, prefix string) (*profile.Profile, error) {
profiles, err := sprofile.ReadDir(dir, func(name string) bool {
func mergePprofProfiles(dir, prefix string) (*profile.Profile, error) {
profiles, err := sprofile.ReadDirPprof(dir, func(name string) bool {
return strings.HasPrefix(name, prefix)
})
if err != nil {
Expand All @@ -141,23 +156,23 @@ func mergeProfiles(dir, prefix string) (*profile.Profile, error) {
return profile.Merge(profiles)
}

func copyProfiles(dir, bin string, typ driver.ProfileType, finalPrefix string) error {
func copyPprofProfiles(dir, bin string, typ diagnostics.Type, finalPrefix string) error {
prefix := profilePrefix(bin, typ)
profiles, err := sprofile.ReadDir(dir, func(name string) bool {
profiles, err := sprofile.ReadDirPprof(dir, func(name string) bool {
return strings.HasPrefix(name, prefix)
})
if err != nil {
return err
}
for _, profile := range profiles {
if err := driver.WriteProfile(profile, typ, finalPrefix); err != nil {
if err := driver.WritePprofProfile(profile, typ, finalPrefix); err != nil {
return err
}
}
return nil
}

func profilePrefix(bin string, typ driver.ProfileType) string {
func profilePrefix(bin string, typ diagnostics.Type) string {
return bin + "-prof." + string(typ)
}

Expand Down Expand Up @@ -200,15 +215,19 @@ func runToolexec() error {
return cmd.Run()
}
var extraFlags []string
for _, typ := range []driver.ProfileType{driver.ProfileCPU, driver.ProfileMem} {
if driver.ProfilingEnabled(typ) {
for _, typ := range []diagnostics.Type{diagnostics.CPUProfile, diagnostics.MemProfile, diagnostics.Trace} {
if driver.DiagnosticEnabled(typ) {
if bin == "link" && typ == diagnostics.Trace {
// TODO(mknyszek): Traces are not supported for the linker.
continue
}
// Stake a claim for a filename.
f, err := os.CreateTemp(tmpDir, profilePrefix(bin, typ))
if err != nil {
return err
}
f.Close()
extraFlags = append(extraFlags, "-"+string(typ)+"profile", f.Name())
extraFlags = append(extraFlags, "-"+string(typ), f.Name())
}
}
cmd := exec.Command(flag.Args()[0], append(extraFlags, flag.Args()[1:]...)...)
Expand Down
22 changes: 13 additions & 9 deletions sweet/benchmarks/gvisor/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"golang.org/x/benchmarks/sweet/benchmarks/internal/driver"
"golang.org/x/benchmarks/sweet/common"
"golang.org/x/benchmarks/sweet/common/diagnostics"
)

func workloadsPath(assetsDir, subBenchmark string) string {
Expand All @@ -23,30 +24,33 @@ func workloadsPath(assetsDir, subBenchmark string) string {
return filepath.Join(assetsDir, subBenchmark, "bin", platformDir, "workload")
}

func (c *config) profilePath(typ driver.ProfileType) string {
func (c *config) profilePath(typ diagnostics.Type) string {
return filepath.Join(c.tmpDir, string(typ)+".prof")
}

func (cfg *config) runscCmd(arg ...string) *exec.Cmd {
var cmd *exec.Cmd
goProfiling := false
for _, typ := range []driver.ProfileType{driver.ProfileCPU, driver.ProfileMem} {
if driver.ProfilingEnabled(typ) {
for _, typ := range []diagnostics.Type{diagnostics.CPUProfile, diagnostics.MemProfile, diagnostics.Trace} {
if driver.DiagnosticEnabled(typ) {
goProfiling = true
break
}
}
if goProfiling {
arg = append([]string{"-profile"}, arg...)
}
if driver.ProfilingEnabled(driver.ProfileCPU) {
arg = append([]string{"-profile-cpu", cfg.profilePath(driver.ProfileCPU)}, arg...)
if driver.DiagnosticEnabled(diagnostics.CPUProfile) {
arg = append([]string{"-profile-cpu", cfg.profilePath(diagnostics.CPUProfile)}, arg...)
}
if driver.ProfilingEnabled(driver.ProfileMem) {
arg = append([]string{"-profile-heap", cfg.profilePath(driver.ProfileMem)}, arg...)
if driver.DiagnosticEnabled(diagnostics.MemProfile) {
arg = append([]string{"-profile-heap", cfg.profilePath(diagnostics.MemProfile)}, arg...)
}
if driver.ProfilingEnabled(driver.ProfilePerf) {
cmd = exec.Command("perf", append([]string{"record", "-o", cfg.profilePath(driver.ProfilePerf), cfg.runscPath}, arg...)...)
if driver.DiagnosticEnabled(diagnostics.Trace) {
arg = append([]string{"-trace", cfg.profilePath(diagnostics.Trace)}, arg...)
}
if driver.DiagnosticEnabled(diagnostics.Perf) {
cmd = exec.Command("perf", append([]string{"record", "-o", cfg.profilePath(diagnostics.Perf), cfg.runscPath}, arg...)...)
} else {
cmd = exec.Command(cfg.runscPath, arg...)
}
Expand Down
7 changes: 4 additions & 3 deletions sweet/benchmarks/gvisor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"time"

"golang.org/x/benchmarks/sweet/benchmarks/internal/driver"
"golang.org/x/benchmarks/sweet/common/diagnostics"
)

type config struct {
Expand Down Expand Up @@ -66,12 +67,12 @@ func main1() error {
}
return err
}
for _, typ := range driver.ProfileTypes {
if !driver.ProfilingEnabled(typ) {
for _, typ := range diagnostics.Types() {
if !driver.DiagnosticEnabled(typ) {
continue
}
// runscCmd ensures these are created if necessary.
if err := driver.CopyProfile(cliCfg.profilePath(typ), typ, bench.name()); err != nil {
if err := driver.CopyDiagnosticData(cliCfg.profilePath(typ), typ, bench.name()); err != nil {
return err
}
}
Expand Down
Loading

0 comments on commit b30e46e

Please sign in to comment.