summaryrefslogtreecommitdiff
path: root/src/pkg/testing
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-08-03 16:54:30 +0200
committerOndřej Surý <ondrej@sury.org>2011-08-03 16:54:30 +0200
commit28592ee1ea1f5cdffcf85472f9de0285d928cf12 (patch)
tree32944e18b23f7fe4a0818a694aa2a6dfb1835463 /src/pkg/testing
parente836bee4716dc0d4d913537ad3ad1925a7ac32d0 (diff)
downloadgolang-upstream/59.tar.gz
Imported Upstream version 59upstream/59
Diffstat (limited to 'src/pkg/testing')
-rw-r--r--src/pkg/testing/benchmark.go54
-rw-r--r--src/pkg/testing/iotest/reader.go21
-rw-r--r--src/pkg/testing/testing.go72
3 files changed, 108 insertions, 39 deletions
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index f8b53e63a..3b416acfa 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/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.
@@ -172,7 +181,18 @@ func (r BenchmarkResult) String() string {
if mbs != 0 {
mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
}
- return fmt.Sprintf("%8d\t%10d ns/op%s", r.N, r.NsPerOp(), 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
@@ -182,7 +202,6 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
if len(*matchBenchmarks) == 0 {
return
}
- procs := runtime.GOMAXPROCS(-1)
for _, Benchmark := range benchmarks {
matched, err := matchString(*matchBenchmarks, Benchmark.Name)
if err != nil {
@@ -192,14 +211,19 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
if !matched {
continue
}
- b := &B{benchmark: Benchmark}
- r := b.run()
- print(fmt.Sprintf("%s\t%v\n", Benchmark.Name, r))
- if p := runtime.GOMAXPROCS(-1); p != procs {
- print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", Benchmark.Name, p))
- procs = p
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ b := &B{benchmark: Benchmark}
+ r := b.run()
+ benchName := Benchmark.Name
+ if procs != 1 {
+ benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
+ }
+ print(fmt.Sprintf("%s\t%v\n", benchName, r))
+ if p := runtime.GOMAXPROCS(-1); p != procs {
+ print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p))
+ }
}
-
}
}
diff --git a/src/pkg/testing/iotest/reader.go b/src/pkg/testing/iotest/reader.go
index e4003d744..daa6ede08 100644
--- a/src/pkg/testing/iotest/reader.go
+++ b/src/pkg/testing/iotest/reader.go
@@ -58,7 +58,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 +66,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/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 3b2dd377a..ba721523e 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/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.
@@ -157,6 +162,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()
@@ -171,7 +177,6 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern
if len(tests) == 0 {
println("testing: warning: no tests to run")
}
- procs := runtime.GOMAXPROCS(-1)
for i := 0; i < len(tests); i++ {
matched, err := matchString(*match, tests[i].Name)
if err != nil {
@@ -181,28 +186,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 p := runtime.GOMAXPROCS(-1); t.failed == false && p != procs {
- t.failed = true
- t.errors = fmt.Sprintf("%s left GOMAXPROCS set to %d\n", tests[i].Name, p)
- procs = p
- }
- 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 {
@@ -271,3 +282,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)
+ }
+ }
+}