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

View as plain text