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, ...
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.
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
the analog would be
It is a bit uglier but runs faster and without allocations:
Details:
https://lab.nexedi.com/kirr/go123/commit/1aa677c8
https://lab.nexedi.com/kirr/go123/blob/c0bbd06e/xfmt/fmt.go