add profile option
This commit is contained in:
parent
160d5751ab
commit
d8ed784311
|
@ -117,15 +117,43 @@ func (p *Profile) HeapProfile(o *ProfileOpts, _ *struct{}) error {
|
||||||
return nil
|
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.
|
// goroutines.
|
||||||
func (p *Profile) Goroutine(o *ProfileOpts, _ *struct{}) error {
|
func (p *Profile) GoroutineProfile(o *ProfileOpts, _ *struct{}) error {
|
||||||
if len(o.FilePayload.Files) < 1 {
|
if len(o.FilePayload.Files) < 1 {
|
||||||
return errNoOutput
|
return errNoOutput
|
||||||
}
|
}
|
||||||
output := o.FilePayload.Files[0]
|
output := o.FilePayload.Files[0]
|
||||||
defer output.Close()
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -101,11 +101,14 @@ const (
|
||||||
|
|
||||||
// Profiling related commands (see pprof.go for more details).
|
// Profiling related commands (see pprof.go for more details).
|
||||||
const (
|
const (
|
||||||
StartCPUProfile = "Profile.StartCPUProfile"
|
StartCPUProfile = "Profile.StartCPUProfile"
|
||||||
StopCPUProfile = "Profile.StopCPUProfile"
|
StopCPUProfile = "Profile.StopCPUProfile"
|
||||||
HeapProfile = "Profile.HeapProfile"
|
HeapProfile = "Profile.HeapProfile"
|
||||||
StartTrace = "Profile.StartTrace"
|
GoroutineProfile = "Profile.GoroutineProfile"
|
||||||
StopTrace = "Profile.StopTrace"
|
BlockProfile = "Profile.BlockProfile"
|
||||||
|
MutexProfile = "Profile.MutexProfile"
|
||||||
|
StartTrace = "Profile.StartTrace"
|
||||||
|
StopTrace = "Profile.StopTrace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logging related commands (see logging.go for more details).
|
// Logging related commands (see logging.go for more details).
|
||||||
|
|
|
@ -32,17 +32,20 @@ import (
|
||||||
|
|
||||||
// Debug implements subcommands.Command for the "debug" command.
|
// Debug implements subcommands.Command for the "debug" command.
|
||||||
type Debug struct {
|
type Debug struct {
|
||||||
pid int
|
pid int
|
||||||
stacks bool
|
stacks bool
|
||||||
signal int
|
signal int
|
||||||
profileHeap string
|
profileHeap string
|
||||||
profileCPU string
|
profileCPU string
|
||||||
trace string
|
profileGoroutine string
|
||||||
strace string
|
profileBlock string
|
||||||
logLevel string
|
profileMutex string
|
||||||
logPackets string
|
trace string
|
||||||
duration time.Duration
|
strace string
|
||||||
ps bool
|
logLevel string
|
||||||
|
logPackets string
|
||||||
|
duration time.Duration
|
||||||
|
ps bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name implements subcommands.Command.
|
// 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.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.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.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.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.StringVar(&d.trace, "trace", "", "writes an execution trace to the given file.")
|
||||||
f.IntVar(&d.signal, "signal", -1, "sends signal to the sandbox")
|
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)
|
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
|
delay := false
|
||||||
if d.profileCPU != "" {
|
if d.profileCPU != "" {
|
||||||
|
|
|
@ -972,6 +972,66 @@ func (s *Sandbox) StopCPUProfile() error {
|
||||||
return nil
|
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.
|
// StartTrace start trace writing to the given file.
|
||||||
func (s *Sandbox) StartTrace(f *os.File) error {
|
func (s *Sandbox) StartTrace(f *os.File) error {
|
||||||
log.Debugf("Trace start %q", s.ID)
|
log.Debugf("Trace start %q", s.ID)
|
||||||
|
|
Loading…
Reference in New Issue