FAQ
Hello peoples,

I wondered about the performance of "concrete" function cals versus
"interface" function calls, of course hoping they were identical: the use
of an interface comes at no cost when the compiler knows that the concrete
type used in the (interface) call satisfies the the interface.
I wrote a test program to find out more, here it is:
http://play.golang.org/p/A5gjsIJuza
Unfortunately it turns out that the interface calls are slower than the
concrete calls, at least in this case. I have looked at the generated
assembly (go run -gcflags -S *.go) but I'm not sure if that is the assembly
used in the final binary. I believe I have read somewhere that the linker
can do code transformations too. Maybe there was an inlining opportunity in
the concrete call case that is (not yet) possible in the interface call
case?
Anyway, what I am really curious about is if it is possible (at some future
point in time) that a function taking interface parameters performs equally
fast as a function taking concrete type parameters. That would be cool, to
be able to rely on that.

--

Search Discussions

  • Bryanturley at Oct 15, 2012 at 9:03 pm
    I would recommend measuring 1000+ calls not a single call.
    You never know if your system timer precision is up to snuff with your cpu
    cycles.
    Unless of course you do know that ;)


    --
  • Bryanturley at Oct 15, 2012 at 9:10 pm
    Also turn off any cpu throttling/powersaving features while measuring.
    On Monday, October 15, 2012 4:03:17 PM UTC-5, bryanturley wrote:

    I would recommend measuring 1000+ calls not a single call.
    You never know if your system timer precision is up to snuff with your cpu
    cycles.
    Unless of course you do know that ;)

    --
  • Erwin at Oct 15, 2012 at 9:11 pm

    I would recommend measuring 1000+ calls not a single call.
    You never know if your system timer precision is up to snuff with your cpu
    cycles.
    Unless of course you do know that ;)

    I know that, that's why I measured a million calls :)

    --
  • Bryanturley at Oct 15, 2012 at 9:28 pm

    On Monday, October 15, 2012 4:06:55 PM UTC-5, notnot wrote:

    I would recommend measuring 1000+ calls not a single call.
    You never know if your system timer precision is up to snuff with your
    cpu cycles.
    Unless of course you do know that ;)

    I know that, that's why I measured a million calls :)
    lol, so you did my bad ;)

    --
  • Rémy Oudompheng at Oct 15, 2012 at 9:04 pm

    On 2012/10/15 Erwin wrote:
    Hello peoples,

    I wondered about the performance of "concrete" function cals versus
    "interface" function calls, of course hoping they were identical: the use of
    an interface comes at no cost when the compiler knows that the concrete type
    used in the (interface) call satisfies the the interface.
    I wrote a test program to find out more, here it is:
    http://play.golang.org/p/A5gjsIJuza
    Unfortunately it turns out that the interface calls are slower than the
    concrete calls, at least in this case. I have looked at the generated
    assembly (go run -gcflags -S *.go) but I'm not sure if that is the assembly
    used in the final binary. I believe I have read somewhere that the linker
    can do code transformations too. Maybe there was an inlining opportunity in
    the concrete call case that is (not yet) possible in the interface call
    case?
    There's clearly an inlining possibility in your code. Maybe you could
    try comparing bytes.Buffer vs io.Reader/io.Writer.

    Here the Read/Write methods of bytes.Buffer are not inlined.

    Concrete calls have the advantage of being inlined if the method is
    very short. When it is not inlined, it is expected that the overhead
    is very small (only a couple of instructions).

    Rémy.

    --
  • Erwin at Oct 15, 2012 at 10:15 pm


    There's clearly an inlining possibility in your code. Maybe you could
    try comparing bytes.Buffer vs io.Reader/io.Writer.

    Here the Read/Write methods of bytes.Buffer are not inlined.

    Concrete calls have the advantage of being inlined if the method is
    very short. When it is not inlined, it is expected that the overhead
    is very small (only a couple of instructions).

    Yes, I figured as much myself. I'll do some "real world" tests, comparing
    concrete calls versus interface calls in a scenario where the methods
    perform more work than just incrementing/decrementing. For the current test
    I used such minimal methods to bring the interface call overhead to the
    surface as clearly as possible. On my machine, the interface calls take
    twice the time of the concrete calls, and something rather vague inside me
    tells me this need not be the case, given a compiler that is "smart"
    enough. Well, lets hope smartness comes with age, like wisdom is said to
    come :)

    --
  • John Beshir at Oct 16, 2012 at 11:24 pm

    On Mon, Oct 15, 2012 at 9:46 PM, Erwin wrote:
    Anyway, what I am really curious about is if it is possible (at some future
    point in time) that a function taking interface parameters performs equally
    fast as a function taking concrete type parameters. That would be cool, to
    be able to rely on that.
    The short answer is that it is not possible to rely on this. A call
    through an interface cannot be guaranteed to take the same time as a
    direct function/method call, aside through slowing down function
    calls.

    This is because a direct call to a function can be done as a simple
    call to a compile-time known function. A method call through an
    interface requires looking up the function to call in a table
    referenced by the interface value, then doing a call to it. The former
    permits, in many cases, a faster implementation, and never requires a
    slower implementation.

    You can think, somewhat loosely, of a direct call as equivalent to a
    call through an interface for which the compiler has more information
    statically available, and so can generate more optimised executable
    code. It is equivalent to the difference in C++ between direct
    function calls and virtual method calls.

    The actual difference may vary with optimisation, as the
    implementation could try to convert calls through interfaces to direct
    calls when it can statically recognise what type the value in the
    interface must be, removing the method lookup and permitting inlining.
    I do not believe you will be able to expect this to happen reliably in
    the foreseeable future, however.

    All that said, unless your functions are doing barely any work, call
    overhead should be small, and the additional overhead from the method
    lookup even smaller. Both function and interface calls in Go easily
    outperform all function calls in languages which require looking up
    called functions at runtime, or otherwise don't compile function calls
    to a direct call. Such languages may permit functions and methods to
    take the same amount of time, but only by making calling both much
    slower.

    You shouldn't worry about method lookup overhead unless profiling is
    directing you to optimise a part of your code, because avoiding it is
    likely to have high maintainability costs with near-zero performance
    improvement in most places.

    --
  • Erwin at Oct 16, 2012 at 10:46 pm

    The actual difference may vary with optimisation, as the
    implementation could try to convert calls through interfaces to direct
    calls when it can statically recognise what type the value in the
    interface must be, removing the method lookup and permitting inlining.
    I do not believe you will be able to expect this to happen reliably in
    the foreseeable future, however.

    This is the scenario I was in fact envisioning, and my playground test
    code would be very suitable for such an optimization.

    All that said, unless your functions are doing barely any work, call
    overhead should be small, and the additional overhead from the method
    lookup even smaller. Both function and interface calls in Go easily
    outperform all function calls in languages which require looking up
    called functions at runtime, or otherwise don't compile function calls
    to a direct call. Such languages may permit functions and methods to
    take the same amount of time, but only by making calling both much
    slower.
    Agreed.

    You shouldn't worry about method lookup overhead unless profiling is
    directing you to optimise a part of your code, because avoiding it is
    likely to have high maintainability costs with near-zero performance
    improvement in most places.
    Sometimes interface methods require just a tiny amount of work, see
    the standard library sort interface for example, especially when used
    with basic types. Looking up a method and making a call, however
    cheap that is, is always more expensive than not doing it, right?

    --
  • John Beshir at Oct 17, 2012 at 9:08 am

    On Tue, Oct 16, 2012 at 11:16 PM, Erwin wrote:
    The actual difference may vary with optimisation, as the
    implementation could try to convert calls through interfaces to direct
    calls when it can statically recognise what type the value in the
    interface must be, removing the method lookup and permitting inlining.
    I do not believe you will be able to expect this to happen reliably in
    the foreseeable future, however.
    This is the scenario I was in fact envisioning, and my playground test
    code would be very suitable for such an optimization.
    ...
    You shouldn't worry about method lookup overhead unless profiling is
    directing you to optimise a part of your code, because avoiding it is
    likely to have high maintainability costs with near-zero performance
    improvement in most places.

    Sometimes interface methods require just a tiny amount of work, see
    the standard library sort interface for example, especially when used
    with basic types. Looking up a method and making a call, however
    cheap that is, is always more expensive than not doing it, right?
    Yes. Cases like that are where profiling would be more likely to show
    improvement, but only if the sorting was itself a significant part of
    the larger application's runtime.

    It's possible that there will at some point be a defined subset of
    possible interface usage which would be specialised like this. I don't
    know of any short/middle-term plans for this, but I might have just
    not spotted them on the list.

    --

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedOct 15, '12 at 8:46p
activeOct 17, '12 at 9:08a
posts10
users4
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase