blob: 7fc68599f5d367cdecc75ef83ff8600d3d1754d0 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package server
import (
"fmt"
"io"
"net/http"
"os"
"sync"
"golang.org/x/benchmarks/sweet/benchmarks/internal/driver"
"golang.org/x/benchmarks/sweet/common/diagnostics"
)
func CollectDiagnostic(host, tmpDir, benchName string, typ diagnostics.Type) (int64, error) {
f, err := os.CreateTemp(tmpDir, benchName+"."+string(typ))
if err != nil {
return 0, err
}
defer f.Close()
resp, err := http.Get(fmt.Sprintf("http://%s/debug/pprof/%s", host, endpoint(typ)))
if err != nil {
return 0, err
}
defer resp.Body.Close()
n, err := io.Copy(f, resp.Body)
if err != nil {
return 0, err
}
return n, driver.CopyDiagnosticData(f.Name(), typ, benchName)
}
func endpoint(typ diagnostics.Type) string {
switch typ {
case diagnostics.CPUProfile:
return "profile?seconds=1"
case diagnostics.MemProfile:
return "heap"
case diagnostics.Trace:
return "trace?seconds=1"
}
panic("diagnostic " + string(typ) + " has no endpoint")
}
func PollDiagnostic(host, tmpDir, benchName string, typ diagnostics.Type) (stop func() uint64) {
// TODO(mknyszek): This is kind of a hack. We really should find a way to just
// enable diagnostic collection at a lower level for the entire server run.
var stopc chan struct{}
var wg sync.WaitGroup
var size uint64
wg.Add(1)
stopc = make(chan struct{})
go func() {
defer wg.Done()
for {
select {
case <-stopc:
return
default:
}
n, err := CollectDiagnostic(host, tmpDir, benchName, typ)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to read diagnostic %s: %v", typ, err)
return
}
size += uint64(n)
}
}()
return func() uint64 {
// Stop the loop.
close(stopc)
wg.Wait()
return size
}
}