gc_test.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. package runtime_test
  5. import (
  6. // "os"
  7. "runtime"
  8. "runtime/debug"
  9. "testing"
  10. "time"
  11. "unsafe"
  12. )
  13. func TestGcSys(t *testing.T) {
  14. /* gccgo does not have a go command
  15. if os.Getenv("GOGC") == "off" {
  16. t.Skip("skipping test; GOGC=off in environment")
  17. }
  18. data := struct{ Short bool }{testing.Short()}
  19. got := executeTest(t, testGCSysSource, &data)
  20. want := "OK\n"
  21. if got != want {
  22. t.Fatalf("expected %q, but got %q", want, got)
  23. }
  24. */
  25. }
  26. const testGCSysSource = `
  27. package main
  28. import (
  29. "fmt"
  30. "runtime"
  31. )
  32. func main() {
  33. runtime.GOMAXPROCS(1)
  34. memstats := new(runtime.MemStats)
  35. runtime.GC()
  36. runtime.ReadMemStats(memstats)
  37. sys := memstats.Sys
  38. runtime.MemProfileRate = 0 // disable profiler
  39. itercount := 1000000
  40. {{if .Short}}
  41. itercount = 100000
  42. {{end}}
  43. for i := 0; i < itercount; i++ {
  44. workthegc()
  45. }
  46. // Should only be using a few MB.
  47. // We allocated 100 MB or (if not short) 1 GB.
  48. runtime.ReadMemStats(memstats)
  49. if sys > memstats.Sys {
  50. sys = 0
  51. } else {
  52. sys = memstats.Sys - sys
  53. }
  54. if sys > 16<<20 {
  55. fmt.Printf("using too much memory: %d bytes\n", sys)
  56. return
  57. }
  58. fmt.Printf("OK\n")
  59. }
  60. func workthegc() []byte {
  61. return make([]byte, 1029)
  62. }
  63. `
  64. func TestGcDeepNesting(t *testing.T) {
  65. type T [2][2][2][2][2][2][2][2][2][2]*int
  66. a := new(T)
  67. // Prevent the compiler from applying escape analysis.
  68. // This makes sure new(T) is allocated on heap, not on the stack.
  69. t.Logf("%p", a)
  70. a[0][0][0][0][0][0][0][0][0][0] = new(int)
  71. *a[0][0][0][0][0][0][0][0][0][0] = 13
  72. runtime.GC()
  73. if *a[0][0][0][0][0][0][0][0][0][0] != 13 {
  74. t.Fail()
  75. }
  76. }
  77. func TestGcHashmapIndirection(t *testing.T) {
  78. defer debug.SetGCPercent(debug.SetGCPercent(1))
  79. runtime.GC()
  80. type T struct {
  81. a [256]int
  82. }
  83. m := make(map[T]T)
  84. for i := 0; i < 2000; i++ {
  85. var a T
  86. a.a[0] = i
  87. m[a] = T{}
  88. }
  89. }
  90. func TestGcArraySlice(t *testing.T) {
  91. type X struct {
  92. buf [1]byte
  93. nextbuf []byte
  94. next *X
  95. }
  96. var head *X
  97. for i := 0; i < 10; i++ {
  98. p := &X{}
  99. p.buf[0] = 42
  100. p.next = head
  101. if head != nil {
  102. p.nextbuf = head.buf[:]
  103. }
  104. head = p
  105. runtime.GC()
  106. }
  107. for p := head; p != nil; p = p.next {
  108. if p.buf[0] != 42 {
  109. t.Fatal("corrupted heap")
  110. }
  111. }
  112. }
  113. func TestGcRescan(t *testing.T) {
  114. type X struct {
  115. c chan error
  116. nextx *X
  117. }
  118. type Y struct {
  119. X
  120. nexty *Y
  121. p *int
  122. }
  123. var head *Y
  124. for i := 0; i < 10; i++ {
  125. p := &Y{}
  126. p.c = make(chan error)
  127. if head != nil {
  128. p.nextx = &head.X
  129. }
  130. p.nexty = head
  131. p.p = new(int)
  132. *p.p = 42
  133. head = p
  134. runtime.GC()
  135. }
  136. for p := head; p != nil; p = p.nexty {
  137. if *p.p != 42 {
  138. t.Fatal("corrupted heap")
  139. }
  140. }
  141. }
  142. func TestGcLastTime(t *testing.T) {
  143. ms := new(runtime.MemStats)
  144. t0 := time.Now().UnixNano()
  145. runtime.GC()
  146. t1 := time.Now().UnixNano()
  147. runtime.ReadMemStats(ms)
  148. last := int64(ms.LastGC)
  149. if t0 > last || last > t1 {
  150. t.Fatalf("bad last GC time: got %v, want [%v, %v]", last, t0, t1)
  151. }
  152. pause := ms.PauseNs[(ms.NumGC+255)%256]
  153. // Due to timer granularity, pause can actually be 0 on windows
  154. // or on virtualized environments.
  155. if pause == 0 {
  156. t.Logf("last GC pause was 0")
  157. } else if pause > 10e9 {
  158. t.Logf("bad last GC pause: got %v, want [0, 10e9]", pause)
  159. }
  160. }
  161. var hugeSink interface{}
  162. func TestHugeGCInfo(t *testing.T) {
  163. // The test ensures that compiler can chew these huge types even on weakest machines.
  164. // The types are not allocated at runtime.
  165. if hugeSink != nil {
  166. // 400MB on 32 bots, 4TB on 64-bits.
  167. const n = (400 << 20) + (unsafe.Sizeof(uintptr(0))-4)<<40
  168. hugeSink = new([n]*byte)
  169. hugeSink = new([n]uintptr)
  170. hugeSink = new(struct {
  171. x float64
  172. y [n]*byte
  173. z []string
  174. })
  175. hugeSink = new(struct {
  176. x float64
  177. y [n]uintptr
  178. z []string
  179. })
  180. }
  181. }
  182. func BenchmarkSetTypeNoPtr1(b *testing.B) {
  183. type NoPtr1 struct {
  184. p uintptr
  185. }
  186. var p *NoPtr1
  187. for i := 0; i < b.N; i++ {
  188. p = &NoPtr1{}
  189. }
  190. _ = p
  191. }
  192. func BenchmarkSetTypeNoPtr2(b *testing.B) {
  193. type NoPtr2 struct {
  194. p, q uintptr
  195. }
  196. var p *NoPtr2
  197. for i := 0; i < b.N; i++ {
  198. p = &NoPtr2{}
  199. }
  200. _ = p
  201. }
  202. func BenchmarkSetTypePtr1(b *testing.B) {
  203. type Ptr1 struct {
  204. p *byte
  205. }
  206. var p *Ptr1
  207. for i := 0; i < b.N; i++ {
  208. p = &Ptr1{}
  209. }
  210. _ = p
  211. }
  212. func BenchmarkSetTypePtr2(b *testing.B) {
  213. type Ptr2 struct {
  214. p, q *byte
  215. }
  216. var p *Ptr2
  217. for i := 0; i < b.N; i++ {
  218. p = &Ptr2{}
  219. }
  220. _ = p
  221. }
  222. func BenchmarkAllocation(b *testing.B) {
  223. type T struct {
  224. x, y *byte
  225. }
  226. ngo := runtime.GOMAXPROCS(0)
  227. work := make(chan bool, b.N+ngo)
  228. result := make(chan *T)
  229. for i := 0; i < b.N; i++ {
  230. work <- true
  231. }
  232. for i := 0; i < ngo; i++ {
  233. work <- false
  234. }
  235. for i := 0; i < ngo; i++ {
  236. go func() {
  237. var x *T
  238. for <-work {
  239. for i := 0; i < 1000; i++ {
  240. x = &T{}
  241. }
  242. }
  243. result <- x
  244. }()
  245. }
  246. for i := 0; i < ngo; i++ {
  247. <-result
  248. }
  249. }
  250. func TestPrintGC(t *testing.T) {
  251. if testing.Short() {
  252. t.Skip("Skipping in short mode")
  253. }
  254. defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
  255. done := make(chan bool)
  256. go func() {
  257. for {
  258. select {
  259. case <-done:
  260. return
  261. default:
  262. runtime.GC()
  263. }
  264. }
  265. }()
  266. for i := 0; i < 1e4; i++ {
  267. func() {
  268. defer print("")
  269. }()
  270. }
  271. close(done)
  272. }