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 }