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(false))
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
View as plain text