1 // Copyright 2011 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.
23 func TestCPUProfile(t
*testing
.T
) {
24 buf
:= make([]byte, 100000)
25 testCPUProfile(t
, []string{"crc32.update"}, func() {
26 // This loop takes about a quarter second on a 2 GHz laptop.
27 // We only need to get one 100 Hz clock tick, so we've got
28 // a 25x safety buffer.
29 for i
:= 0; i
< 1000; i
++ {
30 crc32
.ChecksumIEEE(buf
)
35 func TestCPUProfileMultithreaded(t
*testing
.T
) {
36 // TODO(brainman): delete when issue 6986 is fixed.
37 if runtime
.GOOS
== "windows" && runtime
.GOARCH
== "amd64" {
38 t
.Skip("skipping broken test on windows-amd64-race")
40 buf
:= make([]byte, 100000)
41 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(2))
42 testCPUProfile(t
, []string{"crc32.update"}, func() {
45 for i
:= 0; i
< 2000; i
++ {
46 crc32
.Update(0, crc32
.IEEETable
, buf
)
50 // This loop takes about a quarter second on a 2 GHz laptop.
51 // We only need to get one 100 Hz clock tick, so we've got
52 // a 25x safety buffer.
53 for i
:= 0; i
< 2000; i
++ {
54 crc32
.ChecksumIEEE(buf
)
60 func parseProfile(t
*testing
.T
, bytes
[]byte, f
func(uintptr, []uintptr)) {
61 // Convert []byte to []uintptr.
62 l
:= len(bytes
) / int(unsafe
.Sizeof(uintptr(0)))
63 val
:= *(*[]uintptr)(unsafe
.Pointer(&bytes
))
66 // 5 for the header, 2 for the per-sample header on at least one sample, 3 for the trailer.
68 t
.Logf("profile too short: %#x", val
)
69 if badOS
[runtime
.GOOS
] {
70 t
.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime
.GOOS
)
76 hd
, val
, tl
:= val
[:5], val
[5:l
-3], val
[l
-3:]
77 if hd
[0] != 0 || hd
[1] != 3 || hd
[2] != 0 || hd
[3] != 1e6
/100 || hd
[4] != 0 {
78 t
.Fatalf("unexpected header %#x", hd
)
81 if tl
[0] != 0 || tl
[1] != 1 || tl
[2] != 0 {
82 t
.Fatalf("malformed end-of-data marker %#x", tl
)
86 if len(val
) < 2 || val
[0] < 1 || val
[1] < 1 ||
uintptr(len(val
)) < 2+val
[1] {
87 t
.Fatalf("malformed profile. leftover: %#x", val
)
89 f(val
[0], val
[2:2+val
[1]])
94 func testCPUProfile(t
*testing
.T
, need
[]string, f
func()) {
97 out
, err
:= exec
.Command("uname", "-a").CombinedOutput()
102 t
.Logf("uname -a: %v", vers
)
108 var prof bytes
.Buffer
109 if err
:= StartCPUProfile(&prof
); err
!= nil {
115 // Check that profile is well formed and contains ChecksumIEEE.
116 have
:= make([]uintptr, len(need
))
117 parseProfile(t
, prof
.Bytes(), func(count
uintptr, stk
[]uintptr) {
118 for _
, pc
:= range stk
{
119 f
:= runtime
.FuncForPC(pc
)
123 for i
, name
:= range need
{
124 if strings
.Contains(f
.Name(), name
) {
136 for i
, name
:= range need
{
138 t
.Logf("%s: %d\n", name
, have
[i
])
142 t
.Logf("no CPU profile samples collected")
145 min
:= total
/ uintptr(len(have
)) / 3
146 for i
, name
:= range need
{
148 t
.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name
, have
[i
], total
, min
, total
/uintptr(len(have
)))
154 if badOS
[runtime
.GOOS
] {
155 t
.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime
.GOOS
)
162 func TestCPUProfileWithFork(t
*testing
.T
) {
163 // Fork can hang if preempted with signals frequently enough (see issue 5517).
164 // Ensure that we do not do this.
169 // This makes fork slower.
170 garbage
:= make([]byte, heap
)
171 // Need to touch the slice, otherwise it won't be paged in.
172 done
:= make(chan bool)
174 for i
:= range garbage
{
181 var prof bytes
.Buffer
182 if err
:= StartCPUProfile(&prof
); err
!= nil {
185 defer StopCPUProfile()
187 for i
:= 0; i
< 10; i
++ {
188 exec
.Command("go").CombinedOutput()
192 // Test that profiler does not observe runtime.gogo as "user" goroutine execution.
193 // If it did, it would see inconsistent state and would either record an incorrect stack
194 // or crash because the stack was malformed.
195 func TestGoroutineSwitch(t
*testing
.T
) {
196 if runtime
.GOOS
== "windows" {
197 t
.Skip("flaky test; see http://golang.org/issue/6417")
199 // How much to try. These defaults take about 1 seconds
200 // on a 2012 MacBook Pro. The ones in short mode take
201 // about 0.1 seconds.
207 for try
:= 0; try
< tries
; try
++ {
208 var prof bytes
.Buffer
209 if err
:= StartCPUProfile(&prof
); err
!= nil {
212 for i
:= 0; i
< count
; i
++ {
217 // Read profile to look for entries for runtime.gogo with an attempt at a traceback.
219 parseProfile(t
, prof
.Bytes(), func(count
uintptr, stk
[]uintptr) {
220 // An entry with two frames with 'System' in its top frame
221 // exists to record a PC without a traceback. Those are okay.
223 f
:= runtime
.FuncForPC(stk
[1])
224 if f
!= nil && f
.Name() == "System" {
229 // Otherwise, should not see runtime.gogo.
230 // The place we'd see it would be the inner most frame.
231 f
:= runtime
.FuncForPC(stk
[0])
232 if f
!= nil && f
.Name() == "runtime.gogo" {
234 for _
, pc
:= range stk
{
235 f
:= runtime
.FuncForPC(pc
)
237 fmt
.Fprintf(&buf
, "%#x ?:0\n", pc
)
239 file
, line
:= f
.FileLine(pc
)
240 fmt
.Fprintf(&buf
, "%#x %s:%d\n", pc
, file
, line
)
243 t
.Fatalf("found profile entry for runtime.gogo:\n%s", buf
.String())
249 // Test that profiling of division operations is okay, especially on ARM. See issue 6681.
250 func TestMathBigDivide(t
*testing
.T
) {
251 // TODO(brainman): delete when issue 6986 is fixed.
252 if runtime
.GOOS
== "windows" && runtime
.GOARCH
== "amd64" {
253 t
.Skip("skipping broken test on windows-amd64-race")
255 testCPUProfile(t
, nil, func() {
256 t
:= time
.After(5 * time
.Second
)
259 for i
:= 0; i
< 100; i
++ {
260 n
:= big
.NewInt(2646693125139304345)
261 d
:= big
.NewInt(842468587426513207)
273 // Operating systems that are expected to fail the tests. See issue 6047.
274 var badOS
= map[string]bool{
280 func TestBlockProfile(t
*testing
.T
) {
281 t
.Skip("lots of details are different for gccgo; FIXME")
282 type TestCase
struct {
287 tests
:= [...]TestCase
{
288 {"chan recv", blockChanRecv
, `
289 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
290 # 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
291 # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
292 # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
294 {"chan send", blockChanSend
, `
295 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
296 # 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
297 # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
298 # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
300 {"chan close", blockChanClose
, `
301 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
302 # 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
303 # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
304 # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
306 {"select recv async", blockSelectRecvAsync
, `
307 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
308 # 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
309 # 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
310 # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
312 {"select send sync", blockSelectSendSync
, `
313 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
314 # 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+
315 # 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
316 # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
318 {"mutex", blockMutex
, `
319 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
320 # 0x[0-9,a-f]+ sync\.\(\*Mutex\)\.Lock\+0x[0-9,a-f]+ .*/src/pkg/sync/mutex\.go:[0-9]+
321 # 0x[0-9,a-f]+ runtime/pprof_test\.blockMutex\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
322 # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
326 runtime
.SetBlockProfileRate(1)
327 defer runtime
.SetBlockProfileRate(0)
328 for _
, test
:= range tests
{
332 Lookup("block").WriteTo(&w
, 1)
335 if !strings
.HasPrefix(prof
, "--- contention:\ncycles/second=") {
336 t
.Fatalf("Bad profile header:\n%v", prof
)
339 for _
, test
:= range tests
{
340 if !regexp
.MustCompile(test
.re
).MatchString(prof
) {
341 t
.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test
.name
, test
.re
, prof
)
346 const blockDelay
= 10 * time
.Millisecond
348 func blockChanRecv() {
351 time
.Sleep(blockDelay
)
357 func blockChanSend() {
360 time
.Sleep(blockDelay
)
366 func blockChanClose() {
369 time
.Sleep(blockDelay
)
375 func blockSelectRecvAsync() {
376 c
:= make(chan bool, 1)
377 c2
:= make(chan bool, 1)
379 time
.Sleep(blockDelay
)
388 func blockSelectSendSync() {
390 c2
:= make(chan bool)
392 time
.Sleep(blockDelay
)
405 time
.Sleep(blockDelay
)