Live data from Hacker News

Go Optimization Guide

goperf.dev

121–130 of 173 posts

Re: Go Optimization Guide

#121

Earlier quoted context omitted.

go1.15 re-added small integer packing into interfaces: https://go.dev/doc/go1.15#runtime

It didn't, actually. Instead go 1.15 has a static array of the first 256 positive integers, and when it needs to box one for an interface it gets a pointer into that array instead: https://go-review.googlesource.com/c/go/+/216401/4/src/runti... This array is also used for single-byte strings (which previously had its own array): https://go-review.googlesource.com/c/go/+/221979/3/src/runti...

It didn't, do what? I would consider the first 256 integers to be "small integers" ;)

> Converting a small integer value into an interface value no longer causes allocation

I forgot that it can also be used for single byte strings, That's not an optimization I ever encountered being useful, but it's there!

Re: Go Optimization Guide

#122
post #117

Earlier quoted context omitted.

> then the code was to demonstrate that sync.Pool could be "extended" with other types and custom logic. Wherein lies the aforementioned guarantee? The code guarantees neither the ask (zero values) nor even proper usage if you somehow didn't read what you quoted and thought that some kind of type safety was the guarantee being offered. Furthermore, who, exactly, do you think would be familiar enough with Go to get al…

> Wherein lies the aforementioned guarantee? I think you should re-read what I wrote. You seem to be upset that I did not solve everyone's problem with sync.Pool with my 10 liner (when I claimed no such thing). One could define a new "Pool[T]" type (extending sync.Pool) to get these guarantees Meant... One could define / extend sync.Pool to get those guarantees [for their custom types] ... Followed by an example for…

> I think you should re-read what I wrote.

You "forgot" to copy the colon from the original statement. A curious exclusion given the semantic meaning it carries. Were you hoping I didn't read your original comment and wouldn't notice?

> You seem to be upset

How could one ever possibly become upset on an internet forum? Even if for some bizarre and unlikely reason you were on the path to becoming upset, you'd turn off the computer long before ever becoming upset. There is absolutely no reason to use this tool if it isn't providing joy.

> One could define / extend sync.Pool to get those guarantees [for their custom types] ...

What audience would be interested in this? Is there anyone who understands all the intricacies of sync.Pool but doesn't know how to define types or how to write functions?

Re: Go Optimization Guide

#123

Can someone explain to me why the compiler can’t do struct-field-alignment? This feels like something that can easily be automated.

Because the order of fields can be significant. It's very relevant for syscalls, and is observable via the reflect package; it'd be strange if the field order was arbitrarily changed (and might change further between releases). I assume the thinking was that this is pretty easy to optimise if you care, and if it's on by default there'd then have to be some opt-out which there isn't a good mechanism for.

> and if it's on by default there'd then have to be some opt-out which there isn't a good mechanism for.

Good is subjective, but the mechanism is something already implemented: https://pkg.go.dev/structs#HostLayout

Re: Go Optimization Guide

#124
post #73

Earlier quoted context omitted.

That's just not true. Pool contents are GCed after two cycles if unused.

What do you mean? Pool content can't be GCed , because there are references to it: pool itself. What people do is what this article suggested, pool.Get/pool.Put, which makes it only grow in size even if load profile changes. App literally accumulated now unwanted garbage in pool and no app I have seen made and attempt to GC it.

sync.Pool uses weak references for this purpose. The pool does delay GC, and if your pooled objects have pointers, those are real and can be a problem. If your app never decreases the pool size, you've probably reached a stable equilibrium with usage, or your usage fits a pattern that GC has trouble with. If Go truly cannot GC your pooled objects, you probably have a memory leak. E.g. if you have Nodes in a graph with pointers to each other in the pool, and some root pointer to anything in the pool, that's a memory leak

Re: Go Optimization Guide

#125
post #73

Earlier quoted context omitted.

That's just not true. Pool contents are GCed after two cycles if unused.

