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 }