summaryrefslogtreecommitdiffhomepage
path: root/runsc
diff options
context:
space:
mode:
authorBhasker Hariharan <bhaskerh@google.com>2019-05-29 11:30:59 -0700
committerShentubot <shentubot@google.com>2019-05-30 12:07:11 -0700
commit035a8fa38ed21da2e06db22d3dfd6122610fb856 (patch)
tree3650d76b5519f5a3e8efdd0c5df039cacc1502ec /runsc
parentb52e571a6188ce90b5a13b002753230780119db9 (diff)
Add support for collecting execution trace to runsc.
Updates #220 PiperOrigin-RevId: 250532302
Diffstat (limited to 'runsc')
-rw-r--r--runsc/boot/controller.go2
-rw-r--r--runsc/cmd/debug.go55
-rw-r--r--runsc/sandbox/sandbox.go35
3 files changed, 79 insertions, 13 deletions
diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go
index f09c1bd85..72ab9ef86 100644
--- a/runsc/boot/controller.go
+++ b/runsc/boot/controller.go
@@ -101,6 +101,8 @@ const (
StartCPUProfile = "Profile.StartCPUProfile"
StopCPUProfile = "Profile.StopCPUProfile"
HeapProfile = "Profile.HeapProfile"
+ StartTrace = "Profile.StartTrace"
+ StopTrace = "Profile.StopTrace"
)
// ControlSocketAddr generates an abstract unix socket name for the given ID.
diff --git a/runsc/cmd/debug.go b/runsc/cmd/debug.go
index 000f694c7..27eb51172 100644
--- a/runsc/cmd/debug.go
+++ b/runsc/cmd/debug.go
@@ -35,6 +35,7 @@ type Debug struct {
profileHeap string
profileCPU string
profileDelay int
+ trace string
}
// Name implements subcommands.Command.
@@ -59,6 +60,7 @@ func (d *Debug) SetFlags(f *flag.FlagSet) {
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.IntVar(&d.profileDelay, "profile-delay", 5, "amount of time to wait before stoping CPU profile")
+ f.StringVar(&d.trace, "trace", "", "writes an execution trace to the given file.")
f.IntVar(&d.signal, "signal", -1, "sends signal to the sandbox")
}
@@ -122,35 +124,62 @@ func (d *Debug) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
}
log.Infof(" *** Stack dump ***\n%s", stacks)
}
- if d.profileCPU != "" {
- f, err := os.Create(d.profileCPU)
+ if d.profileHeap != "" {
+ f, err := os.Create(d.profileHeap)
if err != nil {
Fatalf(err.Error())
}
defer f.Close()
- if err := c.Sandbox.StartCPUProfile(f); err != nil {
+ if err := c.Sandbox.HeapProfile(f); err != nil {
Fatalf(err.Error())
}
- log.Infof("CPU profile started for %d sec, writing to %q", d.profileDelay, d.profileCPU)
- time.Sleep(time.Duration(d.profileDelay) * time.Second)
+ log.Infof("Heap profile written to %q", d.profileHeap)
+ }
- if err := c.Sandbox.StopCPUProfile(); err != nil {
+ delay := false
+ if d.profileCPU != "" {
+ delay = true
+ f, err := os.Create(d.profileCPU)
+ if err != nil {
Fatalf(err.Error())
}
- log.Infof("CPU profile written to %q", d.profileCPU)
+ defer func() {
+ f.Close()
+ if err := c.Sandbox.StopCPUProfile(); err != nil {
+ Fatalf(err.Error())
+ }
+ log.Infof("CPU profile written to %q", d.profileCPU)
+ }()
+ if err := c.Sandbox.StartCPUProfile(f); err != nil {
+ Fatalf(err.Error())
+ }
+ log.Infof("CPU profile started for %d sec, writing to %q", d.profileDelay, d.profileCPU)
}
- if d.profileHeap != "" {
- f, err := os.Create(d.profileHeap)
+ if d.trace != "" {
+ delay = true
+ f, err := os.Create(d.trace)
if err != nil {
Fatalf(err.Error())
}
- defer f.Close()
-
- if err := c.Sandbox.HeapProfile(f); err != nil {
+ defer func() {
+ f.Close()
+ if err := c.Sandbox.StopTrace(); err != nil {
+ Fatalf(err.Error())
+ }
+ log.Infof("Trace written to %q", d.trace)
+ }()
+ if err := c.Sandbox.StartTrace(f); err != nil {
Fatalf(err.Error())
}
- log.Infof("Heap profile written to %q", d.profileHeap)
+ log.Infof("Tracing started for %d sec, writing to %q", d.profileDelay, d.trace)
+
}
+
+ if delay {
+ time.Sleep(time.Duration(d.profileDelay) * time.Second)
+
+ }
+
return subcommands.ExitSuccess
}
diff --git a/runsc/sandbox/sandbox.go b/runsc/sandbox/sandbox.go
index bc69a9d61..47a66afb2 100644
--- a/runsc/sandbox/sandbox.go
+++ b/runsc/sandbox/sandbox.go
@@ -883,6 +883,41 @@ func (s *Sandbox) StopCPUProfile() error {
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)
+ 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.StartTrace, &opts, nil); err != nil {
+ return fmt.Errorf("starting sandbox %q trace: %v", s.ID, err)
+ }
+ return nil
+}
+
+// StopTrace stops a previously started trace..
+func (s *Sandbox) StopTrace() error {
+ log.Debugf("Trace stop %q", s.ID)
+ conn, err := s.sandboxConnect()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ if err := conn.Call(boot.StopTrace, nil, nil); err != nil {
+ return fmt.Errorf("stopping sandbox %q trace: %v", s.ID, err)
+ }
+ return nil
+}
+
// DestroyContainer destroys the given container. If it is the root container,
// then the entire sandbox is destroyed.
func (s *Sandbox) DestroyContainer(cid string) error {