Skip to content

Commit

Permalink
Enabled always-on profiling, accessible through SIGUSR[12].
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobsa committed Jul 27, 2015
2 parents 517004d + 0ecbe77 commit 820de48
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 84 deletions.
14 changes: 0 additions & 14 deletions flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,6 @@ func newApp() (app *cli.App) {
// Debugging
/////////////////////////

cli.BoolFlag{
Name: "debug_cpu_profile",
Usage: "Write a 10-second CPU profile to /tmp on SIGHUP.",
},

cli.BoolFlag{
Name: "debug_fuse",
Usage: "Enable fuse-related debugging output.",
Expand All @@ -171,11 +166,6 @@ func newApp() (app *cli.App) {
Name: "debug_invariants",
Usage: "Panic when internal invariants are violated.",
},

cli.BoolFlag{
Name: "debug_mem_profile",
Usage: "Write a 10-second memory profile to /tmp on SIGHUP.",
},
},
}

Expand Down Expand Up @@ -204,12 +194,10 @@ type flagStorage struct {
TempDirLimit int64

// Debugging
DebugCPUProfile bool
DebugFuse bool
DebugGCS bool
DebugHTTP bool
DebugInvariants bool
DebugMemProfile bool
}

// Add the flags accepted by run to the supplied flag set, returning the
Expand Down Expand Up @@ -237,12 +225,10 @@ func populateFlags(c *cli.Context) (flags *flagStorage) {
ImplicitDirs: c.Bool("implicit-dirs"),

// Debugging,
DebugCPUProfile: c.Bool("debug_cpu_profile"),
DebugFuse: c.Bool("debug_fuse"),
DebugGCS: c.Bool("debug_gcs"),
DebugHTTP: c.Bool("debug_http"),
DebugInvariants: c.Bool("debug_invariants"),
DebugMemProfile: c.Bool("debug_mem_profile"),
}

// Handle the repeated "-o" flag.
Expand Down
6 changes: 0 additions & 6 deletions flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,23 +83,19 @@ func (t *FlagsTest) Defaults() {
ExpectEq(1<<31, f.TempDirLimit)

// Debugging
ExpectFalse(f.DebugCPUProfile)
ExpectFalse(f.DebugFuse)
ExpectFalse(f.DebugGCS)
ExpectFalse(f.DebugHTTP)
ExpectFalse(f.DebugInvariants)
ExpectFalse(f.DebugMemProfile)
}

func (t *FlagsTest) Bools() {
names := []string{
"implicit-dirs",
"debug_cpu_profile",
"debug_fuse",
"debug_gcs",
"debug_http",
"debug_invariants",
"debug_mem_profile",
}

var args []string
Expand All @@ -113,12 +109,10 @@ func (t *FlagsTest) Bools() {

f = parseArgs(args)
ExpectTrue(f.ImplicitDirs)
ExpectTrue(f.DebugCPUProfile)
ExpectTrue(f.DebugFuse)
ExpectTrue(f.DebugGCS)
ExpectTrue(f.DebugHTTP)
ExpectTrue(f.DebugInvariants)
ExpectTrue(f.DebugMemProfile)

// --foo=false form
args = nil
Expand Down
135 changes: 71 additions & 64 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"log"
"os"
"os/signal"
"runtime"
"runtime/pprof"
"syscall"
"time"
Expand Down Expand Up @@ -60,85 +61,90 @@ func registerSIGINTHandler(mountPoint string) {
}()
}

// Dump profiles on SIGHUP, if enabled.
func registerSIGHUPHandler(cpu bool, mem bool) {
var desc string
switch {
case cpu && mem:
desc = "CPU and memory profiles"

case cpu:
desc = "CPU profile"
func handleCPUProfileSignals() {
profileOnce := func(duration time.Duration, path string) (err error) {
// Set up the file.
var f *os.File
f, err = os.Create(path)
if err != nil {
err = fmt.Errorf("Create: %v", err)
return
}

case mem:
desc = "memory profile"
defer func() {
closeErr := f.Close()
if err == nil {
err = closeErr
}
}()

default:
// Profile.
pprof.StartCPUProfile(f)
time.Sleep(duration)
pprof.StopCPUProfile()
return
}

const duration = 10 * time.Second
profileOnce := func() (err error) {
// CPU
if cpu {
var f *os.File
f, err = os.Create("/tmp/cpu.pprof")
if err != nil {
err = fmt.Errorf("Create: %v", err)
return
}
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGUSR1)
for range c {
const path = "/tmp/cpu.pprof"
const duration = 10 * time.Second

log.Printf("Writing %v CPU profile to %s...", duration, path)

err := profileOnce(duration, path)
if err == nil {
log.Printf("Done writing CPU profile to %s.", path)
} else {
log.Printf("Error writing CPU profile: %v", err)
}
}
}

defer func() {
closeErr := f.Close()
if err == nil {
err = closeErr
}
}()
func handleMemoryProfileSignals() {
profileOnce := func(path string) (err error) {
// Trigger a garbage collection to get up to date information (cf.
// https://goo.gl/aXVQfL).
runtime.GC()

pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// Open the file.
var f *os.File
f, err = os.Create(path)
if err != nil {
err = fmt.Errorf("Create: %v", err)
return
}

// Memory
if mem {
var f *os.File
f, err = os.Create("/tmp/mem.pprof")
if err != nil {
err = fmt.Errorf("Create: %v", err)
return
defer func() {
closeErr := f.Close()
if err == nil {
err = closeErr
}
}()

defer func() {
closeErr := f.Close()
if err == nil {
err = closeErr
}
}()

defer func() {
pprof.Lookup("heap").WriteTo(f, 0)
}()
// Dump to the file.
err = pprof.Lookup("heap").WriteTo(f, 0)
if err != nil {
err = fmt.Errorf("WriteTo: %v", err)
return
}

time.Sleep(duration)
return
}

c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP)

// Wait for SIGHUP in the background.
go func() {
for {
<-c
log.Printf("Received SIGHUP. Dumping %s to /tmp...", desc)
if err := profileOnce(); err != nil {
log.Printf("Error profiling: %v", err)
} else {
log.Println("Done profiling.")
}
signal.Notify(c, syscall.SIGUSR2)
for range c {
const path = "/tmp/mem.pprof"

err := profileOnce(path)
if err == nil {
log.Printf("Wrote memory profile to %s.", path)
} else {
log.Printf("Error writing memory profile: %v", err)
}
}()
}
}

// Create token source from the JSON file at the supplide path.
Expand Down Expand Up @@ -210,6 +216,10 @@ func main() {
// Make logging output better.
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

// Set up profiling handlers.
go handleCPUProfileSignals()
go handleMemoryProfileSignals()

app := newApp()
app.Action = func(c *cli.Context) {
var err error
Expand All @@ -234,9 +244,6 @@ func main() {
syncutil.EnableInvariantChecking()
}

// Enable profiling if requested.
registerSIGHUPHandler(flags.DebugCPUProfile, flags.DebugMemProfile)

// Grab the connection.
conn, err := getConn(flags)
if err != nil {
Expand Down

0 comments on commit 820de48

Please sign in to comment.