Skip to content

Commit 5e1b224

Browse files
authored
feat: add full goroutine stack dump (#8790)
1 parent 04e7e95 commit 5e1b224

File tree

5 files changed

+52
-0
lines changed

5 files changed

+52
-0
lines changed

bin/collect-profiles.sh

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ fi
2424
echo Collecting goroutine stacks
2525
curl -s -o goroutines.stacks "$SOURCE_URL"'/debug/pprof/goroutine?debug=2'
2626

27+
curl -s -o goroutines.stacks.full "$SOURCE_URL"'/debug/stack'
28+
2729
echo Collecting goroutine profile
2830
go tool pprof -symbolize=remote -svg -output goroutine.svg "$SOURCE_URL/debug/pprof/goroutine"
2931

cmd/ipfs/daemon.go

+1
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
660660
corehttp.VersionOption(),
661661
defaultMux("/debug/vars"),
662662
defaultMux("/debug/pprof/"),
663+
defaultMux("/debug/stack"),
663664
corehttp.MutexFractionOption("/debug/pprof-mutex/"),
664665
corehttp.BlockProfileRateOption("/debug/pprof-block/"),
665666
corehttp.MetricsScrapingOption("/debug/metrics/prometheus"),

cmd/ipfs/debug.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package main
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/ipfs/go-ipfs/core/commands"
7+
)
8+
9+
func init() {
10+
http.HandleFunc("/debug/stack",
11+
func(w http.ResponseWriter, _ *http.Request) {
12+
_ = commands.WriteAllGoroutineStacks(w)
13+
},
14+
)
15+
}

core/commands/profile.go

+30
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,25 @@ However, it could reveal:
121121
},
122122
}
123123

124+
func WriteAllGoroutineStacks(w io.Writer) error {
125+
// this is based on pprof.writeGoroutineStacks, and removes the 64 MB limit
126+
buf := make([]byte, 1<<20)
127+
for i := 0; ; i++ {
128+
n := runtime.Stack(buf, true)
129+
if n < len(buf) {
130+
buf = buf[:n]
131+
break
132+
}
133+
// if len(buf) >= 64<<20 {
134+
// // Filled 64 MB - stop there.
135+
// break
136+
// }
137+
buf = make([]byte, 2*len(buf))
138+
}
139+
_, err := w.Write(buf)
140+
return err
141+
}
142+
124143
func writeProfiles(ctx context.Context, cpuProfileTime time.Duration, w io.Writer) error {
125144
archive := zip.NewWriter(w)
126145

@@ -143,6 +162,17 @@ func writeProfiles(ctx context.Context, cpuProfileTime time.Duration, w io.Write
143162
file: "heap.pprof",
144163
}}
145164

165+
{
166+
out, err := archive.Create("goroutines-all.stacks")
167+
if err != nil {
168+
return err
169+
}
170+
err = WriteAllGoroutineStacks(out)
171+
if err != nil {
172+
return err
173+
}
174+
}
175+
146176
for _, profile := range profiles {
147177
prof := pprof.Lookup(profile.name)
148178
out, err := archive.Create(profile.file)

test/sharness/t0152-profile.sh

+4
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,8 @@ test_expect_success "goroutines stacktrace is valid" '
6161
grep -q "goroutine" "profiles/goroutines.stacks"
6262
'
6363

64+
test_expect_success "full goroutines stacktrace is valid" '
65+
grep -q "goroutine" "profiles/goroutines-all.stacks"
66+
'
67+
6468
test_done

0 commit comments

Comments
 (0)