diff --git a/examples/stuck-deadlock/go.mod b/examples/stuck-deadlock/go.mod index 36dcc3b..78b4987 100644 --- a/examples/stuck-deadlock/go.mod +++ b/examples/stuck-deadlock/go.mod @@ -1,3 +1,12 @@ module github.com/felixge/go-profiler-notes/examples/stuck-program go 1.15 + +require ( + github.com/DataDog/datadog-go v4.4.0+incompatible // indirect + github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/google/uuid v1.2.0 // indirect + gopkg.in/DataDog/dd-trace-go.v1 v1.28.0 +) + +replace gopkg.in/DataDog/dd-trace-go.v1 => /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go diff --git a/examples/stuck-deadlock/go.sum b/examples/stuck-deadlock/go.sum new file mode 100644 index 0000000..c91cf31 --- /dev/null +++ b/examples/stuck-deadlock/go.sum @@ -0,0 +1,31 @@ +github.com/DataDog/datadog-go v4.4.0+incompatible h1:R7WqXWP4fIOAqWJtUKmSfuc7eDsBT58k9AY5WSHVosk= +github.com/DataDog/datadog-go v4.4.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/pprof v0.0.0-20210125172800-10e9aeb4a998 h1:ruQkWz0PK91vTVrWtzAgv3VqTMgIN1FAIvwWr5MY+GQ= +github.com/google/pprof v0.0.0-20210125172800-10e9aeb4a998/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/DataDog/dd-trace-go.v1 v1.28.0 h1:EmglUJuykRsTwsQDcKaAo3CmOunWU6Dqk7U2lo7Pjss= +gopkg.in/DataDog/dd-trace-go.v1 v1.28.0/go.mod h1:Sp1lku8WJMvNV0kjDI4Ni/T7J/U3BO5ct5kEaoVU8+I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/stuck-deadlock/main.go b/examples/stuck-deadlock/main.go index 3a22c79..317f316 100644 --- a/examples/stuck-deadlock/main.go +++ b/examples/stuck-deadlock/main.go @@ -4,7 +4,11 @@ import ( "fmt" "os" "os/signal" + "runtime" "sync" + "time" + + "gopkg.in/DataDog/dd-trace-go.v1/profiler" ) func main() { @@ -14,6 +18,19 @@ func main() { } } func run() error { + if err := os.Setenv("DD_PROFILING_WAIT_PROFILE", "yes"); err != nil { + return err + } else if err := profiler.Start( + profiler.WithService("stuck-deadlock"), + profiler.WithVersion(time.Now().String()), + profiler.WithPeriod(60*time.Second), + profiler.WithProfileTypes( + profiler.GoroutineProfile, + ), + ); err != nil { + return err + } + var ( a = &sync.Mutex{} b = &sync.Mutex{} @@ -23,7 +40,19 @@ func run() error { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) - <-c + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + // force gc on a regular basis to make sure g.waitsince gets populated. + fmt.Printf("gc\n") + runtime.GC() + case sig := <-c: + fmt.Printf("sig: %s\n", sig) + return nil + } + } return nil } @@ -32,6 +61,7 @@ func bob(a, b *sync.Mutex) { fmt.Println("bob is okay") a.Lock() b.Lock() + // do stuff a.Unlock() b.Unlock() } @@ -42,6 +72,7 @@ func alice(a, b *sync.Mutex) { fmt.Println("alice is okay") b.Lock() a.Lock() + // do stuff b.Unlock() a.Unlock() } diff --git a/examples/stuck-producer-consumer/go.mod b/examples/stuck-producer-consumer/go.mod new file mode 100644 index 0000000..39f1960 --- /dev/null +++ b/examples/stuck-producer-consumer/go.mod @@ -0,0 +1,12 @@ +module github.com/felixge/go-profiler-notes/examples/stuck-producer-consumer + +go 1.15 + +require ( + github.com/DataDog/datadog-go v4.4.0+incompatible // indirect + github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/google/uuid v1.2.0 // indirect + gopkg.in/DataDog/dd-trace-go.v1 v1.29.0-alpha.1.0.20210216140755-2d091eca40bb +) + +replace gopkg.in/DataDog/dd-trace-go.v1 => /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go diff --git a/examples/stuck-producer-consumer/go.sum b/examples/stuck-producer-consumer/go.sum new file mode 100644 index 0000000..f57d0b9 --- /dev/null +++ b/examples/stuck-producer-consumer/go.sum @@ -0,0 +1,34 @@ +github.com/DataDog/datadog-go v4.4.0+incompatible h1:R7WqXWP4fIOAqWJtUKmSfuc7eDsBT58k9AY5WSHVosk= +github.com/DataDog/datadog-go v4.4.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/pprof v0.0.0-20210125172800-10e9aeb4a998 h1:ruQkWz0PK91vTVrWtzAgv3VqTMgIN1FAIvwWr5MY+GQ= +github.com/google/pprof v0.0.0-20210125172800-10e9aeb4a998/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/DataDog/dd-trace-go.v1 v1.28.0 h1:EmglUJuykRsTwsQDcKaAo3CmOunWU6Dqk7U2lo7Pjss= +gopkg.in/DataDog/dd-trace-go.v1 v1.28.0/go.mod h1:Sp1lku8WJMvNV0kjDI4Ni/T7J/U3BO5ct5kEaoVU8+I= +gopkg.in/DataDog/dd-trace-go.v1 v1.29.0-alpha.1.0.20210216140755-2d091eca40bb h1:BQMy4tHVzHLWsGeQMmYrgWbHkVPp0ibHM/IDREdchyk= +gopkg.in/DataDog/dd-trace-go.v1 v1.29.0-alpha.1.0.20210216140755-2d091eca40bb/go.mod h1:FLwUDeuH0z5hkvgvd04/M3MHQN4AF5pQDnedeWRWvok= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/stuck-producer-consumer/main.go b/examples/stuck-producer-consumer/main.go new file mode 100644 index 0000000..30868f1 --- /dev/null +++ b/examples/stuck-producer-consumer/main.go @@ -0,0 +1,83 @@ +package main + +import ( + "fmt" + "math/rand" + "os" + "os/signal" + "runtime" + "time" + + "gopkg.in/DataDog/dd-trace-go.v1/profiler" +) + +func main() { + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func run() error { + if err := os.Setenv("DD_PROFILING_WAIT_PROFILE", "yes"); err != nil { + return err + } else if err := profiler.Start( + profiler.WithService("stuck-producer-consumer"), + profiler.WithVersion(time.Now().String()), + profiler.WithPeriod(60*time.Second), + profiler.WithProfileTypes( + profiler.GoroutineProfile, + ), + ); err != nil { + return err + } + + rand.Seed(time.Now().UnixNano()) + + workCh := make(chan struct{}) + go consumer(workCh) + go producer(workCh) + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + // force gc on a regular basis to make sure g.waitsince gets populated. + fmt.Printf("gc\n") + runtime.GC() + case sig := <-c: + fmt.Printf("sig: %s\n", sig) + return nil + } + } +} + +func producer(workCh chan<- struct{}) { + for { + select { + case workCh <- struct{}{}: + if rand.Int63n(10) == 0 { + takeNap() + } + default: + } + } +} + +func consumer(workCh <-chan struct{}) { + for { + <-workCh + if rand.Int63n(10) == 0 { + takeNap() + } + } +} + +func takeNap() { + fmt.Printf("taking a nap\n") + var forever chan struct{} + <-forever +} diff --git a/examples/stuck-producer-worker/go.mod b/examples/stuck-producer-worker/go.mod deleted file mode 100644 index 36dcc3b..0000000 --- a/examples/stuck-producer-worker/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/felixge/go-profiler-notes/examples/stuck-program - -go 1.15 diff --git a/examples/stuck-producer-worker/main.go b/examples/stuck-producer-worker/main.go deleted file mode 100644 index fe07396..0000000 --- a/examples/stuck-producer-worker/main.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "fmt" - "math/rand" - "os" - "os/signal" - "time" -) - -func main() { - if err := run(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func run() error { - rand.Seed(time.Now().UnixNano()) - - workCh := make(chan int) - go worker(workCh) - go producer(workCh) - - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) - <-c - return nil -} - -func producer(workCh chan<- int) { - for msg := 0; ; msg++ { - workCh <- msg - fmt.Printf("producer sent: %d\n", msg) - if rand.Int63n(10) == 0 { - takeNap() - } - } -} - -func worker(workCh <-chan int) { - for { - msg := <-workCh - fmt.Printf("worker received: %d\n", msg) - if rand.Int63n(10) == 0 { - takeNap() - } - } -} - -func takeNap() { - var forever chan struct{} - <-forever -}