Skip to content

Commit

Permalink
Add some goroutine labels & dump stacks if we think we've hung
Browse files Browse the repository at this point in the history
  • Loading branch information
peterebden committed Nov 8, 2024
1 parent 83e0243 commit 2d1814f
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 1 deletion.
14 changes: 14 additions & 0 deletions src/core/state.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package core

import (
"bytes"
"crypto/sha1"
"crypto/sha256"
"fmt"
Expand All @@ -11,6 +12,7 @@ import (
iofs "io/fs"
"iter"
"path/filepath"
"runtime/pprof"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -630,6 +632,10 @@ func (state *BuildState) forwardResults() {
}
}()
activeTargets := map[*BuildTarget]struct{}{}
go func() {
time.Sleep(4 * time.Second)
dumpGoroutineInfo()
}()
// Persist this one timer throughout so we don't generate bazillions of them.
t := time.NewTimer(cycleCheckDuration)
t.Stop()
Expand All @@ -645,6 +651,7 @@ func (state *BuildState) forwardResults() {
}
case <-t.C:
go state.checkForCycles()
go dumpGoroutineInfo()
// Still need to get a result!
result = <-state.progress.internalResults
}
Expand Down Expand Up @@ -1534,3 +1541,10 @@ func (s BuildResultStatus) IsFailure() bool {
func (s BuildResultStatus) IsActive() bool {
return s == PackageParsing || s == TargetBuilding || s == TargetTesting
}

// dumpGoroutineInfo logs out the goroutine stacks when we believe we might have hung.
func dumpGoroutineInfo() {
var buf bytes.Buffer
pprof.Lookup("goroutine").WriteTo(&buf, 1)
log.Debug("Current stacks: %s", buf.String())
}
4 changes: 4 additions & 0 deletions src/parse/asp/interpreter.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package asp

import (
"context"
"fmt"
"iter"
"path/filepath"
"reflect"
"runtime/debug"
"runtime/pprof"
"strings"
"sync"

Expand Down Expand Up @@ -206,6 +208,8 @@ func (i *interpreter) interpretStatements(s *scope, statements []*Statement) (re
func (i *interpreter) Subinclude(pkgScope *scope, path string, label core.BuildLabel, preload bool) pyDict {
key := filepath.Join(path, pkgScope.state.CurrentSubrepo)
globals, err := i.subincludes.GetOrSet(key, func() (pyDict, error) {
pprof.SetGoroutineLabels(pprof.WithLabels(context.Background(), pprof.Labels("subinclude", path)))
defer pprof.SetGoroutineLabels(context.Background())
stmts, err := i.parseSubinclude(path)
if err != nil {
return nil, err
Expand Down
6 changes: 5 additions & 1 deletion src/parse/parse_step.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
package parse

import (
"context"
"errors"
"fmt"
iofs "io/fs"
"path/filepath"
"runtime/pprof"
"strings"

"github.com/thought-machine/please/src/cli/logging"
Expand Down Expand Up @@ -79,7 +81,9 @@ func parse(state *core.BuildState, label, dependent core.BuildLabel, mode core.P
if label.Subrepo != "" && label.PackageName == "" && label.Name == "" {
return nil
}
pkg, err = parsePackage(state, label, dependent, subrepo, mode)
pprof.Do(context.Background(), pprof.Labels("parse", label.String()), func(_ context.Context) {
pkg, err = parsePackage(state, label, dependent, subrepo, mode)
})

if err != nil {
return err
Expand Down

0 comments on commit 2d1814f

Please sign in to comment.