Skip to content

Commit

Permalink
Adding new debugging methods (#338)
Browse files Browse the repository at this point in the history
* Adding new debugging methods

* CR fix

* Adding a method debug_stacks

* CR fix

* cr fix

* cr fix

* Gossip msg size -> 32 MB

* Format go.mod

* CR fix

* CR fix

* Rename the CPUProfile and optimize lowering first case function

* Rename and add comment

* Suppress stylecheck linter

* CR fix

---------

Co-authored-by: Oliver Bundalo <[email protected]>
Co-authored-by: Stefan Negovanović <[email protected]>
  • Loading branch information
3 people authored Aug 29, 2024
1 parent 9e2fed9 commit aae6a34
Show file tree
Hide file tree
Showing 8 changed files with 540 additions and 11 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
max_enqueued: "20000000"
is_london_fork_active: true
is_bridge_active: false
gossip_msg_size: "16777216"
gossip_msg_size: "33554432"
notification: false
secrets:
AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }}
Expand Down Expand Up @@ -168,7 +168,7 @@ jobs:
max_enqueued: "20000000"
is_london_fork_active: true
is_bridge_active: false
gossip_msg_size: "16777216"
gossip_msg_size: "33554432"
logs: true
build_blade_output: ${{ needs.ci.outputs.build_blade }}
lint_output: ${{ needs.ci.outputs.lint }}
Expand Down
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ require (
github.com/golang/protobuf v1.5.4
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3
github.com/hashicorp/go-bexpr v0.1.14
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-immutable-radix v1.3.1
github.com/hashicorp/go-multierror v1.1.1
Expand Down Expand Up @@ -72,11 +73,9 @@ require (
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20240503222823-736c933a666d // indirect
github.com/mitchellh/pointerstructure v1.2.1 // indirect
github.com/tjfoc/gmsm v1.3.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)

require (
cloud.google.com/go/auth v0.7.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-bexpr v0.1.14 h1:uKDeyuOhWhT1r5CiMTjdVY4Aoxdxs6EtwgTGnlosyp4=
github.com/hashicorp/go-bexpr v0.1.14/go.mod h1:gN7hRKB3s7yT+YvTdnhZVLTENejvhlkZ8UE4YVBS+Q8=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
Expand Down Expand Up @@ -512,6 +514,8 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI=
Expand Down
283 changes: 282 additions & 1 deletion jsonrpc/debug_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"runtime/debug"
"time"

"github.com/0xPolygon/polygon-edge/helper/hex"
Expand All @@ -14,7 +17,12 @@ import (
"github.com/0xPolygon/polygon-edge/types"
)

const callTracerName = "callTracer"
const (
callTracerName = "callTracer"
blockString = "block"
mutexString = "mutex"
heapString = "heap"
)

var (
defaultTraceTimeout = 5 * time.Second
Expand Down Expand Up @@ -77,17 +85,290 @@ type debugStore interface {
type Debug struct {
store debugStore
throttling *Throttling
handler *DebugHandler
ReadFileFunc func(filename string) ([]byte, error)
}

func NewDebug(store debugStore, requestsPerSecond uint64) *Debug {
return &Debug{
store: store,
throttling: NewThrottling(requestsPerSecond, time.Second),
handler: new(DebugHandler),
ReadFileFunc: os.ReadFile,
}
}

// CpuProfile turns on CPU profiling for nsec seconds and writes
// profile data to file.
//
//nolint:stylecheck
func (d *Debug) CpuProfile(file string, nsec int64) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
if err := d.handler.StartCPUProfile(file); err != nil {
return nil, err
}

time.Sleep(time.Duration(nsec) * time.Second)

if err := d.handler.StopCPUProfile(); err != nil {
return nil, err
}

absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, nil
},
)
}

// FreeOSMemory forces a garbage collection.
func (d *Debug) FreeOSMemory() (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
debug.FreeOSMemory()

return nil, nil
},
)
}

// GcStats returns GC statistics.
func (d *Debug) GcStats() (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
s := new(debug.GCStats)
debug.ReadGCStats(s)

return s, nil
},
)
}

