]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/runtime/mprof.go
runtime: improve tickspersecond
[gostls13.git] / src / runtime / mprof.go
index 4134a961d6aaf2117898399ea8adb023cb6b4dca..ef485a3cfcdfb9d4ccbd28a038b481e8028eea81 100644 (file)
@@ -39,7 +39,10 @@ const (
        // size of bucket hash table
        buckHashSize = 179999
 
-       // max depth of stack to record in bucket
+       // maxStack is the max depth of stack to record in bucket.
+       // Note that it's only used internally as a guard against
+       // wildly out-of-bounds slicing of the PCs that come after
+       // a bucket struct, and it could increase in the future.
        maxStack = 32
 )
 
@@ -468,7 +471,7 @@ func SetBlockProfileRate(rate int) {
                r = 1 // profile everything
        } else {
                // convert ns to cycles, use float64 to prevent overflow during multiplication
-               r = int64(float64(rate) * float64(tickspersecond()) / (1000 * 1000 * 1000))
+               r = int64(float64(rate) * float64(ticksPerSecond()) / (1000 * 1000 * 1000))
                if r == 0 {
                        r = 1
                }
@@ -510,10 +513,18 @@ func saveblockevent(cycles, rate int64, skip int, which bucketType) {
        bp := b.bp()
 
        lock(&profBlockLock)
+       // We want to up-scale the count and cycles according to the
+       // probability that the event was sampled. For block profile events,
+       // the sample probability is 1 if cycles >= rate, and cycles / rate
+       // otherwise. For mutex profile events, the sample probability is 1 / rate.
+       // We scale the events by 1 / (probability the event was sampled).
        if which == blockProfile && cycles < rate {
                // Remove sampling bias, see discussion on http://golang.org/cl/299991.
                bp.count += float64(rate) / float64(cycles)
                bp.cycles += rate
+       } else if which == mutexProfile {
+               bp.count += float64(rate)
+               bp.cycles += rate * cycles
        } else {
                bp.count++
                bp.cycles += cycles
@@ -545,8 +556,6 @@ func mutexevent(cycles int64, skip int) {
                cycles = 0
        }
        rate := int64(atomic.Load64(&mutexprofilerate))
-       // TODO(pjw): measure impact of always calling fastrand vs using something
-       // like malloc.go:nextSample()
        if rate > 0 && int64(fastrand())%rate == 0 {
                saveblockevent(cycles, rate, skip+1, mutexProfile)
        }
@@ -783,7 +792,7 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
 // If len(p) >= n, MutexProfile copies the profile into p and returns n, true.
 // Otherwise, MutexProfile does not change p, and returns n, false.
 //
-// Most clients should use the runtime/pprof package
+// Most clients should use the [runtime/pprof] package
 // instead of calling MutexProfile directly.
 func MutexProfile(p []BlockProfileRecord) (n int, ok bool) {
        lock(&profBlockLock)
@@ -836,18 +845,13 @@ func runtime_goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer
        return goroutineProfileWithLabels(p, labels)
 }
 
-const go119ConcurrentGoroutineProfile = true
-
 // labels may be nil. If labels is non-nil, it must have the same length as p.
 func goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) {
        if labels != nil && len(labels) != len(p) {
                labels = nil
        }
 
-       if go119ConcurrentGoroutineProfile {
-               return goroutineProfileWithLabelsConcurrent(p, labels)
-       }
-       return goroutineProfileWithLabelsSync(p, labels)
+       return goroutineProfileWithLabelsConcurrent(p, labels)
 }
 
 var goroutineProfile = struct {
@@ -898,7 +902,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point
 
        ourg := getg()
 
-       stopTheWorld("profile")
+       stopTheWorld(stwGoroutineProfile)
        // Using gcount while the world is stopped should give us a consistent view
        // of the number of live goroutines, minus the number of goroutines that are
        // alive and permanently marked as "system". But to make this count agree
@@ -926,6 +930,9 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point
        systemstack(func() {
                saveg(pc, sp, ourg, &p[0])
        })
+       if labels != nil {
+               labels[0] = ourg.labels
+       }
        ourg.goroutineProfiled.Store(goroutineProfileSatisfied)
        goroutineProfile.offset.Store(1)
 
@@ -963,7 +970,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point
                tryRecordGoroutineProfile(gp1, Gosched)
        })
 
-       stopTheWorld("profile cleanup")
+       stopTheWorld(stwGoroutineProfileCleanup)
        endOffset := goroutineProfile.offset.Swap(0)
        goroutineProfile.active = false
        goroutineProfile.records = nil
@@ -1098,7 +1105,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n
                return gp1 != gp && readgstatus(gp1) != _Gdead && !isSystemGoroutine(gp1, false)
        }
 
-       stopTheWorld("profile")
+       stopTheWorld(stwGoroutineProfile)
 
        // World is stopped, no locking required.
        n = 1
@@ -1162,7 +1169,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n
 // If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
 // If len(p) < n, GoroutineProfile does not change p and returns n, false.
 //
-// Most clients should use the runtime/pprof package instead
+// Most clients should use the [runtime/pprof] package instead
 // of calling GoroutineProfile directly.
 func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 
@@ -1170,7 +1177,9 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 }
 
 func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
-       n := gentraceback(pc, sp, 0, gp, 0, &r.Stack0[0], len(r.Stack0), nil, nil, 0)
+       var u unwinder
+       u.initAt(pc, sp, 0, gp, unwindSilentErrors)
+       n := tracebackPCs(&u, 0, r.Stack0[:])
        if n < len(r.Stack0) {
                r.Stack0[n] = 0
        }
@@ -1182,7 +1191,7 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
 // into buf after the trace for the current goroutine.
 func Stack(buf []byte, all bool) int {
        if all {
-               stopTheWorld("stack trace")
+               stopTheWorld(stwAllGoroutinesStack)
        }
 
        n := 0
@@ -1225,7 +1234,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
        if typ == nil {
                print("tracealloc(", p, ", ", hex(size), ")\n")
        } else {
-               print("tracealloc(", p, ", ", hex(size), ", ", typ.string(), ")\n")
+               print("tracealloc(", p, ", ", hex(size), ", ", toRType(typ).string(), ")\n")
        }
        if gp.m.curg == nil || gp == gp.m.curg {
                goroutineheader(gp)