Skip to content
Permalink
Browse files

Benchmarks, performance optimisation

  • Loading branch information...
ztrue committed Feb 16, 2019
1 parent 667f25c commit 6d78a876eb9985d05110fd8750f75509d261c56f
Showing with 70 additions and 5 deletions.
  1. +11 −0 CHANGELOG.md
  2. +4 −0 Makefile
  3. +15 −0 README.md
  4. +6 −1 error.go
  5. +34 −0 error_bench_test.go
  6. +0 −1 examples/existing_error.go
  7. +0 −1 examples/new_error.go
  8. +0 −1 examples/save_log.go
  9. +0 −1 examples/stack_trace.go
@@ -1,5 +1,16 @@
# Changelog

## [0.2.1] - 2019-02-16

### Added

- Benchmarks.
- `DefaultCap` variable for performance tuning purposes.

### Changed

- Stack trace performance optimisation.

## [0.2.0] - 2019-02-15

### Added
@@ -21,3 +21,7 @@ coverage:
go test -coverprofile=coverage.out && \
go tool cover -func=coverage.out && \
go tool cover -html=coverage.out

.PHONY: bench
bench:
GOMAXPROCS=1 go test -bench=. -benchmem
@@ -156,3 +156,18 @@ Or if `err` is of type `*tracerr.Error`:
```go
err = err.Unwrap()
```

## Performance

Stack trace causes a performance overhead, depending on a stack trace depth. This can be insignificant in a number of situations (such as HTTP request handling), however, avoid of adding a stack trace for really hot spots where a high number of errors created frequently, this can be inefficient.

> Benchmarks done on a MacBook Pro 2015 with go 1.11.
Benchmarks for creation a new error with a stack trace of different depth:

```
BenchmarkNew/5 200000 5646 ns/op 976 B/op 4 allocs/op
BenchmarkNew/10 200000 11565 ns/op 976 B/op 4 allocs/op
BenchmarkNew/20 50000 25629 ns/op 976 B/op 4 allocs/op
BenchmarkNew/40 20000 65833 ns/op 2768 B/op 5 allocs/op
```
@@ -9,6 +9,11 @@ import (
"runtime"
)

// DefaultCap is a default cap for frames array.
// It can be changed to number of expected frames
// for purpose of performance optimisation.
var DefaultCap = 20

// Error is an error with stack trace.
type Error struct {
// Error contains original error.
@@ -99,7 +104,7 @@ func (f Frame) String() string {
}

func trace(err error, skip int) *Error {
var frames []Frame
frames := make([]Frame, 0, DefaultCap)
for {
pc, path, line, ok := runtime.Caller(skip)
if !ok {
@@ -0,0 +1,34 @@
package tracerr_test

import (
"fmt"
"testing"

"github.com/ztrue/tracerr"
)

func BenchmarkNew(b *testing.B) {
for _, frames := range []int{5, 10, 20, 40} {
suffix := fmt.Sprintf("%d", frames)
b.Run(suffix, func(b *testing.B) {
err := tracerr.New("")
// Reduce by number of parent frames in order to have a correct depth.
depth := frames - len(err.StackTrace())
if depth < 1 {
panic("number of frames is negative")
}
b.ResetTimer()

for i := 0; i < b.N; i++ {
addFrames(depth, "test error")
}
})
}
}

func addFrames(depth int, message string) *tracerr.Error {
if depth <= 1 {
return tracerr.New(message)
}
return addFrames(depth-1, message)
}
@@ -4,7 +4,6 @@ import (
"io/ioutil"

"github.com/ztrue/tracerr"
// "../../tracerr"
)

func main() {
@@ -2,7 +2,6 @@ package main

import (
"github.com/ztrue/tracerr"
// "../../tracerr"
)

func main() {
@@ -4,7 +4,6 @@ import (
"io/ioutil"

"github.com/ztrue/tracerr"
// "../../tracerr"
)

func main() {
@@ -5,7 +5,6 @@ import (
"io/ioutil"

"github.com/ztrue/tracerr"
// "../../tracerr"
)

func main() {

0 comments on commit 6d78a87

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.