Skip to content
This repository was archived by the owner on Feb 8, 2018. It is now read-only.
This repository was archived by the owner on Feb 8, 2018. It is now read-only.

A lot of the measured interface-call cost is GC #1

@twotwotwo

Description

@twotwotwo

It turns out a lot of the time the interface benchmark was taking was in GC related to the particular way interfaces are being used here, not cost that's inherent to all interface calls.

As background--since Go 1.4, when you wrap a non-pointer type like a uint64 in an interface, the interface value holds a pointer, and the actual int is allocated elsewhere. You can see the allocations by using MemStats with the original code: https://play.golang.org/p/UUlVZp7x-r.

If that cost were present every time someone makes an interface call (or most of the time) you'd want to count it, of course, but it often isn't.

You don't get an extra allocation when you store a pointer type in an interface var, which is probably the most common case, like when you put a *bufio.Writer or *os.File in an io.Writer.

You also get only one extra allocation if you store a non-pointer type in an interface var once, then make lots of calls on it, like when you wrap a large slice in a sort.Interface and call sort.Sort on it.

After this benchmark got posted on Twitter and I noticed it was allocating for each iface call, I rigged up a variation where you call Add on an *Int, so you don't get an alloc per call: https://play.golang.org/p/OgAcagFmZi

The results I got were 0 bytes allocated and 177.376219ms for the concrete calls, 16 bytes allocated and 210.502363ms for the indirect calls. I'm guessing the switch to using pointers was what made the concrete calls slower. Compiling with -gcflags -m shows the concrete call to Add still gets inlined.

If it works for you, I can submit that code and the updates that go with it in a PR so anyone stumbling on this in the future can see the interface call costs without the GC situation. Or if you want to integrate the code yourself, or integrate the info here in some other way, either sounds great to me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions