Skip to content

Instantly share code, notes, and snippets.

@shasderias
Last active December 14, 2022 22:39
Show Gist options
  • Save shasderias/a94689999ce350c8963607f5cb43b44a to your computer and use it in GitHub Desktop.
Save shasderias/a94689999ce350c8963607f5cb43b44a to your computer and use it in GitHub Desktop.
Go Error Checking Performance
package errorperf
import (
"errors"
"fmt"
"math/rand"
"os"
"strconv"
)
var ErrInvalidInput = InvalidInputError{val: 1}
type InvalidInputError struct {
val int
}
func (e InvalidInputError) Error() string {
return fmt.Sprintf("%d", e.val)
}
func (e InvalidInputError) MyError() int {
return e.val
}
type MyError interface {
error
MyError() int
}
var nMax int
func init() {
var err error
nMax, err = strconv.Atoi(os.Getenv("N_MAX"))
if err != nil {
panic(err)
}
}
func ErrReturningFunc() error {
n := rand.Intn(nMax)
switch {
case n < 5:
return fmt.Errorf("error: %w", fmt.Errorf("error: %w", fmt.Errorf("error: %w", ErrInvalidInput)))
case n < 10:
return fmt.Errorf("error: %w", fmt.Errorf("error: %w", ErrInvalidInput))
case n < 15:
return fmt.Errorf("error: %w", ErrInvalidInput)
case n < 50:
return ErrInvalidInput
default:
return nil
}
}
func ErrCheckingFunc_Sentinel() int {
if err := ErrReturningFunc(); err != nil {
if err == ErrInvalidInput {
return 1
}
return 2
}
return 0
}
func ErrCheckingFunc_Assertion() int {
if err := ErrReturningFunc(); err != nil {
if _, ok := err.(InvalidInputError); ok {
return 1
}
return 2
}
return 0
}
func ErrCheckingFunc_Is() int {
if err := ErrReturningFunc(); err != nil {
if errors.Is(ErrReturningFunc(), ErrInvalidInput) {
return 1
}
return 2
}
return 0
}
func ErrCheckingFunc_As_Interface() int {
if err := ErrReturningFunc(); err != nil {
var myError MyError
if errors.As(ErrReturningFunc(), &myError) {
return 1
}
return 2
}
return 0
}
func ErrCheckingFunc_As_Concrete() int {
if err := ErrReturningFunc(); err != nil {
var invalInputErr InvalidInputError
if errors.As(ErrReturningFunc(), &invalInputErr) {
return 1
}
return 2
}
return 0
}
package errorperf
import "testing"
func BenchmarkErrCheckingFunc_Sentinel(b *testing.B) {
for i := 0; i < b.N; i++ {
ErrCheckingFunc_Sentinel()
}
}
func BenchmarkErrCheckingFunc_Assertion(b *testing.B) {
for i := 0; i < b.N; i++ {
ErrCheckingFunc_Assertion()
}
}
func BenchmarkErrCheckingFunc_Is(b *testing.B) {
for i := 0; i < b.N; i++ {
ErrCheckingFunc_Is()
}
}
func BenchmarkErrCheckingFunc_As_Concrete(b *testing.B) {
for i := 0; i < b.N; i++ {
ErrCheckingFunc_As_Concrete()
}
}
func BenchmarkErrCheckingFunc_As_Interface(b *testing.B) {
for i := 0; i < b.N; i++ {
ErrCheckingFunc_As_Interface()
}
}
C:\dev\sandbox\errorperf>set N_MAX=100
C:\dev\sandbox\errorperf>go test -bench .
goos: windows
goarch: amd64
pkg: sandbox/errorperf
cpu: AMD Ryzen 9 3900X 12-Core Processor
BenchmarkErrCheckingFunc_Sentinel-24 12766431 92.51 ns/op
BenchmarkErrCheckingFunc_Assertion-24 12698238 94.82 ns/op
BenchmarkErrCheckingFunc_Is-24 8108030 149.0 ns/op
BenchmarkErrCheckingFunc_As_Concrete-24 6106879 193.0 ns/op
BenchmarkErrCheckingFunc_As_Interface-24 5393304 220.1 ns/op
PASS
ok sandbox/errorperf 6.919s
C:\dev\sandbox\errorperf>set N_MAX=1000
C:\dev\sandbox\errorperf>go test -bench .
goos: windows
goarch: amd64
pkg: sandbox/errorperf
cpu: AMD Ryzen 9 3900X 12-Core Processor
BenchmarkErrCheckingFunc_Sentinel-24 55815250 20.25 ns/op
BenchmarkErrCheckingFunc_Assertion-24 60001500 20.36 ns/op
BenchmarkErrCheckingFunc_Is-24 53334518 22.46 ns/op
BenchmarkErrCheckingFunc_As_Concrete-24 46156686 25.67 ns/op
BenchmarkErrCheckingFunc_As_Interface-24 47059191 24.39 ns/op
PASS
ok sandbox/errorperf 6.211s
C:\dev\sandbox\errorperf>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment