Go: runtime: don't allocate for non-escaping conversions to interface{}

Created on 29 Aug 2014  路  12Comments  路  Source: golang/go

fmt.Fprintf("%d", 8)

Since all interface data fields are now pointers, an int must be allocated and
initialized to 8 so that it can be put in an interface{} to pass to Fprintf.

Since we know the 8 doesn't escape, we could instead allocate that 8 on the stack and
have the interface data word point to that stack slot.  To be safe, we can only do this
when the resulting interface{} doesn't escape.  We probably also need to be sure the
conversion happens at most once so the stack slot is not reused.

We could have a special convT2Enoescape call for the compiler to use when it knows the
result doesn't escape.  Maybe also convT2I, assertT2E, ...
Performance

Most helpful comment

For the reference until this is fixed some of us use ad-hoc printf-style mini language to do text formatting in hot codepaths without allocations. For example if in fmt speak you have

s := fmt.Sprintf("hello %d %s %x", 1, "world", []byte("data"))

the analog would be

buf := xfmt.Buffer{}
buf .S("hello ") .D(1) .C(' ') .S("world") .C(' ') .Xb([]byte("data"))
s := buf.Bytes()

It is a bit uglier but runs faster and without allocations:

pkg: lab.nexedi.com/kirr/go123/xfmt
BenchmarkFmt-4       5000000           246 ns/op          72 B/op      3 allocs/op
BenchmarkXFmt-4     20000000            57.9 ns/op         0 B/op      0 allocs/op

Details:

https://lab.nexedi.com/kirr/go123/commit/1aa677c8
https://lab.nexedi.com/kirr/go123/blob/c0bbd06e/xfmt/fmt.go

All 12 comments

Comment 1:

_Status changed to Accepted._

Comment 2:

_Labels changed: added repo-main._

This thread explains how this issue causes 2 allocs on every call to os.(*File).Write.
https://groups.google.com/forum/#!topic/golang-nuts/0hfeLJP1LSk

Dmitry started this in CL 3503. Note that this requires improved escape analysis.

CL https://golang.org/cl/35554 mentions this issue.

For the reference until this is fixed some of us use ad-hoc printf-style mini language to do text formatting in hot codepaths without allocations. For example if in fmt speak you have

s := fmt.Sprintf("hello %d %s %x", 1, "world", []byte("data"))

the analog would be

buf := xfmt.Buffer{}
buf .S("hello ") .D(1) .C(' ') .S("world") .C(' ') .Xb([]byte("data"))
s := buf.Bytes()

It is a bit uglier but runs faster and without allocations:

pkg: lab.nexedi.com/kirr/go123/xfmt
BenchmarkFmt-4       5000000           246 ns/op          72 B/op      3 allocs/op
BenchmarkXFmt-4     20000000            57.9 ns/op         0 B/op      0 allocs/op

Details:

https://lab.nexedi.com/kirr/go123/commit/1aa677c8
https://lab.nexedi.com/kirr/go123/blob/c0bbd06e/xfmt/fmt.go

Note that when the arguments are constants, they no longer allocate on tip, so this is a bit better than it was.

@josharian thanks for feedback. For the reference the above benchmark was for tip (go version devel +d728be70f4 Thu Apr 20 01:37:08 2017 +0000 linux/amd64).

What are the status about this issue ? Is anyone working on ?

@bnjjj I'm not aware of anybody actively working on this.

One data point here. The gio authors are considering an API design choice: whether to use an interface type or a function type. Using the interface type results in nicer code (when there's a literal struct, it can be used directly rather than via a method expression to obtain the function value), but results in allocations, and avoiding allocations is a key consideration in that context.

To illustrate with a couple of small examples:

This program, using a function type, does not incur any allocations. The required closures can all be allocated on the stack. https://play.golang.org/p/FC4taLlhVGz

This equivalent program, using an interface type, incurs an allocation for each interface conversion. https://play.golang.org/p/XPfcNSMPt82

Given that interfaces are often more idiomatic than function types in Go, it would be nice if they could be used interchangeably without a significant performance difference.

As of five years ago(!), this needed escape analysis improvements. Those stalled; see CL 3503. Maybe @mdempsky could weigh in.

Was this page helpful?
0 / 5 - 0 ratings