github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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  }