github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/_vendor/src/golang.org/x/tools/cmd/stress/stress.go (about)

     1  // Copyright 2015 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  // +build !plan9
     6  
     7  // The stress utility is intended for catching sporadic failures.
     8  // It runs a given process in parallel in a loop and collects any failures.
     9  // Usage:
    10  // 	$ stress ./fmt.test -test.run=TestSometing -test.cpu=10
    11  // You can also specify a number of parallel processes with -p flag;
    12  // instruct the utility to not kill hanged processes for gdb attach;
    13  // or specify the failure output you are looking for (if you want to
    14  // ignore some other sporadic failures).
    15  package main
    16  
    17  import (
    18  	"flag"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"os"
    22  	"os/exec"
    23  	"regexp"
    24  	"runtime"
    25  	"syscall"
    26  	"time"
    27  )
    28  
    29  var (
    30  	flagP       = flag.Int("p", runtime.NumCPU(), "run `N` processes in parallel")
    31  	flagTimeout = flag.Duration("timeout", 10*time.Minute, "timeout each process after `duration`")
    32  	flagKill    = flag.Bool("kill", true, "kill timed out processes if true, otherwise just print pid (to attach with gdb)")
    33  	flagFailure = flag.String("failure", "", "fail only if output matches `regexp`")
    34  	flagIgnore  = flag.String("ignore", "", "ignore failure if output matches `regexp`")
    35  )
    36  
    37  func init() {
    38  	flag.Usage = func() {
    39  		os.Stderr.WriteString(`The stress utility is intended for catching sporadic failures.
    40  It runs a given process in parallel in a loop and collects any failures.
    41  Usage:
    42  
    43  	$ stress ./fmt.test -test.run=TestSometing -test.cpu=10
    44  
    45  `)
    46  		flag.PrintDefaults()
    47  	}
    48  }
    49  
    50  func main() {
    51  	flag.Parse()
    52  	if *flagP <= 0 || *flagTimeout <= 0 || len(flag.Args()) == 0 {
    53  		flag.Usage()
    54  		os.Exit(1)
    55  	}
    56  	var failureRe, ignoreRe *regexp.Regexp
    57  	if *flagFailure != "" {
    58  		var err error
    59  		if failureRe, err = regexp.Compile(*flagFailure); err != nil {
    60  			fmt.Println("bad failure regexp:", err)
    61  			os.Exit(1)
    62  		}
    63  	}
    64  	if *flagIgnore != "" {
    65  		var err error
    66  		if ignoreRe, err = regexp.Compile(*flagIgnore); err != nil {
    67  			fmt.Println("bad ignore regexp:", err)
    68  			os.Exit(1)
    69  		}
    70  	}
    71  	res := make(chan []byte)
    72  	for i := 0; i < *flagP; i++ {
    73  		go func() {
    74  			for {
    75  				cmd := exec.Command(flag.Args()[0], flag.Args()[1:]...)
    76  				done := make(chan bool)
    77  				if *flagTimeout > 0 {
    78  					go func() {
    79  						select {
    80  						case <-done:
    81  							return
    82  						case <-time.After(*flagTimeout):
    83  						}
    84  						if !*flagKill {
    85  							fmt.Printf("process %v timed out\n", cmd.Process.Pid)
    86  							return
    87  						}
    88  						cmd.Process.Signal(syscall.SIGABRT)
    89  						select {
    90  						case <-done:
    91  							return
    92  						case <-time.After(10 * time.Second):
    93  						}
    94  						cmd.Process.Kill()
    95  					}()
    96  				}
    97  				out, err := cmd.CombinedOutput()
    98  				close(done)
    99  				if err != nil && (failureRe == nil || failureRe.Match(out)) && (ignoreRe == nil || !ignoreRe.Match(out)) {
   100  					out = append(out, fmt.Sprintf("\n\nERROR: %v\n", err)...)
   101  				} else {
   102  					out = []byte{}
   103  				}
   104  				res <- out
   105  			}
   106  		}()
   107  	}
   108  	runs, fails := 0, 0
   109  	ticker := time.NewTicker(5 * time.Second).C
   110  	for {
   111  		select {
   112  		case out := <-res:
   113  			runs++
   114  			if len(out) == 0 {
   115  				continue
   116  			}
   117  			fails++
   118  			f, err := ioutil.TempFile("", "go-stress")
   119  			if err != nil {
   120  				fmt.Printf("failed to create temp file: %v\n", err)
   121  				os.Exit(1)
   122  			}
   123  			f.Write(out)
   124  			f.Close()
   125  			if len(out) > 2<<10 {
   126  				out = out[:2<<10]
   127  			}
   128  			fmt.Printf("\n%s\n%s\n", f.Name(), out)
   129  		case <-ticker:
   130  			fmt.Printf("%v runs so far, %v failures\n", runs, fails)
   131  		}
   132  	}
   133  }