diff options
Diffstat (limited to '')
-rw-r--r-- | test/stress/runstress.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/test/stress/runstress.go b/test/stress/runstress.go new file mode 100644 index 0000000..b752fa8 --- /dev/null +++ b/test/stress/runstress.go @@ -0,0 +1,168 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The runstress tool stresses the runtime. +// +// It runs forever and should never fail. It tries to stress the garbage collector, +// maps, channels, the network, and everything else provided by the runtime. +package main + +import ( + "flag" + "fmt" + "io" + "log" + "math/rand" + "net" + "net/http" + "net/http/httptest" + "os/exec" + "strconv" + "time" +) + +var ( + v = flag.Bool("v", false, "verbose") + doMaps = flag.Bool("maps", true, "stress maps") + doExec = flag.Bool("exec", true, "stress exec") + doChan = flag.Bool("chan", true, "stress channels") + doNet = flag.Bool("net", true, "stress networking") + doParseGo = flag.Bool("parsego", true, "stress parsing Go (generates garbage)") +) + +func Println(a ...interface{}) { + if *v { + log.Println(a...) + } +} + +func dialStress(a net.Addr) { + for { + d := net.Dialer{Timeout: time.Duration(rand.Intn(1e9))} + c, err := d.Dial("tcp", a.String()) + if err == nil { + Println("did dial") + go func() { + time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond) + c.Close() + Println("closed dial") + }() + } + // Don't run out of ephermeral ports too quickly: + time.Sleep(250 * time.Millisecond) + } +} + +func stressNet() { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + size, _ := strconv.Atoi(r.FormValue("size")) + w.Write(make([]byte, size)) + })) + go dialStress(ts.Listener.Addr()) + for { + size := rand.Intn(128 << 10) + res, err := http.Get(fmt.Sprintf("%s/?size=%d", ts.URL, size)) + if err != nil { + log.Fatalf("stressNet: http Get error: %v", err) + } + if res.StatusCode != 200 { + log.Fatalf("stressNet: Status code = %d", res.StatusCode) + } + n, err := io.Copy(io.Discard, res.Body) + if err != nil { + log.Fatalf("stressNet: io.Copy: %v", err) + } + if n != int64(size) { + log.Fatalf("stressNet: copied = %d; want %d", n, size) + } + res.Body.Close() + Println("did http", size) + } +} + +func doAnExec() { + exit := rand.Intn(2) + wantOutput := fmt.Sprintf("output-%d", rand.Intn(1e9)) + cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("echo %s; exit %d", wantOutput, exit)) + out, err := cmd.CombinedOutput() + if exit == 1 { + if err == nil { + log.Fatal("stressExec: unexpected exec success") + } + return + } + if err != nil { + log.Fatalf("stressExec: exec failure: %v: %s", err, out) + } + wantOutput += "\n" + if string(out) != wantOutput { + log.Fatalf("stressExec: exec output = %q; want %q", out, wantOutput) + } + Println("did exec") +} + +func stressExec() { + gate := make(chan bool, 10) // max execs at once + for { + gate <- true + go func() { + doAnExec() + <-gate + }() + } +} + +func ringf(in <-chan int, out chan<- int, donec chan bool) { + for { + var n int + select { + case <-donec: + return + case n = <-in: + } + if n == 0 { + close(donec) + return + } + out <- n - 1 + } +} + +func threadRing(bufsize int) { + const N = 100 + donec := make(chan bool) + one := make(chan int, bufsize) // will be input to thread 1 + var in, out chan int = nil, one + for i := 1; i <= N-1; i++ { + in, out = out, make(chan int, bufsize) + go ringf(in, out, donec) + } + go ringf(out, one, donec) + one <- N + <-donec + Println("did threadring of", bufsize) +} + +func stressChannels() { + for { + threadRing(0) + threadRing(1) + } +} + +func main() { + flag.Parse() + for want, f := range map[*bool]func(){ + doMaps: stressMaps, + doNet: stressNet, + doExec: stressExec, + doChan: stressChannels, + doParseGo: stressParseGo, + } { + if *want { + go f() + } + } + select {} +} |