mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime/pprof: test multithreaded profile, remove OS X workarounds
This means that pprof will no longer report profiles on OS X. That's unfortunate, but the profiles were often wrong and, worse, it was difficult to tell whether the profile was wrong or not. The workarounds were making the scheduler more complex, possibly caused a deadlock (see issue 5519), and did not actually deliver reliable results. It may be possible for adventurous users to apply a patch to their kernels to get working results, or perhaps having no results will encourage someone to do the work of creating a profiling thread like on Windows. Issue 6047 has details. Fixes #5519. Fixes #6047. R=golang-dev, bradfitz, r CC=golang-dev https://golang.org/cl/12429045
This commit is contained in:
parent
d8e27db395
commit
d3066e47b1
15 changed files with 68 additions and 136 deletions
|
|
@ -19,6 +19,38 @@ import (
|
|||
)
|
||||
|
||||
func TestCPUProfile(t *testing.T) {
|
||||
buf := make([]byte, 100000)
|
||||
testCPUProfile(t, []string{"crc32.ChecksumIEEE"}, func() {
|
||||
// This loop takes about a quarter second on a 2 GHz laptop.
|
||||
// We only need to get one 100 Hz clock tick, so we've got
|
||||
// a 25x safety buffer.
|
||||
for i := 0; i < 1000; i++ {
|
||||
crc32.ChecksumIEEE(buf)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCPUProfileMultithreaded(t *testing.T) {
|
||||
buf := make([]byte, 100000)
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
|
||||
testCPUProfile(t, []string{"crc32.ChecksumIEEE", "crc32.Update"}, func() {
|
||||
c := make(chan int)
|
||||
go func() {
|
||||
for i := 0; i < 2000; i++ {
|
||||
crc32.Update(0, crc32.IEEETable, buf)
|
||||
}
|
||||
c <- 1
|
||||
}()
|
||||
// This loop takes about a quarter second on a 2 GHz laptop.
|
||||
// We only need to get one 100 Hz clock tick, so we've got
|
||||
// a 25x safety buffer.
|
||||
for i := 0; i < 2000; i++ {
|
||||
crc32.ChecksumIEEE(buf)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func testCPUProfile(t *testing.T, need []string, f func()) {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
out, err := exec.Command("uname", "-a").CombinedOutput()
|
||||
|
|
@ -27,26 +59,16 @@ func TestCPUProfile(t *testing.T) {
|
|||
}
|
||||
vers := string(out)
|
||||
t.Logf("uname -a: %v", vers)
|
||||
// Lion uses "Darwin Kernel Version 11".
|
||||
if strings.Contains(vers, "Darwin Kernel Version 10") && strings.Contains(vers, "RELEASE_X86_64") {
|
||||
t.Skip("skipping test on known-broken kernel (64-bit Leopard / Snow Leopard)")
|
||||
}
|
||||
case "plan9":
|
||||
// unimplemented
|
||||
return
|
||||
}
|
||||
|
||||
buf := make([]byte, 100000)
|
||||
var prof bytes.Buffer
|
||||
if err := StartCPUProfile(&prof); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// This loop takes about a quarter second on a 2 GHz laptop.
|
||||
// We only need to get one 100 Hz clock tick, so we've got
|
||||
// a 25x safety buffer.
|
||||
for i := 0; i < 1000; i++ {
|
||||
crc32.ChecksumIEEE(buf)
|
||||
}
|
||||
f()
|
||||
StopCPUProfile()
|
||||
|
||||
// Convert []byte to []uintptr.
|
||||
|
|
@ -56,6 +78,10 @@ func TestCPUProfile(t *testing.T) {
|
|||
val = val[:l]
|
||||
|
||||
if l < 13 {
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Logf("ignoring failure on OS X; see golang.org/issue/6047")
|
||||
return
|
||||
}
|
||||
t.Fatalf("profile too short: %#x", val)
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +95,7 @@ func TestCPUProfile(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check that profile is well formed and contains ChecksumIEEE.
|
||||
found := false
|
||||
have := make([]uintptr, len(need))
|
||||
for len(val) > 0 {
|
||||
if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
|
||||
t.Fatalf("malformed profile. leftover: %#x", val)
|
||||
|
|
@ -79,14 +105,38 @@ func TestCPUProfile(t *testing.T) {
|
|||
if f == nil {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(f.Name(), "ChecksumIEEE") {
|
||||
found = true
|
||||
for i, name := range need {
|
||||
if strings.Contains(f.Name(), name) {
|
||||
have[i] += val[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
val = val[2+val[1]:]
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatal("did not find ChecksumIEEE in the profile")
|
||||
var total uintptr
|
||||
for i, name := range need {
|
||||
total += have[i]
|
||||
t.Logf("%s: %d\n", name, have[i])
|
||||
}
|
||||
ok := true
|
||||
if total == 0 {
|
||||
t.Logf("no CPU profile samples collected")
|
||||
ok = false
|
||||
}
|
||||
min := total / uintptr(len(have)) / 2
|
||||
for i, name := range need {
|
||||
if have[i] < min {
|
||||
t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Logf("ignoring failure on OS X; see golang.org/issue/6047")
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue