add profile option

This commit is contained in:
moricho 2020-02-25 16:49:08 +09:00
parent 160d5751ab
commit d8ed784311
4 changed files with 152 additions and 19 deletions

View File

@ -117,15 +117,43 @@ func (p *Profile) HeapProfile(o *ProfileOpts, _ *struct{}) error {
return nil
}
// Goroutine is an RPC stub which dumps out the stack trace for all running
// GoroutineProfile is an RPC stub which dumps out the stack trace for all running
// goroutines.
func (p *Profile) Goroutine(o *ProfileOpts, _ *struct{}) error {
func (p *Profile) GoroutineProfile(o *ProfileOpts, _ *struct{}) error {
if len(o.FilePayload.Files) < 1 {
return errNoOutput
}
output := o.FilePayload.Files[0]
defer output.Close()
if err := pprof.Lookup("goroutine").WriteTo(output, 2); err != nil {
if err := pprof.Lookup("goroutine").WriteTo(output, 0); err != nil {
return err
}
return nil
}
// BlockProfile is an RPC stub which dumps out the stack trace that led to
// blocking on synchronization primitives.
func (p *Profile) BlockProfile(o *ProfileOpts, _ *struct{}) error {
if len(o.FilePayload.Files) < 1 {
return errNoOutput
}
output := o.FilePayload.Files[0]
defer output.Close()
if err := pprof.Lookup("block").WriteTo(output, 0); err != nil {
return err
}
return nil
}
// MutexProfile is an RPC stub which dumps out the stack trace of holders of
// contended mutexes.
func (p *Profile) MutexProfile(o *ProfileOpts, _ *struct{}) error {
if len(o.FilePayload.Files) < 1 {
return errNoOutput
}
output := o.FilePayload.Files[0]
defer output.Close()
if err := pprof.Lookup("mutex").WriteTo(output, 0); err != nil {
return err
}
return nil

View File

@ -101,11 +101,14 @@ const (
// Profiling related commands (see pprof.go for more details).
const (
StartCPUProfile = "Profile.StartCPUProfile"
StopCPUProfile = "Profile.StopCPUProfile"
HeapProfile = "Profile.HeapProfile"
StartTrace = "Profile.StartTrace"
StopTrace = "Profile.StopTrace"
StartCPUProfile = "Profile.StartCPUProfile"
StopCPUProfile = "Profile.StopCPUProfile"
HeapProfile = "Profile.HeapProfile"
GoroutineProfile = "Profile.GoroutineProfile"
BlockProfile = "Profile.BlockProfile"
MutexProfile = "Profile.MutexProfile"
StartTrace = "Profile.StartTrace"
StopTrace = "Profile.StopTrace"
)
// Logging related commands (see logging.go for more details).

View File

@ -32,17 +32,20 @@ import (
// Debug implements subcommands.Command for the "debug" command.
type Debug struct {
pid int
stacks bool
signal int
profileHeap string
profileCPU string
trace string
strace string
logLevel string
logPackets string
duration time.Duration
ps bool
pid int
stacks bool
signal int
profileHeap string
profileCPU string
profileGoroutine string
profileBlock string
profileMutex string
trace string
strace string
logLevel string
logPackets string
duration time.Duration
ps bool
}
// Name implements subcommands.Command.
@ -66,6 +69,9 @@ func (d *Debug) SetFlags(f *flag.FlagSet) {
f.BoolVar(&d.stacks, "stacks", false, "if true, dumps all sandbox stacks to the log")
f.StringVar(&d.profileHeap, "profile-heap", "", "writes heap profile to the given file.")
f.StringVar(&d.profileCPU, "profile-cpu", "", "writes CPU profile to the given file.")
f.StringVar(&d.profileGoroutine, "profile-goroutine", "", "writes goroutine profile to the given file.")
f.StringVar(&d.profileBlock, "profile-block", "", "writes block profile to the given file.")
f.StringVar(&d.profileMutex, "profile-mutex", "", "writes mutex profile to the given file.")
f.DurationVar(&d.duration, "duration", time.Second, "amount of time to wait for CPU and trace profiles")
f.StringVar(&d.trace, "trace", "", "writes an execution trace to the given file.")
f.IntVar(&d.signal, "signal", -1, "sends signal to the sandbox")
@ -147,6 +153,42 @@ func (d *Debug) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
}
log.Infof("Heap profile written to %q", d.profileHeap)
}
if d.profileGoroutine != "" {
f, err := os.Create(d.profileGoroutine)
if err != nil {
return Errorf(err.Error())
}
defer f.Close()
if err := c.Sandbox.GoroutineProfile(f); err != nil {
return Errorf(err.Error())
}
log.Infof("Goroutine profile written to %q", d.profileGoroutine)
}
if d.profileBlock != "" {
f, err := os.Create(d.profileBlock)
if err != nil {
return Errorf(err.Error())
}
defer f.Close()
if err := c.Sandbox.BlockProfile(f); err != nil {
return Errorf(err.Error())
}
log.Infof("Block profile written to %q", d.profileBlock)
}
if d.profileMutex != "" {
f, err := os.Create(d.profileMutex)
if err != nil {
return Errorf(err.Error())
}
defer f.Close()
if err := c.Sandbox.MutexProfile(f); err != nil {
return Errorf(err.Error())
}
log.Infof("Mutex profile written to %q", d.profileMutex)
}
delay := false
if d.profileCPU != "" {

View File

@ -972,6 +972,66 @@ func (s *Sandbox) StopCPUProfile() error {
return nil
}
// GoroutineProfile writes a goroutine profile to the given file.
func (s *Sandbox) GoroutineProfile(f *os.File) error {
log.Debugf("Goroutine profile %q", s.ID)
conn, err := s.sandboxConnect()
if err != nil {
return err
}
defer conn.Close()
opts := control.ProfileOpts{
FilePayload: urpc.FilePayload{
Files: []*os.File{f},
},
}
if err := conn.Call(boot.GoroutineProfile, &opts, nil); err != nil {
return fmt.Errorf("getting sandbox %q goroutine profile: %v", s.ID, err)
}
return nil
}
// BlockProfile writes a block profile to the given file.
func (s *Sandbox) BlockProfile(f *os.File) error {
log.Debugf("Block profile %q", s.ID)
conn, err := s.sandboxConnect()
if err != nil {
return err
}
defer conn.Close()
opts := control.ProfileOpts{
FilePayload: urpc.FilePayload{
Files: []*os.File{f},
},
}
if err := conn.Call(boot.BlockProfile, &opts, nil); err != nil {
return fmt.Errorf("getting sandbox %q block profile: %v", s.ID, err)
}
return nil
}
// MutexProfile writes a mutex profile to the given file.
func (s *Sandbox) MutexProfile(f *os.File) error {
log.Debugf("Mutex profile %q", s.ID)
conn, err := s.sandboxConnect()
if err != nil {
return err
}
defer conn.Close()
opts := control.ProfileOpts{
FilePayload: urpc.FilePayload{
Files: []*os.File{f},
},
}
if err := conn.Call(boot.MutexProfile, &opts, nil); err != nil {
return fmt.Errorf("getting sandbox %q mutex profile: %v", s.ID, err)
}
return nil
}
// StartTrace start trace writing to the given file.
func (s *Sandbox) StartTrace(f *os.File) error {
log.Debugf("Trace start %q", s.ID)