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