| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- // Package sync is an extension of the stdlib "sync" package. It has extra
- // functionality that helps debug the use of synchronization primitives. The
- // package should be importable in place of "sync". The extra functionality
- // can be enabled by calling Enable() or passing a non-empty PPROF_SYNC
- // environment variable to the process.
- //
- // Several profiles are exposed on the default HTTP muxer (and to
- // "/debug/pprof" when "net/http/pprof" is imported by the process).
- // "lockHolders" lists the stack traces of goroutines that called Mutex.Lock
- // that haven't subsequently been Unlocked. "lockBlockers" contains goroutines
- // that are waiting to obtain locks. "/debug/lockTimes" or PrintLockTimes()
- // shows the longest time a lock is held for each stack trace.
- //
- // Note that currently RWMutex is treated like a Mutex when the package is
- // enabled.
- package sync
- import (
- "fmt"
- "io"
- "net/http"
- "os"
- "runtime/pprof"
- "strings"
- "sync"
- "text/tabwriter"
- "github.com/anacrolix/missinggo"
- )
- var (
- // Protects initialization and enabling of the package.
- enableMu sync.Mutex
- // Whether shared locks must be handled as exclusive locks.
- noSharedLocking = false
- contentionOn = false
- lockTimesOn = false
- // Current lock holders.
- lockHolders *pprof.Profile
- // Those blocked on acquiring a lock.
- lockBlockers *pprof.Profile
- )
- // Writes out the longest time a Mutex remains locked for each stack trace
- // that locks a Mutex.
- func PrintLockTimes(w io.Writer) {
- lockTimes := sortedLockTimes()
- tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
- defer tw.Flush()
- w = tw
- for _, elem := range lockTimes {
- fmt.Fprintf(w, "%s (%s * %d [%s, %s])\n", elem.Total, elem.MeanTime(), elem.Count, elem.Min, elem.Max)
- missinggo.WriteStack(w, elem.stack[:])
- }
- }
- func Enable() {
- EnableContention()
- EnableLockTimes()
- }
- func EnableContention() {
- lockHolders = pprof.NewProfile("lockHolders")
- lockBlockers = pprof.NewProfile("lockBlockers")
- noSharedLocking = true
- contentionOn = true
- }
- func EnableLockTimes() {
- lockStatsByStack = make(map[lockStackKey]lockStats)
- http.DefaultServeMux.HandleFunc("/debug/lockTimes", func(w http.ResponseWriter, r *http.Request) {
- PrintLockTimes(w)
- })
- noSharedLocking = true
- lockTimesOn = true
- }
- func init() {
- env := os.Getenv("PPROF_SYNC")
- all := true
- if strings.Contains(env, "times") {
- EnableLockTimes()
- all = false
- }
- if strings.Contains(env, "contention") {
- EnableContention()
- all = false
- }
- if all && env != "" {
- Enable()
- }
- }
|