var profInsertLock … var profBlockLock … var profMemActiveLock … var profMemFutureLock … const memProfile … const blockProfile … const mutexProfile … const buckHashSize … const maxSkip … const maxProfStackDepth … type bucketType … type bucket … type memRecord … type memRecordCycle … // add accumulates b into a. It does not zero b. func (a *memRecordCycle) add(b *memRecordCycle) { … } type blockRecord … var mbuckets … var bbuckets … var xbuckets … var buckhash … var mProfCycle … type buckhashArray … const mProfCycleWrap … type mProfCycleHolder … // read returns the current cycle count. func (c *mProfCycleHolder) read() (cycle uint32) { … } // setFlushed sets the flushed flag. It returns the current cycle count and the // previous value of the flushed flag. func (c *mProfCycleHolder) setFlushed() (cycle uint32, alreadyFlushed bool) { … } // increment increases the cycle count by one, wrapping the value at // mProfCycleWrap. It clears the flushed flag. func (c *mProfCycleHolder) increment() { … } // newBucket allocates a bucket with the given type and number of stack entries. func newBucket(typ bucketType, nstk int) *bucket { … } // stk returns the slice in b holding the stack. The caller can assume that the // backing array is immutable. func (b *bucket) stk() []uintptr { … } // mp returns the memRecord associated with the memProfile bucket b. func (b *bucket) mp() *memRecord { … } // bp returns the blockRecord associated with the blockProfile bucket b. func (b *bucket) bp() *blockRecord { … } // Return the bucket for stk[0:nstk], allocating new bucket if needed. func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket { … } func eqslice(x, y []uintptr) bool { … } // mProf_NextCycle publishes the next heap profile cycle and creates a // fresh heap profile cycle. This operation is fast and can be done // during STW. The caller must call mProf_Flush before calling // mProf_NextCycle again. // // This is called by mark termination during STW so allocations and // frees after the world is started again count towards a new heap // profiling cycle. func mProf_NextCycle() { … } // mProf_Flush flushes the events from the current heap profiling // cycle into the active profile. After this it is safe to start a new // heap profiling cycle with mProf_NextCycle. // // This is called by GC after mark termination starts the world. In // contrast with mProf_NextCycle, this is somewhat expensive, but safe // to do concurrently. func mProf_Flush() { … } // mProf_FlushLocked flushes the events from the heap profiling cycle at index // into the active profile. The caller must hold the lock for the active profile // (profMemActiveLock) and for the profiling cycle at index // (profMemFutureLock[index]). func mProf_FlushLocked(index uint32) { … } // mProf_PostSweep records that all sweep frees for this GC cycle have // completed. This has the effect of publishing the heap profile // snapshot as of the last mark termination without advancing the heap // profile cycle. func mProf_PostSweep() { … } // Called by malloc to record a profiled block. func mProf_Malloc(mp *m, p unsafe.Pointer, size uintptr) { … } // Called when freeing a profiled block. func mProf_Free(b *bucket, size uintptr) { … } var blockprofilerate … // SetBlockProfileRate controls the fraction of goroutine blocking events // that are reported in the blocking profile. The profiler aims to sample // an average of one blocking event per rate nanoseconds spent blocked. // // To include every blocking event in the profile, pass rate = 1. // To turn off profiling entirely, pass rate <= 0. func SetBlockProfileRate(rate int) { … } func blockevent(cycles int64, skip int) { … } // blocksampled returns true for all events where cycles >= rate. Shorter // events have a cycles/rate random chance of returning true. func blocksampled(cycles, rate int64) bool { … } // saveblockevent records a profile event of the type specified by which. // cycles is the quantity associated with this event and rate is the sampling rate, // used to adjust the cycles value in the manner determined by the profile type. // skip is the number of frames to omit from the traceback associated with the event. // The traceback will be recorded from the stack of the goroutine associated with the current m. // skip should be positive if this event is recorded from the current stack // (e.g. when this is not called from a system stack) func saveblockevent(cycles, rate int64, skip int, which bucketType) { … } // fpTracebackPartialExpand records a call stack obtained starting from fp. // This function will skip the given number of frames, properly accounting for // inlining, and save remaining frames as "physical" return addresses. The // consumer should later use CallersFrames or similar to expand inline frames. func fpTracebackPartialExpand(skip int, fp unsafe.Pointer, pcBuf []uintptr) int { … } type lockTimer … func (lt *lockTimer) begin() { … } func (lt *lockTimer) end() { … } type mLockProfile … func (prof *mLockProfile) recordLock(cycles int64, l *mutex) { … } // From unlock2, we might not be holding a p in this code. // //go:nowritebarrierrec func (prof *mLockProfile) recordUnlock(l *mutex) { … } func (prof *mLockProfile) captureStack() { … } func (prof *mLockProfile) store() { … } func saveBlockEventStack(cycles, rate int64, stk []uintptr, which bucketType) { … } var mutexprofilerate … // SetMutexProfileFraction controls the fraction of mutex contention events // that are reported in the mutex profile. On average 1/rate events are // reported. The previous rate is returned. // // To turn off profiling entirely, pass rate 0. // To just read the current rate, pass rate < 0. // (For n>1 the details of sampling may change.) func SetMutexProfileFraction(rate int) int { … } //go:linkname mutexevent sync.event func mutexevent(cycles int64, skip int) { … } type StackRecord … // Stack returns the stack trace associated with the record, // a prefix of r.Stack0. func (r *StackRecord) Stack() []uintptr { … } var MemProfileRate … var disableMemoryProfiling … type MemProfileRecord … // InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes). func (r *MemProfileRecord) InUseBytes() int64 { … } // InUseObjects returns the number of objects in use (AllocObjects - FreeObjects). func (r *MemProfileRecord) InUseObjects() int64 { … } // Stack returns the stack trace associated with the record, // a prefix of r.Stack0. func (r *MemProfileRecord) Stack() []uintptr { … } // MemProfile returns a profile of memory allocated and freed per allocation // site. // // MemProfile returns n, the number of records in the current memory profile. // If len(p) >= n, MemProfile copies the profile into p and returns n, true. // If len(p) < n, MemProfile does not change p and returns n, false. // // If inuseZero is true, the profile includes allocation records // where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes. // These are sites where memory was allocated, but it has all // been released back to the runtime. // // The returned profile may be up to two garbage collection cycles old. // This is to avoid skewing the profile toward allocations; because // allocations happen in real time but frees are delayed until the garbage // collector performs sweeping, the profile only accounts for allocations // that have had a chance to be freed by the garbage collector. // // Most clients should use the runtime/pprof package or // the testing package's -test.memprofile flag instead // of calling MemProfile directly. func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { … } // memProfileInternal returns the number of records n in the profile. If there // are less than size records, copyFn is invoked for each record, and ok returns // true. // // The linker set disableMemoryProfiling to true to disable memory profiling // if this function is not reachable. Mark it noinline to ensure the symbol exists. // (This function is big and normally not inlined anyway.) // See also disableMemoryProfiling above and cmd/link/internal/ld/lib.go:linksetup. // //go:noinline func memProfileInternal(size int, inuseZero bool, copyFn func(profilerecord.MemProfileRecord)) (n int, ok bool) { … } func copyMemProfileRecord(dst *MemProfileRecord, src profilerecord.MemProfileRecord) { … } //go:linkname pprof_memProfileInternal func pprof_memProfileInternal(p []profilerecord.MemProfileRecord, inuseZero bool) (n int, ok bool) { … } func iterate_memprof(fn func(*bucket, uintptr, *uintptr, uintptr, uintptr, uintptr)) { … } type BlockProfileRecord … // BlockProfile returns n, the number of records in the current blocking profile. // If len(p) >= n, BlockProfile copies the profile into p and returns n, true. // If len(p) < n, BlockProfile does not change p and returns n, false. // // Most clients should use the [runtime/pprof] package or // the [testing] package's -test.blockprofile flag instead // of calling BlockProfile directly. func BlockProfile(p []BlockProfileRecord) (n int, ok bool) { … } func expandFrames(p []BlockProfileRecord) { … } // blockProfileInternal returns the number of records n in the profile. If there // are less than size records, copyFn is invoked for each record, and ok returns // true. func blockProfileInternal(size int, copyFn func(profilerecord.BlockProfileRecord)) (n int, ok bool) { … } // copyBlockProfileRecord copies the sample values and call stack from src to dst. // The call stack is copied as-is. The caller is responsible for handling inline // expansion, needed when the call stack was collected with frame pointer unwinding. func copyBlockProfileRecord(dst *BlockProfileRecord, src profilerecord.BlockProfileRecord) { … } //go:linkname pprof_blockProfileInternal func pprof_blockProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) { … } // MutexProfile returns n, the number of records in the current mutex profile. // 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 // instead of calling MutexProfile directly. func MutexProfile(p []BlockProfileRecord) (n int, ok bool) { … } // mutexProfileInternal returns the number of records n in the profile. If there // are less than size records, copyFn is invoked for each record, and ok returns // true. func mutexProfileInternal(size int, copyFn func(profilerecord.BlockProfileRecord)) (n int, ok bool) { … } //go:linkname pprof_mutexProfileInternal func pprof_mutexProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) { … } // ThreadCreateProfile returns n, the number of records in the thread creation profile. // If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true. // If len(p) < n, ThreadCreateProfile does not change p and returns n, false. // // Most clients should use the runtime/pprof package instead // of calling ThreadCreateProfile directly. func ThreadCreateProfile(p []StackRecord) (n int, ok bool) { … } // threadCreateProfileInternal returns the number of records n in the profile. // If there are less than size records, copyFn is invoked for each record, and // ok returns true. func threadCreateProfileInternal(size int, copyFn func(profilerecord.StackRecord)) (n int, ok bool) { … } //go:linkname pprof_threadCreateInternal func pprof_threadCreateInternal(p []profilerecord.StackRecord) (n int, ok bool) { … } //go:linkname pprof_goroutineProfileWithLabels func pprof_goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { … } // labels may be nil. If labels is non-nil, it must have the same length as p. func goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { … } var goroutineProfile … type goroutineProfileState … const goroutineProfileAbsent … const goroutineProfileInProgress … const goroutineProfileSatisfied … type goroutineProfileStateHolder … func (p *goroutineProfileStateHolder) Load() goroutineProfileState { … } func (p *goroutineProfileStateHolder) Store(value goroutineProfileState) { … } func (p *goroutineProfileStateHolder) CompareAndSwap(old, new goroutineProfileState) bool { … } func goroutineProfileWithLabelsConcurrent(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { … } // tryRecordGoroutineProfileWB asserts that write barriers are allowed and calls // tryRecordGoroutineProfile. // //go:yeswritebarrierrec func tryRecordGoroutineProfileWB(gp1 *g) { … } // tryRecordGoroutineProfile ensures that gp1 has the appropriate representation // in the current goroutine profile: either that it should not be profiled, or // that a snapshot of its call stack and labels are now in the profile. func tryRecordGoroutineProfile(gp1 *g, pcbuf []uintptr, yield func()) { … } // doRecordGoroutineProfile writes gp1's call stack and labels to an in-progress // goroutine profile. Preemption is disabled. // // This may be called via tryRecordGoroutineProfile in two ways: by the // goroutine that is coordinating the goroutine profile (running on its own // stack), or from the scheduler in preparation to execute gp1 (running on the // system stack). func doRecordGoroutineProfile(gp1 *g, pcbuf []uintptr) { … } func goroutineProfileWithLabelsSync(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { … } // GoroutineProfile returns n, the number of records in the active goroutine stack profile. // 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 // of calling GoroutineProfile directly. func GoroutineProfile(p []StackRecord) (n int, ok bool) { … } func goroutineProfileInternal(p []profilerecord.StackRecord) (n int, ok bool) { … } func saveg(pc, sp uintptr, gp *g, r *profilerecord.StackRecord, pcbuf []uintptr) { … } // Stack formats a stack trace of the calling goroutine into buf // and returns the number of bytes written to buf. // If all is true, Stack formats stack traces of all other goroutines // into buf after the trace for the current goroutine. func Stack(buf []byte, all bool) int { … }