]> Cypherpunks repositories - gostls13.git/commitdiff
errors: record only single frame
authorMarcel van Lohuizen <mpvl@golang.org>
Wed, 13 Mar 2019 11:24:54 +0000 (12:24 +0100)
committerMarcel van Lohuizen <mpvl@golang.org>
Thu, 14 Mar 2019 09:31:05 +0000 (09:31 +0000)
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 <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
src/errors/frame.go
src/errors/frame_test.go

index a5369e5c3693155b800ff01a84aa895143a2b82b..487092fa892328237cb838bf5bc6533f9b868421 100644 (file)
@@ -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
 }
 
index 864a6934d1a3c1ef7a4396923400668f98a1a70c..ba08166966777f566a4b4b8cf51f9443ed7cb23c 100644 (file)
@@ -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) {