]> Cypherpunks.ru repositories - gostls13.git/blob - test/stress/runstress.go
all: make copyright headers consistent with one space after period
[gostls13.git] / test / stress / runstress.go
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 }