From adb0401dac41c81571722312d4586b2693f95aa6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 16 Sep 2011 15:47:21 +0000 Subject: Update Go library to r60. From-SVN: r178910 --- libgo/go/testing/benchmark.go | 67 ++++++++++++++++++++++++++++++--------- libgo/go/testing/iotest/reader.go | 22 +++++++++++-- libgo/go/testing/testing.go | 67 ++++++++++++++++++++++++++++----------- 3 files changed, 121 insertions(+), 35 deletions(-) (limited to 'libgo/go/testing') diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go index cf73e2b..fd0bd86 100644 --- a/libgo/go/testing/benchmark.go +++ b/libgo/go/testing/benchmark.go @@ -13,6 +13,7 @@ import ( ) var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run") +var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds") // An internal type but exported because it is cross-package; part of the implementation // of gotest. @@ -34,7 +35,11 @@ type B struct { // StartTimer starts timing a test. This function is called automatically // before a benchmark starts, but it can also used to resume timing after // a call to StopTimer. -func (b *B) StartTimer() { b.start = time.Nanoseconds() } +func (b *B) StartTimer() { + if b.start == 0 { + b.start = time.Nanoseconds() + } +} // StopTimer stops timing a test. This can be used to pause the timer // while performing complex initialization that you don't @@ -46,9 +51,12 @@ func (b *B) StopTimer() { b.start = 0 } -// ResetTimer stops the timer and sets the elapsed benchmark time to zero. +// ResetTimer sets the elapsed benchmark time to zero. +// It does not affect whether the timer is running. func (b *B) ResetTimer() { - b.start = 0 + if b.start > 0 { + b.start = time.Nanoseconds() + } b.ns = 0 } @@ -125,14 +133,15 @@ func (b *B) run() BenchmarkResult { // Run the benchmark for a single iteration in case it's expensive. n := 1 b.runN(n) - // Run the benchmark for at least a second. - for b.ns < 1e9 && n < 1e9 { + // Run the benchmark for at least the specified amount of time. + time := int64(*benchTime * 1e9) + for b.ns < time && n < 1e9 { last := n // Predict iterations/sec. if b.nsPerOp() == 0 { n = 1e9 } else { - n = 1e9 / int(b.nsPerOp()) + n = int(time / b.nsPerOp()) } // Run more iterations than we think we'll need for a second (1.5x). // Don't grow too fast in case we had timing errors previously. @@ -143,14 +152,13 @@ func (b *B) run() BenchmarkResult { b.runN(n) } return BenchmarkResult{b.N, b.ns, b.bytes} - } // The results of a benchmark run. type BenchmarkResult struct { N int // The number of iterations. Ns int64 // The total time taken. - Bytes int64 // The total number of bytes processed. + Bytes int64 // Bytes processed in one iteration. } func (r BenchmarkResult) NsPerOp() int64 { @@ -160,13 +168,31 @@ func (r BenchmarkResult) NsPerOp() int64 { return r.Ns / int64(r.N) } +func (r BenchmarkResult) mbPerSec() float64 { + if r.Bytes <= 0 || r.Ns <= 0 || r.N <= 0 { + return 0 + } + return float64(r.Bytes) * float64(r.N) / float64(r.Ns) * 1e3 +} + func (r BenchmarkResult) String() string { - ns := r.NsPerOp() + mbs := r.mbPerSec() mb := "" - if ns > 0 && r.Bytes > 0 { - mb = fmt.Sprintf("\t%7.2f MB/s", (float64(r.Bytes)/1e6)/(float64(ns)/1e9)) + if mbs != 0 { + mb = fmt.Sprintf("\t%7.2f MB/s", mbs) } - return fmt.Sprintf("%8d\t%10d ns/op%s", r.N, ns, mb) + nsop := r.NsPerOp() + ns := fmt.Sprintf("%10d ns/op", nsop) + if r.N > 0 && nsop < 100 { + // The format specifiers here make sure that + // the ones digits line up for all three possible formats. + if nsop < 10 { + ns = fmt.Sprintf("%13.2f ns/op", float64(r.Ns)/float64(r.N)) + } else { + ns = fmt.Sprintf("%12.1f ns/op", float64(r.Ns)/float64(r.N)) + } + } + return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb) } // An internal function but exported because it is cross-package; part of the implementation @@ -185,9 +211,20 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark if !matched { continue } - b := &B{benchmark: Benchmark} - r := b.run() - fmt.Printf("%s\t%v\n", Benchmark.Name, r) + for _, procs := range cpuList { + runtime.GOMAXPROCS(procs) + b := &B{benchmark: Benchmark} + benchName := Benchmark.Name + if procs != 1 { + benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs) + } + print(fmt.Sprintf("%s\t", benchName)) + r := b.run() + print(fmt.Sprintf("%v\n", r)) + if p := runtime.GOMAXPROCS(-1); p != procs { + print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p)) + } + } } } diff --git a/libgo/go/testing/iotest/reader.go b/libgo/go/testing/iotest/reader.go index e4003d7..dcf5565 100644 --- a/libgo/go/testing/iotest/reader.go +++ b/libgo/go/testing/iotest/reader.go @@ -37,7 +37,6 @@ func (r *halfReader) Read(p []byte) (int, os.Error) { return r.r.Read(p[0 : (len(p)+1)/2]) } - // DataErrReader returns a Reader that returns the final // error with the last data read, instead of by itself with // zero bytes of data. @@ -58,7 +57,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) { r.unread = r.data[0:n1] err = err1 } - if n > 0 { + if n > 0 || err != nil { break } n = copy(p, r.unread) @@ -66,3 +65,22 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) { } return } + +var ErrTimeout = os.NewError("timeout") + +// TimeoutReader returns ErrTimeout on the second read +// with no data. Subsequent calls to read succeed. +func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} } + +type timeoutReader struct { + r io.Reader + count int +} + +func (r *timeoutReader) Read(p []byte) (int, os.Error) { + r.count++ + if r.count == 2 { + return 0, ErrTimeout + } + return r.r.Read(p) +} diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index 8781b20..ec4a453 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -44,6 +44,8 @@ import ( "os" "runtime" "runtime/pprof" + "strings" + "strconv" "time" ) @@ -62,6 +64,9 @@ var ( memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate") cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution") timeout = flag.Int64("test.timeout", 0, "if > 0, sets time limit for tests in seconds") + cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test") + + cpuList []int ) // Short reports whether the -test.short flag is set. @@ -69,7 +74,6 @@ func Short() bool { return *short } - // Insert final newline if needed and tabs after internal newlines. func tabify(s string) string { n := len(s) @@ -157,6 +161,7 @@ func tRunner(t *T, test *InternalTest) { // of gotest. func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest, benchmarks []InternalBenchmark) { flag.Parse() + parseCpuList() before() startAlarm() @@ -180,23 +185,34 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern if !matched { continue } - if *chatty { - println("=== RUN ", tests[i].Name) - } - ns := -time.Nanoseconds() - t := new(T) - t.ch = make(chan *T) - go tRunner(t, &tests[i]) - <-t.ch - ns += time.Nanoseconds() - tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9) - if t.failed { - println("--- FAIL:", tests[i].Name, tstr) - print(t.errors) - ok = false - } else if *chatty { - println("--- PASS:", tests[i].Name, tstr) - print(t.errors) + for _, procs := range cpuList { + runtime.GOMAXPROCS(procs) + testName := tests[i].Name + if procs != 1 { + testName = fmt.Sprintf("%s-%d", tests[i].Name, procs) + } + if *chatty { + println("=== RUN ", testName) + } + ns := -time.Nanoseconds() + t := new(T) + t.ch = make(chan *T) + go tRunner(t, &tests[i]) + <-t.ch + ns += time.Nanoseconds() + tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9) + if p := runtime.GOMAXPROCS(-1); t.failed == false && p != procs { + t.failed = true + t.errors = fmt.Sprintf("%s left GOMAXPROCS set to %d\n", testName, p) + } + if t.failed { + println("--- FAIL:", testName, tstr) + print(t.errors) + ok = false + } else if *chatty { + println("--- PASS:", testName, tstr) + print(t.errors) + } } } if !ok { @@ -265,3 +281,18 @@ func stopAlarm() { func alarm() { panic("test timed out") } + +func parseCpuList() { + if len(*cpuListStr) == 0 { + cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) + } else { + for _, val := range strings.Split(*cpuListStr, ",") { + cpu, err := strconv.Atoi(val) + if err != nil || cpu <= 0 { + println("invalid value for -test.cpu") + os.Exit(1) + } + cpuList = append(cpuList, cpu) + } + } +} -- cgit v1.1