From 5402854c3557f87fa2741a52ffc15dfb1ef333cc Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Wed, 13 Mar 2019 12:24:54 +0100 Subject: [PATCH] errors: record only single frame MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit See Issue #29382 and Issue #30468. 3 frames are no longer needed as of https://go-review.googlesource.com/c/go/+/152537/ name old time/op new time/op delta New-8 475ns ± 3% 352ns ± 2% -25.87% (p=0.008 n=5+5) Errorf/no_format-8 661ns ± 4% 558ns ± 2% -15.63% (p=0.008 n=5+5) Errorf/with_format-8 729ns ± 6% 626ns ± 2% -14.23% (p=0.008 n=5+5) Errorf/method:_mytype-8 1.00µs ± 9% 0.84µs ± 2% -15.94% (p=0.008 n=5+5) Errorf/method:_number-8 1.25µs ± 7% 1.04µs ± 2% -16.38% (p=0.008 n=5+5) Change-Id: I30377e769b3b3be623f63ecbe365f8950ca08dda Reviewed-on: https://go-review.googlesource.com/c/go/+/167400 Run-TryBot: Marcel van Lohuizen TryBot-Result: Gobot Gobot Reviewed-by: Damien Neil --- src/errors/frame.go | 15 +++------------ src/errors/frame_test.go | 31 +++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/errors/frame.go b/src/errors/frame.go index a5369e5c36..487092fa89 100644 --- a/src/errors/frame.go +++ b/src/errors/frame.go @@ -10,10 +10,7 @@ import ( // A Frame contains part of a call stack. type Frame struct { - // Make room for three PCs: the one we were asked for, what it called, - // and possibly a PC for skipPleaseUseCallersFrames. See: - // https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169 - frames [3]uintptr + frames [1]uintptr } // Caller returns a Frame that describes a frame on the caller's stack. @@ -21,7 +18,7 @@ type Frame struct { // Caller(0) returns the frame for the caller of Caller. func Caller(skip int) Frame { var s Frame - runtime.Callers(skip+1, s.frames[:]) + runtime.Callers(skip+2, s.frames[:]) return s } @@ -30,13 +27,7 @@ func Caller(skip int) Frame { // The returned function may be "" even if file and line are not. func (f Frame) location() (function, file string, line int) { frames := runtime.CallersFrames(f.frames[:]) - if _, ok := frames.Next(); !ok { - return "", "", 0 - } - fr, ok := frames.Next() - if !ok { - return "", "", 0 - } + fr, _ := frames.Next() return fr.Function, fr.File, fr.Line } diff --git a/src/errors/frame_test.go b/src/errors/frame_test.go index 864a6934d1..ba08166966 100644 --- a/src/errors/frame_test.go +++ b/src/errors/frame_test.go @@ -9,19 +9,42 @@ import ( "errors" "fmt" "math/big" + "regexp" + "strings" "testing" ) +func TestFrame(t *testing.T) { + + // Extra line + got := fmt.Sprintf("%+v", errors.New("Test")) + got = got[strings.Index(got, "Test"):] + const want = "^Test:" + + "\n errors_test.TestFrame" + + "\n .*/errors/frame_test.go:20$" + ok, err := regexp.MatchString(want, got) + if err != nil { + t.Fatal(err) + } + if !ok { + t.Errorf("\n got %v;\nwant %v", got, want) + } +} + type myType struct{} func (myType) Format(s fmt.State, v rune) { s.Write(bytes.Repeat([]byte("Hi! "), 10)) } +func BenchmarkNew(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = errors.New("new error") + } +} + func BenchmarkErrorf(b *testing.B) { err := errors.New("foo") - // pi := big.NewFloat(3.14) // Something expensive. - num := big.NewInt(5) args := func(a ...interface{}) []interface{} { return a } benchCases := []struct { name string @@ -30,8 +53,8 @@ func BenchmarkErrorf(b *testing.B) { }{ {"no_format", "msg: %v", args(err)}, {"with_format", "failed %d times: %v", args(5, err)}, - {"method: mytype", "pi: %v", args("myfile.go", myType{}, err)}, - {"method: number", "pi: %v", args("myfile.go", num, err)}, + {"method: mytype", "pi %s %v: %v", args("myfile.go", myType{}, err)}, + {"method: number", "pi %s %d: %v", args("myfile.go", big.NewInt(5), err)}, } for _, bc := range benchCases { b.Run(bc.name, func(b *testing.B) { -- 2.48.1