1// +build go1.7
2
3package errors
4
5import (
6	"fmt"
7	"testing"
8
9	stderrors "errors"
10)
11
12func noErrors(at, depth int) error {
13	if at >= depth {
14		return stderrors.New("no error")
15	}
16	return noErrors(at+1, depth)
17}
18
19func yesErrors(at, depth int) error {
20	if at >= depth {
21		return New("ye error")
22	}
23	return yesErrors(at+1, depth)
24}
25
26// GlobalE is an exported global to store the result of benchmark results,
27// preventing the compiler from optimising the benchmark functions away.
28var GlobalE interface{}
29
30func BenchmarkErrors(b *testing.B) {
31	type run struct {
32		stack int
33		std   bool
34	}
35	runs := []run{
36		{10, false},
37		{10, true},
38		{100, false},
39		{100, true},
40		{1000, false},
41		{1000, true},
42	}
43	for _, r := range runs {
44		part := "pkg/errors"
45		if r.std {
46			part = "errors"
47		}
48		name := fmt.Sprintf("%s-stack-%d", part, r.stack)
49		b.Run(name, func(b *testing.B) {
50			var err error
51			f := yesErrors
52			if r.std {
53				f = noErrors
54			}
55			b.ReportAllocs()
56			for i := 0; i < b.N; i++ {
57				err = f(0, r.stack)
58			}
59			b.StopTimer()
60			GlobalE = err
61		})
62	}
63}
64
65func BenchmarkStackFormatting(b *testing.B) {
66	type run struct {
67		stack  int
68		format string
69	}
70	runs := []run{
71		{10, "%s"},
72		{10, "%v"},
73		{10, "%+v"},
74		{30, "%s"},
75		{30, "%v"},
76		{30, "%+v"},
77		{60, "%s"},
78		{60, "%v"},
79		{60, "%+v"},
80	}
81
82	var stackStr string
83	for _, r := range runs {
84		name := fmt.Sprintf("%s-stack-%d", r.format, r.stack)
85		b.Run(name, func(b *testing.B) {
86			err := yesErrors(0, r.stack)
87			b.ReportAllocs()
88			b.ResetTimer()
89			for i := 0; i < b.N; i++ {
90				stackStr = fmt.Sprintf(r.format, err)
91			}
92			b.StopTimer()
93		})
94	}
95
96	for _, r := range runs {
97		name := fmt.Sprintf("%s-stacktrace-%d", r.format, r.stack)
98		b.Run(name, func(b *testing.B) {
99			err := yesErrors(0, r.stack)
100			st := err.(*fundamental).stack.StackTrace()
101			b.ReportAllocs()
102			b.ResetTimer()
103			for i := 0; i < b.N; i++ {
104				stackStr = fmt.Sprintf(r.format, st)
105			}
106			b.StopTimer()
107		})
108	}
109	GlobalE = stackStr
110}
111