Earlier quoted context omitted.
I'd argue quite the reverse. Allocation can be quite efficient if done properly, but copying involves a lot of other work.
I disagree--the bottleneck here is entirely the allocation. The copying is just a memcpy and it's very fast for small structs like this; like I said, it's not the same as a clone() in Rust, which is a deep copy. If you optimized the allocation away entirely (leaving only the copy cost), there wouldn't have been a significant performance problem and this blog would never have been written.
Making a Go program faster with a one-character change
221–230 of 249 posts
Re: Making a Go program faster with a one-character change
#222The deeper lesson here is "don't use pointers unless you're sure you need them". I've seen quite a few people use pointers for no reason in particular, or there's simply the assumption it's faster (and have done this myself, too), but it puts a lot more pressure on the GC than simple local stack variables. Of course sometimes pointers are faster, or much more convenient. But as a rule of thumb: don't use pointers unl…
Eh, I've waffled a couple of times between "pass values by default" and "pass pointers by default". Ultimately, I don't think there's a really good answer except to understand escape analysis and get comfortable with the escape analyzer. Notably, "using pointers" doesn't inherently put pressure on the GC, but rather allocations put pressure on the GC and there are plenty of instances where pointers don't put pressure…
Isn't it still possible for the value to escape here? For example the callee could stick it until a global data structure.
In fact it seems like a pointer passed to a function would need to be on the heap "by default" unless the compiler can prove that it doesn't escape.
Re: Making a Go program faster with a one-character change
#223A while ago at my company we switched from GCC to Clang, and noticed a couple of massive regressions (on the order of 50%?) in performance having to do with floating point. After profiling for a bit, I discovered that suddenly a lot of time was spent in isinf on Clang and no time in GCC… Clang was emitting a function call where GCC wasn’t. I happened to randomly change isinf to std::isinf (it’s a random habit of mine…
And did you learn your lesson about making random changes that "shouldn't matter" without proving they don't matter? :)
I find that once I spend the time to make these changes correctly, they are not worth the time to make correctly.
Re: Making a Go program faster with a one-character change
#224Earlier quoted context omitted.
Eh, I've waffled a couple of times between "pass values by default" and "pass pointers by default". Ultimately, I don't think there's a really good answer except to understand escape analysis and get comfortable with the escape analyzer. Notably, "using pointers" doesn't inherently put pressure on the GC, but rather allocations put pressure on the GC and there are plenty of instances where pointers don't put pressure…
> notably, if you're passing data into a function by pointer, it's not going to allocate Isn't it still possible for the value to escape here? For example the callee could stick it until a global data structure. In fact it seems like a pointer passed to a function would need to be on the heap "by default" unless the compiler can prove that it doesn't escape.
Re: Making a Go program faster with a one-character change
#225Earlier quoted context omitted.
I consider tens of milliseconds to be a long pause time (P99 should be more explicit .
If one cares about pause times, G1 isn't it, rather the pauseless ZGC, Azul's C4 or Shenodah. Capable of handling TB sized heaps with micro seconds pauses.
Re: Making a Go program faster with a one-character change
#226Aaaaaand that's why I love Rust's decision to make copies explicit with `.clone()`. Annoying as hell when you're not used to it but overall worth it.
Re: Making a Go program faster with a one-character change
#227Earlier quoted context omitted.
If one cares about pause times, G1 isn't it, rather the pauseless ZGC, Azul's C4 or Shenodah. Capable of handling TB sized heaps with micro seconds pauses.
Yeah, I’m nominally familiar with these, but I can’t understand why one of these low latency collectors wouldn’t be the default GC unless they impose other significant tradeoffs.
Re: Making a Go program faster with a one-character change
#228Earlier quoted context omitted.
> the history rule I'm unfamiliar with this rule (and not finding anything good to google). Can you elaborate? I can't really think of a scenario where an immutable datastructure isn't a subset of actions against a mutable datastructure.
I had to look it up too, it apparently is a constraint for subtypes defined in Liskovs substitution principle [1]. From Wikipedia: > History constraint (the "history rule"). Objects are regarded as being modifiable only through their methods (encapsulation). Because subtypes may introduce methods that are not present in the supertype, the introduction of these methods may allow state changes in the subtype that are n…
Re: Making a Go program faster with a one-character change
#229Re: Making a Go program faster with a one-character change
#230Earlier quoted context omitted.
> C is fast because it's close to how CPU and memory actually work. Out-of-order execution, cache hierarchies, branch prediction, virtual memory, pipelining, vector instructions, ILP, NUMA are all pretty transparent to the C spec. Trying to accommodat hardware quirks with C feels like blackbox engineering. It's certainly better than with managed languages but still....
C is an abstraction, and most (all?) cpu architectures pretends to be c machines. I don't know of any other way of manipulating the cpu as closely as C and assembly. Do you?