// MemStats returns detailed runtime memory statistics.
func (d *Debug) MemStats() (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
s := new(runtime.MemStats)
runtime.ReadMemStats(s)

return s, nil
},
)
}

// MutexProfile turns on mutex profiling for nsec seconds and writes profile data to file.
// It uses a profile rate of 1 for most accurate information. If a different rate is
// desired, set the rate and write the profile manually.
func (d *Debug) MutexProfile(file string, nsec int64) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
runtime.SetMutexProfileFraction(1)
time.Sleep(time.Duration(nsec) * time.Second)
defer runtime.SetMutexProfileFraction(0)

absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, writeProfile(mutexString, file)
},
)
}

// BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to
// file. It uses a profile rate of 1 for most accurate information. If a different rate is
// desired, set the rate and write the profile manually.
func (d *Debug) BlockProfile(file string, nsec int64) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
runtime.SetBlockProfileRate(1)
time.Sleep(time.Duration(nsec) * time.Second)

defer runtime.SetBlockProfileRate(0)

absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, writeProfile(blockString, file)
},
)
}

// SetBlockProfileRate sets the rate of goroutine block profile data collection.
// rate 0 disables block profiling.
func (d *Debug) SetBlockProfileRate(rate int) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
runtime.SetBlockProfileRate(rate)

return nil, nil
},
)
}

// SetGCPercent sets the garbage collection target percentage. It returns the previous
// setting. A negative value disables GC.
func (d *Debug) SetGCPercent(v int) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
return debug.SetGCPercent(v), nil
},
)
}

// SetMutexProfileFraction sets the rate of mutex profiling.
func (d *Debug) SetMutexProfileFraction(rate int) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
runtime.SetMutexProfileFraction(rate)

return nil, nil
},
)
}

// StartCPUProfile turns on CPU profiling, writing to the given file.
func (d *Debug) StartCPUProfile(file string) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
if err := d.handler.StartCPUProfile(file); err != nil {
return nil, err
}

absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, nil
},
)
}

// StartGoTrace turns on tracing, writing to the given file.
func (d *Debug) StartGoTrace(file string) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
if err := d.handler.StartGoTrace(file); err != nil {
return nil, err
}

absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, nil
},
)
}

// StopCPUProfile stops an ongoing CPU profile.
func (d *Debug) StopCPUProfile() (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
if err := d.handler.StopCPUProfile(); err != nil {
return nil, err
}

return nil, nil
},
)
}

// StopGoTrace stops an ongoing trace.
func (d *Debug) StopGoTrace() (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
if err := d.handler.StopGoTrace(); err != nil {
return nil, err
}

return nil, nil
},
)
}

// WriteBlockProfile writes a goroutine blocking profile to the given file.
func (d *Debug) WriteBlockProfile(file string) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, writeProfile(blockString, file)
},
)
}

// WriteMemProfile writes an allocation profile to the given file.
// Note that the profiling rate cannot be set through the API,
// it must be set on the command line.
// WriteBlockProfile writes a goroutine blocking profile to the given file.
func (d *Debug) WriteMemProfile(file string) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, writeProfile(heapString, file)
},
)
}

// WriteMutexProfile writes a goroutine blocking profile to the given file.
func (d *Debug) WriteMutexProfile(file string) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
absPath, err := filepath.Abs(file)
if err != nil {
absPath = file
}

return absPath, writeProfile(mutexString, file)
},
)
}

// Stacks returns a printed representation of the stacks of all goroutines. It
// also permits the following optional filters to be used:
// - filter: boolean expression of packages to filter for
func (d *Debug) Stacks(filter *string) (interface{}, error) {
return d.throttling.AttemptRequest(
context.Background(),
func() (interface{}, error) {
return d.handler.Stacks(filter)
},
)
}

type TraceConfig struct {
EnableMemory bool `json:"enableMemory"`
DisableStack bool `json:"disableStack"`
Expand Down
Loading

0 comments on commit aae6a34

Please sign in to comment.