What do you mean? Pool content can't be GCed , because there are references to it: pool itself. What people do is what this article suggested, pool.Get/pool.Put, which makes it only grow in size even if load profile changes. App literally accumulated now unwanted garbage in pool and no app I have seen made and attempt to GC it.

[deleted]

Re: Go Optimization Guide

#126

Earlier quoted context omitted.

It didn't, actually. Instead go 1.15 has a static array of the first 256 positive integers, and when it needs to box one for an interface it gets a pointer into that array instead: https://go-review.googlesource.com/c/go/+/216401/4/src/runti... This array is also used for single-byte strings (which previously had its own array): https://go-review.googlesource.com/c/go/+/221979/3/src/runti...

It didn't, do what? I would consider the first 256 integers to be "small integers" ;) > Converting a small integer value into an interface value no longer causes allocation I forgot that it can also be used for single byte strings, That's not an optimization I ever encountered being useful, but it's there!

> It didn't, do what?

Reintroduce “packing into interfaces”.

It did a completely different thing. Small integers remain not inlined.

Re: Go Optimization Guide

#127

Can someone explain to me why the compiler can’t do struct-field-alignment? This feels like something that can easily be automated.

Like the answer to all "Why doesn't Go have X?" questions: Lack of manpower. There has been some work done to support it, but is far from complete. Open source doesn't mean open willingness to contribute, unfortunately. Especially when you're not the cool kid on the block.

Re: Go Optimization Guide

#128
post #7

You're not really writing 'Go' anymore when you're optimising it, it's defeating the point of the language as a simple but powerful interface over networked services.

Why? You have control over the parts where control yields noticeable savings, and the rest just kind of works with reasonable defaults. Taken to the extreme, Go is still nice even with constraints. For example, tinygo is pretty nice for microcontroller projects. You can say upfront that you don't want GC, and just allocate everything at the start of the program (kind of like how DJB writes C programs) and writing the…

100%. I work in Go and use optimizations like the ones in the article, but only in a small percentage of the code. Go has a nice balance where it's not pessimized by default, and you can just write 99% of code without thinking about these optimizations. But having this control in performance critical parts is huge. Some of this stuff is 10x, not +5%. Also, Go has very good built-in support for CPU and memory profiling which pairs perfectly with this.

Re: Go Optimization Guide

#129
post #87

Earlier quoted context omitted.

Because the order of fields can be significant. It's very relevant for syscalls, and is observable via the reflect package; it'd be strange if the field order was arbitrarily changed (and might change further between releases). I assume the thinking was that this is pretty easy to optimise if you care, and if it's on by default there'd then have to be some opt-out which there isn't a good mechanism for.

In particular, struct field alignment matches C (even without cgo) and so any change to the default would break a lot of code.

> struct field alignment matches C (even without cgo)

The spec defines alignment for numeric types, but that's about it. There is nothing in the spec about struct layout. That is implementation dependent. If you are relying on a particular implementation, you are decidedly in unsafe territory.

> so any change to the default would break a lot of code.

The compiler can disable optimization on cgo calls automatically and most other places where it matters are via the standard library, so it might not be as much as you think. And if you still have a case where it matters, that is what this is for: https://pkg.go.dev/structs#HostLayout

Re: Go Optimization Guide

#130
post #122

Earlier quoted context omitted.

> Wherein lies the aforementioned guarantee? I think you should re-read what I wrote. You seem to be upset that I did not solve everyone's problem with sync.Pool with my 10 liner (when I claimed no such thing). One could define a new "Pool[T]" type (extending sync.Pool) to get these guarantees Meant... One could define / extend sync.Pool to get those guarantees [for their custom types] ... Followed by an example for…

> I think you should re-read what I wrote. You "forgot" to copy the colon from the original statement. A curious exclusion given the semantic meaning it carries. Were you hoping I didn't read your original comment and wouldn't notice? > You seem to be upset How could one ever possibly become upset on an internet forum? Even if for some bizarre and unlikely reason you were on the path to becoming upset, you'd turn off…

> You "forgot" to copy the colon from the original statement.

You got me!

Post reply on HN