modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/stress/runstress.go (about) 1 // Copyright 2013 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 // The runstress tool stresses the runtime. 6 // 7 // It runs forever and should never fail. It tries to stress the garbage collector, 8 // maps, channels, the network, and everything else provided by the runtime. 9 package main 10 11 import ( 12 "flag" 13 "fmt" 14 "io" 15 "io/ioutil" 16 "log" 17 "math/rand" 18 "net" 19 "net/http" 20 "net/http/httptest" 21 "os/exec" 22 "strconv" 23 "time" 24 ) 25 26 var ( 27 v = flag.Bool("v", false, "verbose") 28 doMaps = flag.Bool("maps", true, "stress maps") 29 doExec = flag.Bool("exec", true, "stress exec") 30 doChan = flag.Bool("chan", true, "stress channels") 31 doNet = flag.Bool("net", true, "stress networking") 32 doParseGo = flag.Bool("parsego", true, "stress parsing Go (generates garbage)") 33 ) 34 35 func Println(a ...interface{}) { 36 if *v { 37 log.Println(a...) 38 } 39 } 40 41 func dialStress(a net.Addr) { 42 for { 43 d := net.Dialer{Timeout: time.Duration(rand.Intn(1e9))} 44 c, err := d.Dial("tcp", a.String()) 45 if err == nil { 46 Println("did dial") 47 go func() { 48 time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond) 49 c.Close() 50 Println("closed dial") 51 }() 52 } 53 // Don't run out of ephermeral ports too quickly: 54 time.Sleep(250 * time.Millisecond) 55 } 56 } 57 58 func stressNet() { 59 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 60 size, _ := strconv.Atoi(r.FormValue("size")) 61 w.Write(make([]byte, size)) 62 })) 63 go dialStress(ts.Listener.Addr()) 64 for { 65 size := rand.Intn(128 << 10) 66 res, err := http.Get(fmt.Sprintf("%s/?size=%d", ts.URL, size)) 67 if err != nil { 68 log.Fatalf("stressNet: http Get error: %v", err) 69 } 70 if res.StatusCode != 200 { 71 log.Fatalf("stressNet: Status code = %d", res.StatusCode) 72 } 73 n, err := io.Copy(ioutil.Discard, res.Body) 74 if err != nil { 75 log.Fatalf("stressNet: io.Copy: %v", err) 76 } 77 if n != int64(size) { 78 log.Fatalf("stressNet: copied = %d; want %d", n, size) 79 } 80 res.Body.Close() 81 Println("did http", size) 82 } 83 } 84 85 func doAnExec() { 86 exit := rand.Intn(2) 87 wantOutput := fmt.Sprintf("output-%d", rand.Intn(1e9)) 88 cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("echo %s; exit %d", wantOutput, exit)) 89 out, err := cmd.CombinedOutput() 90 if exit == 1 { 91 if err == nil { 92 log.Fatal("stressExec: unexpected exec success") 93 } 94 return 95 } 96 if err != nil { 97 log.Fatalf("stressExec: exec failure: %v: %s", err, out) 98 } 99 wantOutput += "\n" 100 if string(out) != wantOutput { 101 log.Fatalf("stressExec: exec output = %q; want %q", out, wantOutput) 102 } 103 Println("did exec") 104 } 105 106 func stressExec() { 107 gate := make(chan bool, 10) // max execs at once 108 for { 109 gate <- true 110 go func() { 111 doAnExec() 112 <-gate 113 }() 114 } 115 } 116 117 func ringf(in <-chan int, out chan<- int, donec chan bool) { 118 for { 119 var n int 120 select { 121 case <-donec: 122 return 123 case n = <-in: 124 } 125 if n == 0 { 126 close(donec) 127 return 128 } 129 out <- n - 1 130 } 131 } 132 133 func threadRing(bufsize int) { 134 const N = 100 135 donec := make(chan bool) 136 one := make(chan int, bufsize) // will be input to thread 1 137 var in, out chan int = nil, one 138 for i := 1; i <= N-1; i++ { 139 in, out = out, make(chan int, bufsize) 140 go ringf(in, out, donec) 141 } 142 go ringf(out, one, donec) 143 one <- N 144 <-donec 145 Println("did threadring of", bufsize) 146 } 147 148 func stressChannels() { 149 for { 150 threadRing(0) 151 threadRing(1) 152 } 153 } 154 155 func main() { 156 flag.Parse() 157 for want, f := range map[*bool]func(){ 158 doMaps: stressMaps, 159 doNet: stressNet, 160 doExec: stressExec, 161 doChan: stressChannels, 162 doParseGo: stressParseGo, 163 } { 164 if *want { 165 go f() 166 } 167 } 168 select {} 169 }