Has anyone quantified the runtime cost of doing interface upgrades? I have a vague memory that the vtable for a specific type/interface pair is constructed at runtime and then cached -- is this true?
An interesting question. Using [1], which note can't be executed on the Playground but you can execute by copying and pasting into a file "upgrade_test.go" in a new directory and executing
For clarity, I've elided the "execution count" column which is not useful information for us here.
InterfaceUpgrade is testing the cost of having an interface-referenced value in hand and asking if it implements another interface. My belief based on the understanding of the runtime is that this is all a static check at runtime (i.e., taking the type of the value, looking that type's info up, and then reading from that type whether it implements a given interface, with all calculation done at compile time and only the lookup being done dynamically), and that while that number may go up a bit if there are more interfaces in play it shouldn't go up much.
DoNothingInterfaceCall is the time to call a function that does nothing and returns nothing through the interface. I tried adding a benchmark time for a do-nothing static call but Go inlines it away into nothing, making it a useless test of how fast the loop itself is running. 0.89 ns, FWIW.
InterfaceUpgradeAndCall combines the upgrade check and call into one pass. InterfaceUpgradeFail just checks to see if the fail case times very differently (no).
It's fairly easy to tweak these if you'd like to ask different questions. (Note some of the tests have a bit of spurious stuff at the end to make it so Go doesn't complain about unused values. Go really doesn't like to see unused values.)
Also, for those who may have spent some time benchmarking the more dynamic languages, I call your attention to the "ns" there. That's not milli- or microseconds, that's nanoseconds. (I once benchmarked something between Go and Erlang, and mistakingly though the Go was slower when it took 700 and Erlang was taking 70, but it turned out to be nanoseconds and microseconds respectively. FWIW, the code wasn't doing exactly the same thing, either, it was just some code I was benchmarking at the time, and it is expected that the Go code was doing less; point being, watch your units.)
InterfaceUpgrade is testing the cost of having an interface-referenced value in hand and asking if it implements another interface. My belief based on the understanding of the runtime is that this is all a static check at runtime (i.e., taking the type of the value, looking that type's info up, and then reading from that type whether it implements a given interface, with all calculation done at compile time and only the lookup being done dynamically), and that while that number may go up a bit if there are more interfaces in play it shouldn't go up much.
DoNothingInterfaceCall is the time to call a function that does nothing and returns nothing through the interface. I tried adding a benchmark time for a do-nothing static call but Go inlines it away into nothing, making it a useless test of how fast the loop itself is running. 0.89 ns, FWIW.
InterfaceUpgradeAndCall combines the upgrade check and call into one pass. InterfaceUpgradeFail just checks to see if the fail case times very differently (no).
It's fairly easy to tweak these if you'd like to ask different questions. (Note some of the tests have a bit of spurious stuff at the end to make it so Go doesn't complain about unused values. Go really doesn't like to see unused values.)
Also, for those who may have spent some time benchmarking the more dynamic languages, I call your attention to the "ns" there. That's not milli- or microseconds, that's nanoseconds. (I once benchmarked something between Go and Erlang, and mistakingly though the Go was slower when it took 700 and Erlang was taking 70, but it turned out to be nanoseconds and microseconds respectively. FWIW, the code wasn't doing exactly the same thing, either, it was just some code I was benchmarking at the time, and it is expected that the Go code was doing less; point being, watch your units.)
http://play.golang.org/p/K1LedMxMPL