Type Assertion perfomance

From this question on Stackoverflow on assertion performance.

I also made my own testing using Go 1.9, But this two test intrigues me.

func incnAssertion(any Inccer, n int) {
	for k := 0; k < n; k++ {
		if newint, ok := any.(*myint); ok {
			newint.inc()
		}
	}
}

func incnAssertionNoCheck(any Inccer, n int) {
	for k := 0; k < n; k++ {
		any.(*myint).inc()
	}
}

And got this results

BenchmarkTypeAssertion-4          	1000000000	         2.13 ns/op
BenchmarkTypeAssertionNoCheck-4   	1000000000	         2.39 ns/op

I was expecting that incnAssertionNoCheck will be faster because it doesn’t do checking. So it will just run faster but can go panic if passed an invalid type.

Is there something I missed here? Why adding if statement makes it much faster? Because on my understanding adding the if statement adds an operation.

Thanks

You can look at the assembly for the full truth. But guessing wildly just based on your benchmark without doing any research at all I can imagine that the

any.(*myint).inc()

in fact compiles to something roughly equivalent to

_tmp, ok := any.(*myint)
if !ok {
    panic("assertion failure")
}
_tmp.inc()

that is, if you’re not doing the check, someone needs to do it in the end anyway in order to verify that the assertion passes or raise the appropriate panic. Maybe the fact that it can panic either makes something less inline-able, requires some further setup (figuring out the panic message, maybe), or changes the branch prediction to make it those 0.2 nanoseconds slower…

All in all what you’ve shown is that it doesn’t matter from a performance point of view, which is nice.

1 Like

:sweat_smile: you got me there, but I am not still good at reading assembly.

Me neither, so I’m good with the conclusion that the difference is small enough to not matter.

1 Like

My guess is your benchmark is being mostly optimised away.

Do you mean optimized by the language itself?

By the compiler, yes. Can you post a complete benchmark example.

Here it is

package main_test

import (
	"testing"
)

type myint int64

type Inccer interface {
	inc()
}

func (i *myint) inc() {
	*i = *i + 1
}

func incnIntmethod(i *myint, n int) {
	for k := 0; k < n; k++ {
		i.inc()
	}
}

func incnInterface(any Inccer, n int) {
	for k := 0; k < n; k++ {
		any.inc()
	}
}

func incnSwitch(any Inccer, n int) {
	for k := 0; k < n; k++ {
		switch v := any.(type) {
		case *myint:
			v.inc()
		}
	}
}

func incnAssertion(any Inccer, n int) {
	for k := 0; k < n; k++ {
		if newint, ok := any.(*myint); ok {
			newint.inc()
		}
	}
}

func incnAssertionNoCheck(any Inccer, n int) {
	for k := 0; k < n; k++ {
		any.(*myint).inc()
	}
}

func BenchmarkIntmethod(b *testing.B) {
	i := new(myint)
	incnIntmethod(i, b.N)
}

func BenchmarkInterface(b *testing.B) {
	i := new(myint)
	incnInterface(i, b.N)
}

func BenchmarkTypeSwitch(b *testing.B) {
	i := new(myint)
	incnSwitch(i, b.N)
}

func BenchmarkTypeAssertion(b *testing.B) {
	i := new(myint)
	incnAssertion(i, b.N)
}

func BenchmarkTypeAssertionNoCheck(b *testing.B) {
	i := new(myint)
	incnAssertionNoCheck(i, b.N)
}

What is your thought about this?

Thanks.

Thanks for posting your code. The problem with each of these benchmarks is the compiler can deduce that they do nothing. They change no external state, and nothing is visible from outside the function when, and after, the benchmark has run. Thus the compiler can deduce that it can delete all your code, and achieve the same result.

However, this isn’t happening, or isn’t happened consistently. However I consider these benchmarks unstable because a future improvement to the compile could cause their runtime to drop to zero.

Have a read of this, https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go.

1 Like

I don’t have a broad understanding on using golang benchmark for now. Basically I am new to this, I have been playing this language for a few months now. Actually the code above is not mine, it is from Stackoverflow linked above, I just added the incnAssertionNoCheck that also suggested on that the same thread.

Actually I am looking the best way to do assertion. Do you have any suggestion for that?

BTW thanks for the article.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.