mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
This CL adds two related features enabled by default via compatibility GODEBUGs containermaxprocs and updatemaxprocs. On Linux, containermaxprocs makes the Go runtime consider cgroup CPU bandwidth limits (quota/period) when setting GOMAXPROCS. If the cgroup limit is lower than the number of logical CPUs available, then the cgroup limit takes precedence. On all OSes, updatemaxprocs makes the Go runtime periodically recalculate the default GOMAXPROCS value and update GOMAXPROCS if it has changed. If GOMAXPROCS is set manually, this update does not occur. This is intended primarily to detect changes to cgroup limits, but it applies on all OSes because the CPU affinity mask can change as well. The runtime only considers the limit in the leaf cgroup (the one that actually contains the process), caching the CPU limit file descriptor(s), which are periodically reread for updates. This is a small departure from the original proposed design. It will not consider limits of parent cgroups (which may be lower than the leaf), and it will not detection cgroup migration after process start. We can consider changing this in the future, but the simpler approach is less invasive; less risk to packages that have some awareness of runtime internals. e.g., if the runtime periodically opens new files during execution, file descriptor leak detection is difficult to implement in a stable way. For #73193. Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Change-Id: I6a6a636c631c1ae577fb8254960377ba91c5dc98 Reviewed-on: https://go-review.googlesource.com/c/go/+/670497 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
94 lines
3.5 KiB
Go
94 lines
3.5 KiB
Go
// Copyright 2022 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package coverage
|
|
|
|
// Building the runtime package with coverage instrumentation enabled
|
|
// is tricky. For all other packages, you can be guaranteed that
|
|
// the package init function is run before any functions are executed,
|
|
// but this invariant is not maintained for packages such as "runtime",
|
|
// "internal/cpu", etc. To handle this, hard-code the package ID for
|
|
// the set of packages whose functions may be running before the
|
|
// init function of the package is complete.
|
|
//
|
|
// Hardcoding is unfortunate because it means that the tool that does
|
|
// coverage instrumentation has to keep a list of runtime packages,
|
|
// meaning that if someone makes changes to the pkg "runtime"
|
|
// dependencies, unexpected behavior will result for coverage builds.
|
|
// The coverage runtime will detect and report the unexpected
|
|
// behavior; look for an error of this form:
|
|
//
|
|
// internal error in coverage meta-data tracking:
|
|
// list of hard-coded runtime package IDs needs revising.
|
|
// registered list:
|
|
// slot: 0 path='internal/cpu' hard-coded id: 1
|
|
// slot: 1 path='internal/goarch' hard-coded id: 2
|
|
// slot: 2 path='internal/runtime/atomic' hard-coded id: 3
|
|
// slot: 3 path='internal/goos'
|
|
// slot: 4 path='internal/runtime/sys' hard-coded id: 5
|
|
// slot: 5 path='internal/abi' hard-coded id: 4
|
|
// slot: 6 path='internal/runtime/math' hard-coded id: 6
|
|
// slot: 7 path='internal/bytealg' hard-coded id: 7
|
|
// slot: 8 path='internal/goexperiment'
|
|
// slot: 9 path='internal/runtime/syscall' hard-coded id: 8
|
|
// slot: 10 path='runtime' hard-coded id: 9
|
|
// fatal error: runtime.addCovMeta
|
|
//
|
|
// For the error above, the hard-coded list is missing "internal/goos"
|
|
// and "internal/goexperiment" ; the developer in question will need
|
|
// to copy the list above into "rtPkgs" below.
|
|
//
|
|
// Note: this strategy assumes that the list of dependencies of
|
|
// package runtime is fixed, and doesn't vary depending on OS/arch. If
|
|
// this were to be the case, we would need a table of some sort below
|
|
// as opposed to a fixed list.
|
|
|
|
var rtPkgs = [...]string{
|
|
"internal/asan",
|
|
"internal/byteorder",
|
|
"internal/coverage/rtcov",
|
|
"internal/cpu",
|
|
"internal/bytealg",
|
|
"internal/goarch",
|
|
"internal/abi",
|
|
"internal/chacha8rand",
|
|
"internal/godebugs",
|
|
"internal/goexperiment",
|
|
"internal/goos",
|
|
"internal/msan",
|
|
"internal/profilerecord",
|
|
"internal/race",
|
|
"internal/runtime/atomic",
|
|
"internal/runtime/exithook",
|
|
"internal/runtime/gc",
|
|
"internal/runtime/math",
|
|
"internal/runtime/strconv",
|
|
"internal/runtime/sys",
|
|
"internal/runtime/maps",
|
|
"internal/runtime/syscall",
|
|
"internal/runtime/cgroup",
|
|
"internal/stringslite",
|
|
"runtime",
|
|
}
|
|
|
|
// Scoping note: the constants and apis in this file are internal
|
|
// only, not expected to ever be exposed outside of the runtime (unlike
|
|
// other coverage file formats and APIs, which will likely be shared
|
|
// at some point).
|
|
|
|
// NotHardCoded is a package pseudo-ID indicating that a given package
|
|
// is not part of the runtime and doesn't require a hard-coded ID.
|
|
const NotHardCoded = -1
|
|
|
|
// HardCodedPkgID returns the hard-coded ID for the specified package
|
|
// path, or -1 if we don't use a hard-coded ID. Hard-coded IDs start
|
|
// at -2 and decrease as we go down the list.
|
|
func HardCodedPkgID(pkgpath string) int {
|
|
for k, p := range rtPkgs {
|
|
if p == pkgpath {
|
|
return (0 - k) - 2
|
|
}
|
|
}
|
|
return NotHardCoded
|
|
}
|