mirror of
https://github.com/golang/go
synced 2024-11-26 23:11:24 -07:00
runtime, cmd/link/internal/ld: disable memory profiling when data unreachable
If runtime.MemProfile is unreachable, default to not collecting any memory profiling samples, to save memory on the hash table. Fixes #42347 Change-Id: I9a4894a5fc77035fe59b1842e1ec77a1182e70c1 Reviewed-on: https://go-review.googlesource.com/c/go/+/299671 Reviewed-by: Cherry Zhang <cherryyz@google.com> Trust: Keith Randall <khr@golang.org>
This commit is contained in:
parent
e4f3cfadf6
commit
18510ae88f
@ -224,3 +224,103 @@ func testWindowsBuildmodeCSharedASLR(t *testing.T, useASLR bool) {
|
|||||||
t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag should not be set")
|
t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag should not be set")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestMemProfileCheck tests that cmd/link sets
|
||||||
|
// runtime.disableMemoryProfiling if the runtime.MemProfile
|
||||||
|
// symbol is unreachable after deadcode (and not dynlinking).
|
||||||
|
// The runtime then uses that to set the default value of
|
||||||
|
// runtime.MemProfileRate, which this test checks.
|
||||||
|
func TestMemProfileCheck(t *testing.T) {
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
prog string
|
||||||
|
wantOut string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"no_memprofile",
|
||||||
|
`
|
||||||
|
package main
|
||||||
|
import "runtime"
|
||||||
|
func main() {
|
||||||
|
println(runtime.MemProfileRate)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"with_memprofile",
|
||||||
|
`
|
||||||
|
package main
|
||||||
|
import "runtime"
|
||||||
|
func main() {
|
||||||
|
runtime.MemProfile(nil, false)
|
||||||
|
println(runtime.MemProfileRate)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"524288",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"with_memprofile_indirect",
|
||||||
|
`
|
||||||
|
package main
|
||||||
|
import "runtime"
|
||||||
|
var f = runtime.MemProfile
|
||||||
|
func main() {
|
||||||
|
if f == nil {
|
||||||
|
panic("no f")
|
||||||
|
}
|
||||||
|
println(runtime.MemProfileRate)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"524288",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"with_memprofile_runtime_pprof",
|
||||||
|
`
|
||||||
|
package main
|
||||||
|
import "runtime"
|
||||||
|
import "runtime/pprof"
|
||||||
|
func main() {
|
||||||
|
_ = pprof.Profiles()
|
||||||
|
println(runtime.MemProfileRate)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"524288",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"with_memprofile_http_pprof",
|
||||||
|
`
|
||||||
|
package main
|
||||||
|
import "runtime"
|
||||||
|
import _ "net/http/pprof"
|
||||||
|
func main() {
|
||||||
|
println(runtime.MemProfileRate)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"524288",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tempDir := t.TempDir()
|
||||||
|
src := filepath.Join(tempDir, "x.go")
|
||||||
|
if err := ioutil.WriteFile(src, []byte(tt.prog), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cmd := exec.Command(testenv.GoToolPath(t), "run", src)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := strings.TrimSpace(string(out))
|
||||||
|
if got != tt.wantOut {
|
||||||
|
t.Errorf("got %q; want %q", got, tt.wantOut)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -790,6 +790,18 @@ func (ctxt *Link) linksetup() {
|
|||||||
sb.SetSize(0)
|
sb.SetSize(0)
|
||||||
sb.AddUint8(uint8(objabi.GOARM))
|
sb.AddUint8(uint8(objabi.GOARM))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set runtime.disableMemoryProfiling bool if
|
||||||
|
// runtime.MemProfile is not retained in the binary after
|
||||||
|
// deadcode (and we're not dynamically linking).
|
||||||
|
memProfile := ctxt.loader.Lookup("runtime.MemProfile", sym.SymVerABIInternal)
|
||||||
|
if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
|
||||||
|
memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
|
||||||
|
sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
|
||||||
|
sb.SetType(sym.SDATA)
|
||||||
|
sb.SetSize(0)
|
||||||
|
sb.AddUint8(1) // true bool
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If OTOH the module does not contain the runtime package,
|
// If OTOH the module does not contain the runtime package,
|
||||||
// create a local symbol for the moduledata.
|
// create a local symbol for the moduledata.
|
||||||
|
@ -490,7 +490,22 @@ func (r *StackRecord) Stack() []uintptr {
|
|||||||
// memory profiling rate should do so just once, as early as
|
// memory profiling rate should do so just once, as early as
|
||||||
// possible in the execution of the program (for example,
|
// possible in the execution of the program (for example,
|
||||||
// at the beginning of main).
|
// at the beginning of main).
|
||||||
var MemProfileRate int = 512 * 1024
|
var MemProfileRate int = defaultMemProfileRate(512 * 1024)
|
||||||
|
|
||||||
|
// defaultMemProfileRate returns 0 if disableMemoryProfiling is set.
|
||||||
|
// It exists primarily for the godoc rendering of MemProfileRate
|
||||||
|
// above.
|
||||||
|
func defaultMemProfileRate(v int) int {
|
||||||
|
if disableMemoryProfiling {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// disableMemoryProfiling is set by the linker if runtime.MemProfile
|
||||||
|
// is not used and the link type guarantees nobody else could use it
|
||||||
|
// elsewhere.
|
||||||
|
var disableMemoryProfiling bool
|
||||||
|
|
||||||
// A MemProfileRecord describes the live objects allocated
|
// A MemProfileRecord describes the live objects allocated
|
||||||
// by a particular call sequence (stack trace).
|
// by a particular call sequence (stack trace).
|
||||||
|
Loading…
Reference in New Issue
Block a user