pprof_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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.
  4. // +build !nacl
  5. package pprof_test
  6. import (
  7. "bytes"
  8. "fmt"
  9. "math/big"
  10. "os/exec"
  11. "regexp"
  12. "runtime"
  13. . "runtime/pprof"
  14. "strings"
  15. "sync"
  16. "testing"
  17. "time"
  18. "unsafe"
  19. )
  20. func cpuHogger(f func()) {
  21. // We only need to get one 100 Hz clock tick, so we've got
  22. // a 25x safety buffer.
  23. // But do at least 500 iterations (which should take about 100ms),
  24. // otherwise TestCPUProfileMultithreaded can fail if only one
  25. // thread is scheduled during the 250ms period.
  26. t0 := time.Now()
  27. for i := 0; i < 500 || time.Since(t0) < 250*time.Millisecond; i++ {
  28. f()
  29. }
  30. }
  31. var (
  32. salt1 = 0
  33. salt2 = 0
  34. )
  35. // The actual CPU hogging function.
  36. // Must not call other functions nor access heap/globals in the loop,
  37. // otherwise under race detector the samples will be in the race runtime.
  38. func cpuHog1() {
  39. foo := salt1
  40. for i := 0; i < 1e5; i++ {
  41. if foo > 0 {
  42. foo *= foo
  43. } else {
  44. foo *= foo + 1
  45. }
  46. }
  47. salt1 = foo
  48. }
  49. func cpuHog2() {
  50. foo := salt2
  51. for i := 0; i < 1e5; i++ {
  52. if foo > 0 {
  53. foo *= foo
  54. } else {
  55. foo *= foo + 2
  56. }
  57. }
  58. salt2 = foo
  59. }
  60. func TestCPUProfile(t *testing.T) {
  61. testCPUProfile(t, []string{"pprof_test.cpuHog1"}, func() {
  62. cpuHogger(cpuHog1)
  63. })
  64. }
  65. func TestCPUProfileMultithreaded(t *testing.T) {
  66. defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
  67. testCPUProfile(t, []string{"pprof_test.cpuHog1", "pprof_test.cpuHog2"}, func() {
  68. c := make(chan int)
  69. go func() {
  70. cpuHogger(cpuHog1)
  71. c <- 1
  72. }()
  73. cpuHogger(cpuHog2)
  74. <-c
  75. })
  76. }
  77. func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) {
  78. // Convert []byte to []uintptr.
  79. l := len(bytes) / int(unsafe.Sizeof(uintptr(0)))
  80. val := *(*[]uintptr)(unsafe.Pointer(&bytes))
  81. val = val[:l]
  82. // 5 for the header, 2 for the per-sample header on at least one sample, 3 for the trailer.
  83. if l < 5+2+3 {
  84. t.Logf("profile too short: %#x", val)
  85. if badOS[runtime.GOOS] {
  86. t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
  87. return
  88. }
  89. t.FailNow()
  90. }
  91. hd, val, tl := val[:5], val[5:l-3], val[l-3:]
  92. if hd[0] != 0 || hd[1] != 3 || hd[2] != 0 || hd[3] != 1e6/100 || hd[4] != 0 {
  93. t.Fatalf("unexpected header %#x", hd)
  94. }
  95. if tl[0] != 0 || tl[1] != 1 || tl[2] != 0 {
  96. t.Fatalf("malformed end-of-data marker %#x", tl)
  97. }
  98. for len(val) > 0 {
  99. if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
  100. t.Fatalf("malformed profile. leftover: %#x", val)
  101. }
  102. f(val[0], val[2:2+val[1]])
  103. val = val[2+val[1]:]
  104. }
  105. }
  106. func testCPUProfile(t *testing.T, need []string, f func()) {
  107. switch runtime.GOOS {
  108. case "darwin":
  109. out, err := exec.Command("uname", "-a").CombinedOutput()
  110. if err != nil {
  111. t.Fatal(err)
  112. }
  113. vers := string(out)
  114. t.Logf("uname -a: %v", vers)
  115. case "plan9":
  116. // unimplemented
  117. return
  118. }
  119. var prof bytes.Buffer
  120. if err := StartCPUProfile(&prof); err != nil {
  121. t.Fatal(err)
  122. }
  123. f()
  124. StopCPUProfile()
  125. // Check that profile is well formed and contains need.
  126. have := make([]uintptr, len(need))
  127. parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) {
  128. for _, pc := range stk {
  129. f := runtime.FuncForPC(pc)
  130. if f == nil {
  131. continue
  132. }
  133. t.Log(f.Name(), count)
  134. for i, name := range need {
  135. if strings.Contains(f.Name(), name) {
  136. have[i] += count
  137. }
  138. }
  139. }
  140. })
  141. if len(need) == 0 {
  142. return
  143. }
  144. var total uintptr
  145. for i, name := range need {
  146. total += have[i]
  147. t.Logf("%s: %d\n", name, have[i])
  148. }
  149. ok := true
  150. if total == 0 {
  151. t.Logf("no CPU profile samples collected")
  152. ok = false
  153. }
  154. // We'd like to check a reasonable minimum, like
  155. // total / len(have) / smallconstant, but this test is
  156. // pretty flaky (see bug 7095). So we'll just test to
  157. // make sure we got at least one sample.
  158. min := uintptr(1)
  159. for i, name := range need {
  160. if have[i] < min {
  161. t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
  162. ok = false
  163. }
  164. }
  165. if !ok {
  166. if badOS[runtime.GOOS] {
  167. t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
  168. return
  169. }
  170. t.FailNow()
  171. }
  172. }
  173. func TestCPUProfileWithFork(t *testing.T) {
  174. // Fork can hang if preempted with signals frequently enough (see issue 5517).
  175. // Ensure that we do not do this.
  176. heap := 1 << 30
  177. if testing.Short() {
  178. heap = 100 << 20
  179. }
  180. // This makes fork slower.
  181. garbage := make([]byte, heap)
  182. // Need to touch the slice, otherwise it won't be paged in.
  183. done := make(chan bool)
  184. go func() {
  185. for i := range garbage {
  186. garbage[i] = 42
  187. }
  188. done <- true
  189. }()
  190. <-done
  191. var prof bytes.Buffer
  192. if err := StartCPUProfile(&prof); err != nil {
  193. t.Fatal(err)
  194. }
  195. defer StopCPUProfile()
  196. for i := 0; i < 10; i++ {
  197. exec.Command("go").CombinedOutput()
  198. }
  199. }
  200. // Test that profiler does not observe runtime.gogo as "user" goroutine execution.
  201. // If it did, it would see inconsistent state and would either record an incorrect stack
  202. // or crash because the stack was malformed.
  203. func TestGoroutineSwitch(t *testing.T) {
  204. // How much to try. These defaults take about 1 seconds
  205. // on a 2012 MacBook Pro. The ones in short mode take
  206. // about 0.1 seconds.
  207. tries := 10
  208. count := 1000000
  209. if testing.Short() {
  210. tries = 1
  211. }
  212. for try := 0; try < tries; try++ {
  213. var prof bytes.Buffer
  214. if err := StartCPUProfile(&prof); err != nil {
  215. t.Fatal(err)
  216. }
  217. for i := 0; i < count; i++ {
  218. runtime.Gosched()
  219. }
  220. StopCPUProfile()
  221. // Read profile to look for entries for runtime.gogo with an attempt at a traceback.
  222. // The special entry
  223. parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) {
  224. // An entry with two frames with 'System' in its top frame
  225. // exists to record a PC without a traceback. Those are okay.
  226. if len(stk) == 2 {
  227. f := runtime.FuncForPC(stk[1])
  228. if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") {
  229. return
  230. }
  231. }
  232. // Otherwise, should not see runtime.gogo.
  233. // The place we'd see it would be the inner most frame.
  234. f := runtime.FuncForPC(stk[0])
  235. if f != nil && f.Name() == "runtime.gogo" {
  236. var buf bytes.Buffer
  237. for _, pc := range stk {
  238. f := runtime.FuncForPC(pc)
  239. if f == nil {
  240. fmt.Fprintf(&buf, "%#x ?:0\n", pc)
  241. } else {
  242. file, line := f.FileLine(pc)
  243. fmt.Fprintf(&buf, "%#x %s:%d\n", pc, file, line)
  244. }
  245. }
  246. t.Fatalf("found profile entry for runtime.gogo:\n%s", buf.String())
  247. }
  248. })
  249. }
  250. }
  251. // Test that profiling of division operations is okay, especially on ARM. See issue 6681.
  252. func TestMathBigDivide(t *testing.T) {
  253. testCPUProfile(t, nil, func() {
  254. t := time.After(5 * time.Second)
  255. pi := new(big.Int)
  256. for {
  257. for i := 0; i < 100; i++ {
  258. n := big.NewInt(2646693125139304345)
  259. d := big.NewInt(842468587426513207)
  260. pi.Div(n, d)
  261. }
  262. select {
  263. case <-t:
  264. return
  265. default:
  266. }
  267. }
  268. })
  269. }
  270. // Operating systems that are expected to fail the tests. See issue 6047.
  271. var badOS = map[string]bool{
  272. "darwin": true,
  273. "netbsd": true,
  274. "plan9": true,
  275. }
  276. func TestBlockProfile(t *testing.T) {
  277. t.Skip("lots of details are different for gccgo; FIXME")
  278. type TestCase struct {
  279. name string
  280. f func()
  281. re string
  282. }
  283. tests := [...]TestCase{
  284. {"chan recv", blockChanRecv, `
  285. [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]+
  286. # 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/runtime/chan.go:[0-9]+
  287. # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  288. # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  289. `},
  290. {"chan send", blockChanSend, `
  291. [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]+
  292. # 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/runtime/chan.go:[0-9]+
  293. # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  294. # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  295. `},
  296. {"chan close", blockChanClose, `
  297. [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]+
  298. # 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/runtime/chan.go:[0-9]+
  299. # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  300. # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  301. `},
  302. {"select recv async", blockSelectRecvAsync, `
  303. [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]+
  304. # 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/runtime/select.go:[0-9]+
  305. # 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  306. # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  307. `},
  308. {"select send sync", blockSelectSendSync, `
  309. [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]+
  310. # 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/runtime/select.go:[0-9]+
  311. # 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  312. # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  313. `},
  314. {"mutex", blockMutex, `
  315. [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]+
  316. # 0x[0-9,a-f]+ sync\.\(\*Mutex\)\.Lock\+0x[0-9,a-f]+ .*/src/sync/mutex\.go:[0-9]+
  317. # 0x[0-9,a-f]+ runtime/pprof_test\.blockMutex\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  318. # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  319. `},
  320. {"cond", blockCond, `
  321. [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]+
  322. # 0x[0-9,a-f]+ sync\.\(\*Cond\)\.Wait\+0x[0-9,a-f]+ .*/src/sync/cond\.go:[0-9]+
  323. # 0x[0-9,a-f]+ runtime/pprof_test\.blockCond\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  324. # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/runtime/pprof/pprof_test.go:[0-9]+
  325. `},
  326. }
  327. runtime.SetBlockProfileRate(1)
  328. defer runtime.SetBlockProfileRate(0)
  329. for _, test := range tests {
  330. test.f()
  331. }
  332. var w bytes.Buffer
  333. Lookup("block").WriteTo(&w, 1)
  334. prof := w.String()
  335. if !strings.HasPrefix(prof, "--- contention:\ncycles/second=") {
  336. t.Fatalf("Bad profile header:\n%v", prof)
  337. }
  338. for _, test := range tests {
  339. if !regexp.MustCompile(test.re).MatchString(prof) {
  340. t.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof)
  341. }
  342. }
  343. }
  344. const blockDelay = 10 * time.Millisecond
  345. func blockChanRecv() {
  346. c := make(chan bool)
  347. go func() {
  348. time.Sleep(blockDelay)
  349. c <- true
  350. }()
  351. <-c
  352. }
  353. func blockChanSend() {
  354. c := make(chan bool)
  355. go func() {
  356. time.Sleep(blockDelay)
  357. <-c
  358. }()
  359. c <- true
  360. }
  361. func blockChanClose() {
  362. c := make(chan bool)
  363. go func() {
  364. time.Sleep(blockDelay)
  365. close(c)
  366. }()
  367. <-c
  368. }
  369. func blockSelectRecvAsync() {
  370. c := make(chan bool, 1)
  371. c2 := make(chan bool, 1)
  372. go func() {
  373. time.Sleep(blockDelay)
  374. c <- true
  375. }()
  376. select {
  377. case <-c:
  378. case <-c2:
  379. }
  380. }
  381. func blockSelectSendSync() {
  382. c := make(chan bool)
  383. c2 := make(chan bool)
  384. go func() {
  385. time.Sleep(blockDelay)
  386. <-c
  387. }()
  388. select {
  389. case c <- true:
  390. case c2 <- true:
  391. }
  392. }
  393. func blockMutex() {
  394. var mu sync.Mutex
  395. mu.Lock()
  396. go func() {
  397. time.Sleep(blockDelay)
  398. mu.Unlock()
  399. }()
  400. mu.Lock()
  401. }
  402. func blockCond() {
  403. var mu sync.Mutex
  404. c := sync.NewCond(&mu)
  405. mu.Lock()
  406. go func() {
  407. time.Sleep(blockDelay)
  408. mu.Lock()
  409. c.Signal()
  410. mu.Unlock()
  411. }()
  412. c.Wait()
  413. mu.Unlock()
  414. }