mirror of
https://github.com/golang/go
synced 2024-09-06 00:19:45 +00:00
170 lines
3.6 KiB
Go
170 lines
3.6 KiB
Go
// 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"
|
|
"io/ioutil"
|
|
"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(ioutil.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 {}
|
|
}
|