Source file src/runtime/debug.go
1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 import ( 8 "internal/runtime/atomic" 9 "unsafe" 10 ) 11 12 // GOMAXPROCS sets the maximum number of CPUs that can be executing 13 // simultaneously and returns the previous setting. If n < 1, it does not change 14 // the current setting. 15 // 16 // # Default 17 // 18 // If the GOMAXPROCS environment variable is set to a positive whole number, 19 // GOMAXPROCS defaults to that value. 20 // 21 // Otherwise, the Go runtime selects an appropriate default value from a combination of 22 // - the number of logical CPUs on the machine, 23 // - the process’s CPU affinity mask, 24 // - and, on Linux, the process’s average CPU throughput limit based on cgroup CPU 25 // quota, if any. 26 // 27 // If GODEBUG=containermaxprocs=0 is set and GOMAXPROCS is not set by the 28 // environment variable, then GOMAXPROCS instead defaults to the value of 29 // [runtime.NumCPU]. Note that GODEBUG=containermaxprocs=0 is [default] for 30 // language version 1.24 and below. 31 // 32 // # Updates 33 // 34 // The Go runtime periodically updates the default value based on changes to 35 // the total logical CPU count, the CPU affinity mask, or cgroup quota. Setting 36 // a custom value with the GOMAXPROCS environment variable or by calling 37 // GOMAXPROCS disables automatic updates. The default value and automatic 38 // updates can be restored by calling [SetDefaultGOMAXPROCS]. 39 // 40 // If GODEBUG=updatemaxprocs=0 is set, the Go runtime does not perform 41 // automatic GOMAXPROCS updating. Note that GODEBUG=updatemaxprocs=0 is 42 // [default] for language version 1.24 and below. 43 // 44 // # Compatibility 45 // 46 // Note that the default GOMAXPROCS behavior may change as the scheduler 47 // improves, especially the implementation detail below. 48 // 49 // # Implementation details 50 // 51 // When computing default GOMAXPROCS via cgroups, the Go runtime computes the 52 // "average CPU throughput limit" as the cgroup CPU quota / period. In cgroup 53 // v2, these values come from the cpu.max file. In cgroup v1, they come from 54 // cpu.cfs_quota_us and cpu.cfs_period_us, respectively. In container runtimes 55 // that allow configuring CPU limits, this value usually corresponds to the 56 // "CPU limit" option, not "CPU request". 57 // 58 // The Go runtime typically selects the default GOMAXPROCS as the minimum of 59 // the logical CPU count, the CPU affinity mask count, or the cgroup CPU 60 // throughput limit. However, it will never set GOMAXPROCS less than 2 unless 61 // the logical CPU count or CPU affinity mask count are below 2. 62 // 63 // If the cgroup CPU throughput limit is not a whole number, the Go runtime 64 // rounds up to the next whole number. 65 // 66 // GOMAXPROCS updates are performed up to once per second, or less if the 67 // application is idle. 68 // 69 // [default]: https://go.dev/doc/godebug#default 70 func GOMAXPROCS(n int) int { 71 if GOARCH == "wasm" && n > 1 { 72 n = 1 // WebAssembly has no threads yet, so only one CPU is possible. 73 } 74 75 lock(&sched.lock) 76 ret := int(gomaxprocs) 77 if n <= 0 { 78 unlock(&sched.lock) 79 return ret 80 } 81 // Set early so we can wait for sysmon befor STW. See comment on 82 // computeMaxProcsLock. 83 sched.customGOMAXPROCS = true 84 unlock(&sched.lock) 85 86 // Wait for sysmon to complete running defaultGOMAXPROCS. 87 lock(&computeMaxProcsLock) 88 unlock(&computeMaxProcsLock) 89 90 if n == ret { 91 // sched.customGOMAXPROCS set, but no need to actually STW 92 // since the gomaxprocs itself isn't changing. 93 return ret 94 } 95 96 stw := stopTheWorldGC(stwGOMAXPROCS) 97 98 // newprocs will be processed by startTheWorld 99 // 100 // TODO(prattmic): this could use a nicer API. Perhaps add it to the 101 // stw parameter? 102 newprocs = int32(n) 103 104 startTheWorldGC(stw) 105 return ret 106 } 107 108 // SetDefaultGOMAXPROCS updates the GOMAXPROCS setting to the runtime 109 // default, as described by [GOMAXPROCS], ignoring the GOMAXPROCS 110 // environment variable. 111 // 112 // SetDefaultGOMAXPROCS can be used to enable the default automatic updating 113 // GOMAXPROCS behavior if it has been disabled by the GOMAXPROCS 114 // environment variable or a prior call to [GOMAXPROCS], or to force an immediate 115 // update if the caller is aware of a change to the total logical CPU count, CPU 116 // affinity mask or cgroup quota. 117 func SetDefaultGOMAXPROCS() { 118 // SetDefaultGOMAXPROCS conceptually means "[re]do what the runtime 119 // would do at startup if the GOMAXPROCS environment variable were 120 // unset." It still respects GODEBUG. 121 122 procs := defaultGOMAXPROCS(0) 123 124 lock(&sched.lock) 125 curr := gomaxprocs 126 custom := sched.customGOMAXPROCS 127 unlock(&sched.lock) 128 129 if !custom && procs == curr { 130 // Nothing to do if we're already using automatic GOMAXPROCS 131 // and the limit is unchanged. 132 return 133 } 134 135 stw := stopTheWorldGC(stwGOMAXPROCS) 136 137 // newprocs will be processed by startTheWorld 138 // 139 // TODO(prattmic): this could use a nicer API. Perhaps add it to the 140 // stw parameter? 141 newprocs = procs 142 lock(&sched.lock) 143 sched.customGOMAXPROCS = false 144 unlock(&sched.lock) 145 146 startTheWorldGC(stw) 147 } 148 149 // NumCPU returns the number of logical CPUs usable by the current process. 150 // 151 // The set of available CPUs is checked by querying the operating system 152 // at process startup. Changes to operating system CPU allocation after 153 // process startup are not reflected. 154 func NumCPU() int { 155 return int(numCPUStartup) 156 } 157 158 // NumCgoCall returns the number of cgo calls made by the current process. 159 func NumCgoCall() int64 { 160 var n = int64(atomic.Load64(&ncgocall)) 161 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { 162 n += int64(mp.ncgocall) 163 } 164 return n 165 } 166 167 func totalMutexWaitTimeNanos() int64 { 168 total := sched.totalMutexWaitTime.Load() 169 170 total += sched.totalRuntimeLockWaitTime.Load() 171 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { 172 total += mp.mLockProfile.waitTime.Load() 173 } 174 175 return total 176 } 177 178 // NumGoroutine returns the number of goroutines that currently exist. 179 func NumGoroutine() int { 180 return int(gcount()) 181 } 182 183 //go:linkname debug_modinfo runtime/debug.modinfo 184 func debug_modinfo() string { 185 return modinfo 186 } 187 188 // mayMoreStackPreempt is a maymorestack hook that forces a preemption 189 // at every possible cooperative preemption point. 190 // 191 // This is valuable to apply to the runtime, which can be sensitive to 192 // preemption points. To apply this to all preemption points in the 193 // runtime and runtime-like code, use the following in bash or zsh: 194 // 195 // X=(-{gc,asm}flags={runtime/...,reflect,sync}=-d=maymorestack=runtime.mayMoreStackPreempt) GOFLAGS=${X[@]} 196 // 197 // This must be deeply nosplit because it is called from a function 198 // prologue before the stack is set up and because the compiler will 199 // call it from any splittable prologue (leading to infinite 200 // recursion). 201 // 202 // Ideally it should also use very little stack because the linker 203 // doesn't currently account for this in nosplit stack depth checking. 204 // 205 // Ensure mayMoreStackPreempt can be called for all ABIs. 206 // 207 //go:nosplit 208 //go:linkname mayMoreStackPreempt 209 func mayMoreStackPreempt() { 210 // Don't do anything on the g0 or gsignal stack. 211 gp := getg() 212 if gp == gp.m.g0 || gp == gp.m.gsignal { 213 return 214 } 215 // Force a preemption, unless the stack is already poisoned. 216 if gp.stackguard0 < stackPoisonMin { 217 gp.stackguard0 = stackPreempt 218 } 219 } 220 221 // mayMoreStackMove is a maymorestack hook that forces stack movement 222 // at every possible point. 223 // 224 // See mayMoreStackPreempt. 225 // 226 //go:nosplit 227 //go:linkname mayMoreStackMove 228 func mayMoreStackMove() { 229 // Don't do anything on the g0 or gsignal stack. 230 gp := getg() 231 if gp == gp.m.g0 || gp == gp.m.gsignal { 232 return 233 } 234 // Force stack movement, unless the stack is already poisoned. 235 if gp.stackguard0 < stackPoisonMin { 236 gp.stackguard0 = stackForceMove 237 } 238 } 239 240 // debugPinnerKeepUnpin is used to make runtime.(*Pinner).Unpin reachable. 241 var debugPinnerKeepUnpin bool = false 242 243 // debugPinnerV1 returns a new Pinner that pins itself. This function can be 244 // used by debuggers to easily obtain a Pinner that will not be garbage 245 // collected (or moved in memory) even if no references to it exist in the 246 // target program. This pinner in turn can be used to extend this property 247 // to other objects, which debuggers can use to simplify the evaluation of 248 // expressions involving multiple call injections. 249 func debugPinnerV1() *Pinner { 250 p := new(Pinner) 251 p.Pin(unsafe.Pointer(p)) 252 if debugPinnerKeepUnpin { 253 // Make Unpin reachable. 254 p.Unpin() 255 } 256 return p 257 } 258