github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/runtime/testdata/testprog/gc.go (about)

     1  // Copyright 2015 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 main
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"runtime"
    11  	"runtime/debug"
    12  	"sync/atomic"
    13  	"time"
    14  )
    15  
    16  func init() {
    17  	register("GCFairness", GCFairness)
    18  	register("GCFairness2", GCFairness2)
    19  	register("GCSys", GCSys)
    20  }
    21  
    22  func GCSys() {
    23  	runtime.GOMAXPROCS(1)
    24  	memstats := new(runtime.MemStats)
    25  	runtime.GC()
    26  	runtime.ReadMemStats(memstats)
    27  	sys := memstats.Sys
    28  
    29  	runtime.MemProfileRate = 0 // disable profiler
    30  
    31  	itercount := 100000
    32  	for i := 0; i < itercount; i++ {
    33  		workthegc()
    34  	}
    35  
    36  	// Should only be using a few MB.
    37  	// We allocated 100 MB or (if not short) 1 GB.
    38  	runtime.ReadMemStats(memstats)
    39  	if sys > memstats.Sys {
    40  		sys = 0
    41  	} else {
    42  		sys = memstats.Sys - sys
    43  	}
    44  	if sys > 16<<20 {
    45  		fmt.Printf("using too much memory: %d bytes\n", sys)
    46  		return
    47  	}
    48  	fmt.Printf("OK\n")
    49  }
    50  
    51  var sink []byte
    52  
    53  func workthegc() []byte {
    54  	sink = make([]byte, 1029)
    55  	return sink
    56  }
    57  
    58  func GCFairness() {
    59  	runtime.GOMAXPROCS(1)
    60  	f, err := os.Open("/dev/null")
    61  	if os.IsNotExist(err) {
    62  		// This test tests what it is intended to test only if writes are fast.
    63  		// If there is no /dev/null, we just don't execute the test.
    64  		fmt.Println("OK")
    65  		return
    66  	}
    67  	if err != nil {
    68  		fmt.Println(err)
    69  		os.Exit(1)
    70  	}
    71  	for i := 0; i < 2; i++ {
    72  		go func() {
    73  			for {
    74  				f.Write([]byte("."))
    75  			}
    76  		}()
    77  	}
    78  	time.Sleep(10 * time.Millisecond)
    79  	fmt.Println("OK")
    80  }
    81  
    82  func GCFairness2() {
    83  	// Make sure user code can't exploit the GC's high priority
    84  	// scheduling to make scheduling of user code unfair. See
    85  	// issue #15706.
    86  	runtime.GOMAXPROCS(1)
    87  	debug.SetGCPercent(1)
    88  	var count [3]int64
    89  	var sink [3]interface{}
    90  	for i := range count {
    91  		go func(i int) {
    92  			for {
    93  				sink[i] = make([]byte, 1024)
    94  				atomic.AddInt64(&count[i], 1)
    95  			}
    96  		}(i)
    97  	}
    98  	// Note: If the unfairness is really bad, it may not even get
    99  	// past the sleep.
   100  	//
   101  	// If the scheduling rules change, this may not be enough time
   102  	// to let all goroutines run, but for now we cycle through
   103  	// them rapidly.
   104  	//
   105  	// OpenBSD's scheduler makes every usleep() take at least
   106  	// 20ms, so we need a long time to ensure all goroutines have
   107  	// run. If they haven't run after 30ms, give it another 1000ms
   108  	// and check again.
   109  	time.Sleep(30 * time.Millisecond)
   110  	var fail bool
   111  	for i := range count {
   112  		if atomic.LoadInt64(&count[i]) == 0 {
   113  			fail = true
   114  		}
   115  	}
   116  	if fail {
   117  		time.Sleep(1 * time.Second)
   118  		for i := range count {
   119  			if atomic.LoadInt64(&count[i]) == 0 {
   120  				fmt.Printf("goroutine %d did not run\n", i)
   121  				return
   122  			}
   123  		}
   124  	}
   125  	fmt.Println("OK")
   126  }