Skip to content

Commit 2fe225c

Browse files
committed
pprof: take cpu and memory profiles by setting environment variables
When run in standalone mode, the environment variables `DOCKER_BUILDX_CPU_PROFILE` and `DOCKER_BUILDX_MEM_PROFILE` will cause profiles to be written by the CLI. Signed-off-by: Jonathan A. Sternberg <[email protected]>
1 parent 9f0ebd2 commit 2fe225c

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

cmd/buildx/debug.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"os"
6+
"runtime"
7+
"runtime/pprof"
8+
9+
"github.com/moby/buildkit/util/bklog"
10+
"github.com/sirupsen/logrus"
11+
)
12+
13+
func setupDebugProfiles(ctx context.Context) (stop func()) {
14+
var stopFuncs []func()
15+
if fn := setupCPUProfile(ctx); fn != nil {
16+
stopFuncs = append(stopFuncs, fn)
17+
}
18+
if fn := setupHeapProfile(ctx); fn != nil {
19+
stopFuncs = append(stopFuncs, fn)
20+
}
21+
return func() {
22+
for _, fn := range stopFuncs {
23+
fn()
24+
}
25+
}
26+
}
27+
28+
func setupCPUProfile(ctx context.Context) (stop func()) {
29+
if cpuProfile := os.Getenv("BUILDX_CPU_PROFILE"); cpuProfile != "" {
30+
f, err := os.Create(cpuProfile)
31+
if err != nil {
32+
bklog.G(ctx).Warn("could not create cpu profile", logrus.WithError(err))
33+
return nil
34+
}
35+
36+
if err := pprof.StartCPUProfile(f); err != nil {
37+
bklog.G(ctx).Warn("could not start cpu profile", logrus.WithError(err))
38+
_ = f.Close()
39+
return nil
40+
}
41+
42+
return func() {
43+
pprof.StopCPUProfile()
44+
if err := f.Close(); err != nil {
45+
bklog.G(ctx).Warn("could not close file for cpu profile", logrus.WithError(err))
46+
}
47+
}
48+
}
49+
return nil
50+
}
51+
52+
func setupHeapProfile(ctx context.Context) (stop func()) {
53+
if heapProfile := os.Getenv("BUILDX_MEM_PROFILE"); heapProfile != "" {
54+
// Memory profile is only created on stop.
55+
return func() {
56+
f, err := os.Create(heapProfile)
57+
if err != nil {
58+
bklog.G(ctx).Warn("could not create memory profile", logrus.WithError(err))
59+
return
60+
}
61+
62+
// get up-to-date statistics
63+
runtime.GC()
64+
65+
if err := pprof.WriteHeapProfile(f); err != nil {
66+
bklog.G(ctx).Warn("could not write memory profile", logrus.WithError(err))
67+
}
68+
69+
if err := f.Close(); err != nil {
70+
bklog.G(ctx).Warn("could not close file for memory profile", logrus.WithError(err))
71+
}
72+
}
73+
}
74+
return nil
75+
}

cmd/buildx/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ func init() {
4040
}
4141

4242
func runStandalone(cmd *command.DockerCli) error {
43+
stopProfiles := setupDebugProfiles(context.TODO())
44+
defer stopProfiles()
45+
4346
if err := cmd.Initialize(cliflags.NewClientOptions()); err != nil {
4447
return err
4548
}
@@ -65,6 +68,9 @@ func flushMetrics(cmd *command.DockerCli) {
6568
}
6669

6770
func runPlugin(cmd *command.DockerCli) error {
71+
stopProfiles := setupDebugProfiles(context.TODO())
72+
defer stopProfiles()
73+
6874
rootCmd := commands.NewRootCmd("buildx", true, cmd)
6975
return plugin.RunPlugin(cmd, rootCmd, manager.Metadata{
7076
SchemaVersion: "0.1.0",

0 commit comments

Comments
 (0)