You've already forked go-profiler-notes
mirror of
https://github.com/DataDog/go-profiler-notes.git
synced 2025-07-12 23:50:13 +02:00
187 lines
3.6 KiB
Go
187 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
_ "net/http/pprof"
|
|
"runtime"
|
|
"runtime/pprof"
|
|
"time"
|
|
)
|
|
|
|
type Profile struct {
|
|
Name string
|
|
WriteTo func(w io.Writer) error
|
|
}
|
|
|
|
var profiles = []Profile{
|
|
{
|
|
Name: "runtime.stack.txt",
|
|
WriteTo: func(w io.Writer) error {
|
|
buf := make([]byte, 1024*1024)
|
|
n := runtime.Stack(buf, true)
|
|
buf = buf[:n]
|
|
_, err := w.Write(buf)
|
|
return err
|
|
},
|
|
},
|
|
{
|
|
Name: "runtime.goroutineprofile.json",
|
|
WriteTo: func(w io.Writer) error {
|
|
p := make([]runtime.StackRecord, 1000)
|
|
n, ok := runtime.GoroutineProfile(p)
|
|
if !ok {
|
|
return errors.New("runtime.GoroutineProfile: not ok")
|
|
}
|
|
p = p[0:n]
|
|
e := json.NewEncoder(w)
|
|
e.SetIndent("", " ")
|
|
return e.Encode(p)
|
|
},
|
|
},
|
|
{
|
|
Name: "pprof.lookup.goroutine.debug0.pb.gz",
|
|
WriteTo: func(w io.Writer) error {
|
|
profile := pprof.Lookup("goroutine")
|
|
return profile.WriteTo(w, 0)
|
|
},
|
|
},
|
|
{
|
|
Name: "pprof.lookup.goroutine.debug1.txt",
|
|
WriteTo: func(w io.Writer) error {
|
|
profile := pprof.Lookup("goroutine")
|
|
return profile.WriteTo(w, 1)
|
|
},
|
|
},
|
|
{
|
|
Name: "pprof.lookup.goroutine.debug2.txt",
|
|
WriteTo: func(w io.Writer) error {
|
|
profile := pprof.Lookup("goroutine")
|
|
return profile.WriteTo(w, 2)
|
|
},
|
|
},
|
|
{
|
|
Name: "net.http.pprof.goroutine.debug0.pb.gz",
|
|
WriteTo: func(w io.Writer) error {
|
|
return writeHttpProfile(w, 0)
|
|
},
|
|
},
|
|
{
|
|
Name: "net.http.pprof.goroutine.debug1.txt",
|
|
WriteTo: func(w io.Writer) error {
|
|
return writeHttpProfile(w, 1)
|
|
},
|
|
},
|
|
{
|
|
Name: "net.http.pprof.goroutine.debug2.txt",
|
|
WriteTo: func(w io.Writer) error {
|
|
return writeHttpProfile(w, 2)
|
|
},
|
|
},
|
|
}
|
|
|
|
func writeHttpProfile(w io.Writer, debug int) error {
|
|
url := fmt.Sprintf("http://%s/debug/pprof/goroutine?debug=%d", listenAddr, debug)
|
|
res, err := http.Get(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
_, err = io.Copy(w, res.Body)
|
|
return err
|
|
}
|
|
|
|
func writeProfiles(n int) error {
|
|
for _, profile := range profiles {
|
|
buf := &bytes.Buffer{}
|
|
filename := fmt.Sprintf("%d.%s", n, profile.Name)
|
|
if err := profile.WriteTo(buf); err != nil {
|
|
return err
|
|
} else if err := ioutil.WriteFile(filename, buf.Bytes(), 0666); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var listenAddr = "127.0.0.1:8080"
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
fmt.Printf("Listening for pprof requests on %s\n", listenAddr)
|
|
errCh <- http.ListenAndServe(listenAddr, nil)
|
|
}()
|
|
|
|
labels := pprof.Labels("test_label", "test_value")
|
|
ctx := pprof.WithLabels(context.Background(), labels)
|
|
pprof.SetGoroutineLabels(ctx)
|
|
|
|
go shortSleepLoop()
|
|
go sleepLoop(time.Hour)
|
|
go chanReceiveForever()
|
|
go indirectShortSleepLoop()
|
|
|
|
sleep := time.Second
|
|
fmt.Printf("Sleeping for %s followed by gc\n", sleep)
|
|
|
|
time.Sleep(time.Second)
|
|
runtime.GC()
|
|
|
|
fmt.Printf("Dump 1\n")
|
|
if err := writeProfiles(1); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
sleep = 1*time.Minute + 10*time.Second
|
|
fmt.Printf("Sleeping for %s followed by gc\n", sleep)
|
|
time.Sleep(sleep)
|
|
runtime.GC()
|
|
|
|
fmt.Printf("Dump 2\n")
|
|
if err := writeProfiles(2); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Printf("Waiting forever\n")
|
|
|
|
//fmt.Printf("waiting indefinitely so you can press ctrl+\\ to compare the output\n")
|
|
//runtime.GC()
|
|
<-errCh
|
|
}
|
|
|
|
func shortSleepLoop() {
|
|
for {
|
|
time.Sleep(time.Second)
|
|
}
|
|
}
|
|
|
|
func sleepLoop(d time.Duration) {
|
|
for {
|
|
time.Sleep(d)
|
|
}
|
|
}
|
|
|
|
func chanReceiveForever() {
|
|
forever := make(chan struct{})
|
|
<-forever
|
|
}
|
|
|
|
func indirectShortSleepLoop() {
|
|
indirectShortSleepLoop2()
|
|
}
|
|
|
|
func indirectShortSleepLoop2() {
|
|
go shortSleepLoop()
|
|
}
|