summaryrefslogtreecommitdiffhomepage
path: root/runsc/container
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2021-09-13 18:07:29 -0400
committerMichael Pratt <mpratt@google.com>2021-09-16 11:20:37 -0400
commitbd296e799bd3eceaa3c3f3db1227f9dba62bb1a1 (patch)
tree94dd1cd89df012d7159b0922e5f2f53914e73e8a /runsc/container
parent9bdeddd8826f98251584567b4157c63b297b7825 (diff)
runsc: add global profile collection flags
Add global flags -profile-{block,cpu,heap,mutex} and -trace which enable collection of the specified profile for the entire duration of a container execution. This provides a way to definitively start profiling before that application starts, rather than attempting to race with an out-of-band `runsc debug`. Note that only the main boot process is profiled. This exposed a bug in Task.traceExecEvent: a crash when tracing and -race are enabled. traceExecEvent is called off of the task goroutine, but uses the Task as a context, which is a violation of the Task contract. Switching to the AsyncContext fixes the issue. Fixes #220
Diffstat (limited to 'runsc/container')
-rw-r--r--runsc/container/container_test.go43
1 files changed, 43 insertions, 0 deletions
diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go
index 681f5c1a9..69dcf3f03 100644
--- a/runsc/container/container_test.go
+++ b/runsc/container/container_test.go
@@ -2829,3 +2829,46 @@ func TestStream(t *testing.T) {
t.Errorf("out got %s, want include %s", buf, want)
}
}
+
+// TestProfile checks that profiling options generate profiles.
+func TestProfile(t *testing.T) {
+ // Perform a non-trivial amount of work so we actually capture
+ // something in the profiles.
+ spec := testutil.NewSpecWithArgs("/bin/bash", "-c", "true")
+ conf := testutil.TestConfig(t)
+ conf.ProfileEnable = true
+ conf.ProfileBlock = filepath.Join(t.TempDir(), "block.pprof")
+ conf.ProfileCPU = filepath.Join(t.TempDir(), "cpu.pprof")
+ conf.ProfileHeap = filepath.Join(t.TempDir(), "heap.pprof")
+ conf.ProfileMutex = filepath.Join(t.TempDir(), "mutex.pprof")
+ conf.TraceFile = filepath.Join(t.TempDir(), "trace.out")
+
+ _, bundleDir, cleanup, err := testutil.SetupContainer(spec, conf)
+ if err != nil {
+ t.Fatalf("error setting up container: %v", err)
+ }
+ defer cleanup()
+
+ args := Args{
+ ID: testutil.RandomContainerID(),
+ Spec: spec,
+ BundleDir: bundleDir,
+ Attached: true,
+ }
+
+ _, err = Run(conf, args)
+ if err != nil {
+ t.Fatalf("Creating container: %v", err)
+ }
+
+ // Basic test; simply assert that the profiles are not empty.
+ for _, name := range []string{conf.ProfileBlock, conf.ProfileCPU, conf.ProfileHeap, conf.ProfileMutex, conf.TraceFile} {
+ fi, err := os.Stat(name)
+ if err != nil {
+ t.Fatalf("Unable to stat profile file %s: %v", name, err)
+ }
+ if fi.Size() == 0 {
+ t.Errorf("Profile file %s is empty: %+v", name, fi)
+ }
+ }
+}