github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/runtime/gc_test.go (about)

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