github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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  func workthegc() []byte {
    52  	return make([]byte, 1029)
    53  }
    54  
    55  func GCFairness() {
    56  	runtime.GOMAXPROCS(1)
    57  	f, err := os.Open("/dev/null")
    58  	if os.IsNotExist(err) {
    59  		// This test tests what it is intended to test only if writes are fast.
    60  		// If there is no /dev/null, we just don't execute the test.
    61  		fmt.Println("OK")
    62  		return
    63  	}
    64  	if err != nil {
    65  		fmt.Println(err)
    66  		os.Exit(1)
    67  	}
    68  	for i := 0; i < 2; i++ {
    69  		go func() {
    70  			for {
    71  				f.Write([]byte("."))
    72  			}
    73  		}()
    74  	}
    75  	time.Sleep(10 * time.Millisecond)
    76  	fmt.Println("OK")
    77  }
    78  
    79  func GCFairness2() {
    80  	// Make sure user code can't exploit the GC's high priority
    81  	// scheduling to make scheduling of user code unfair. See
    82  	// issue #15706.
    83  	runtime.GOMAXPROCS(1)
    84  	debug.SetGCPercent(1)
    85  	var count [3]int64
    86  	var sink [3]interface{}
    87  	for i := range count {
    88  		go func(i int) {
    89  			for {
    90  				sink[i] = make([]byte, 1024)
    91  				atomic.AddInt64(&count[i], 1)
    92  			}
    93  		}(i)
    94  	}
    95  	// Note: If the unfairness is really bad, it may not even get
    96  	// past the sleep.
    97  	//
    98  	// If the scheduling rules change, this may not be enough time
    99  	// to let all goroutines run, but for now we cycle through
   100  	// them rapidly.
   101  	//
   102  	// OpenBSD's scheduler makes every usleep() take at least
   103  	// 20ms, so we need a long time to ensure all goroutines have
   104  	// run. If they haven't run after 30ms, give it another 1000ms
   105  	// and check again.
   106  	time.Sleep(30 * time.Millisecond)
   107  	var fail bool
   108  	for i := range count {
   109  		if atomic.LoadInt64(&count[i]) == 0 {
   110  			fail = true
   111  		}
   112  	}
   113  	if fail {
   114  		time.Sleep(1 * time.Second)
   115  		for i := range count {
   116  			if atomic.LoadInt64(&count[i]) == 0 {
   117  				fmt.Printf("goroutine %d did not run\n", i)
   118  				return
   119  			}
   120  		}
   121  	}
   122  	fmt.Println("OK")
   123  }