Live data from Hacker News

Generics can make your Go code slower

planetscale.com

41–50 of 418 posts

Re: Generics can make your Go code slower

#42

I'm excited about generics that gives you a tradeoff between monomorphization and "everything is a pointer". The "everything is a pointer" approach, like Haskell, is incredibly inefficient wrt execution time and memory usage, the "monomorphize everything" approach can explode your code size surprisingly fast. I wouldn't be surprised if we get some control over monomorphization down the line, but if Go started with th…

A hybrid approach would be monomorphization for native types like int and pointers for records. C# is doing that if I remember correctly.

Re: Generics can make your Go code slower

#43
post #12

Earlier quoted context omitted.

If the information in this article is make-or-break for your program, you probably shouldn't have chosen Go. In the grand space of all programming languages, Go is fast. In the space of compiled programming languages, it's on the slower end. If you're in a "counting CPU ops" situation it's not a good choice. There is an intermediate space in which one is optimizing a particular tight loop, certainly, I've been there,…

This is good high-level advice as well as low-level advice. Go is positioned to be most useful as an alternative to Java, and to C++ where performance isn't the key factor (i.e. projects where C++ would be chosen because "Enh, it's a big desktop application and C++ is familiar to a lot of developers," not because the project actually calls for being able to break out into assembly language easily or where fine-tuning…

In practice, it's used as an alternative to python and ruby and nodejs. It can't fully do what Java or C# do.

Re: Generics can make your Go code slower

#44
post #9

Earlier quoted context omitted.

Premature optimization is a bad thing. Just implement naively, then if you have performance issues identify the bottleneck.

Ignorance of how your language works is a bad thing. Knowing where performance issues with certain techniques might arise is not premature optimization. Implement with an appropriate level of care, including performance concerns. Not every kind of poor performance appears as a clear spike in a call graph, and even fewer can be fixed without changing any external API.

The language is a tool for a job.

If I'm using low torque, I don't need to know the yield strength of my wrench

Re: Generics can make your Go code slower

#45

Great article, just skimmed it, but will definitely dive deeper into it. I thought Go is doing full monomorphization. As another datapoint I can add that I tried to replace the interface{}-based btree that I use as the main workhorse for grouping in OctoSQL[0] with a generic one, and got around 5% of a speedup out of it in terms of records per second. That said, compiling with Go 1.18 vs Go 1.17 got me a 10-15% speed…

> That said, compiling with Go 1.18 vs Go 1.17 got me a 10-15% speedup by itself. Where did you see this speedup? Other than `GOAMD64` there wasn't much in the release notes about compiler or stdlib performance improvements so I didn't rush to get 1.18-compiled binaries deployed, but maybe I should... (I do expect some nice speedups from using Cut and AvailableBuffer in a few places, but not without some rewrites.)

I've experienced that speedup on an ARM MacBook Pro. I've just checked on Linux AMD64 and there's no performance difference there.

Re: Generics can make your Go code slower

#46
I'd argue that golang is inherently not a systems language, with its mandatory GC managed memory. I think it's a poor choice for anything performance or memory sensitive, especially a database. I know people would disagree (hence all the DBs written in golang these days, and Java before it), but I think C/C++/Rust/D are all superior for that kind of application.

All of which is to say, I don't think it matters. Use the right tool for the job - if you care about generic overhead, golang is not the right thing to use in the first place.

Re: Generics can make your Go code slower

#47

I'm excited about generics that gives you a tradeoff between monomorphization and "everything is a pointer". The "everything is a pointer" approach, like Haskell, is incredibly inefficient wrt execution time and memory usage, the "monomorphize everything" approach can explode your code size surprisingly fast. I wouldn't be surprised if we get some control over monomorphization down the line, but if Go started with th…

Haskell does monomorphization as well. See https://reasonablypolymorphic.com/blog/specialization/

Re: Generics can make your Go code slower

#48

Great article, just skimmed it, but will definitely dive deeper into it. I thought Go is doing full monomorphization. As another datapoint I can add that I tried to replace the interface{}-based btree that I use as the main workhorse for grouping in OctoSQL[0] with a generic one, and got around 5% of a speedup out of it in terms of records per second. That said, compiling with Go 1.18 vs Go 1.17 got me a 10-15% speed…

> That said, compiling with Go 1.18 vs Go 1.17 got me a 10-15% speedup by itself. Where did you see this speedup? Other than `GOAMD64` there wasn't much in the release notes about compiler or stdlib performance improvements so I didn't rush to get 1.18-compiled binaries deployed, but maybe I should... (I do expect some nice speedups from using Cut and AvailableBuffer in a few places, but not without some rewrites.)

GOAMD64 could be significant, so I'm not sure why your comment seems to dismiss it?

Also, as the article mentions, Go 1.18 can now inline functions that contain a "range" for loop, which previously was not allowed, and this would contribute performance improvements for some programs by itself. The new register-based calling convention was extended to ARM64, so if you're running Go on something like Graviton2 or an Apple Silicon laptop, you could expect to see a measurable improvement from that too. (edit: the person you replied to confirmed they're using Apple Silicon, so definitely a major factor.)

The Go team is always working on performance improvements, so I'm sure there are others that made it into the release without being mentioned in the release notes.

Re: Generics can make your Go code slower

#49

Earlier quoted context omitted.

> That said, compiling with Go 1.18 vs Go 1.17 got me a 10-15% speedup by itself. Where did you see this speedup? Other than `GOAMD64` there wasn't much in the release notes about compiler or stdlib performance improvements so I didn't rush to get 1.18-compiled binaries deployed, but maybe I should... (I do expect some nice speedups from using Cut and AvailableBuffer in a few places, but not without some rewrites.)

I've experienced that speedup on an ARM MacBook Pro. I've just checked on Linux AMD64 and there's no performance difference there.

It's probably because of the new register passing calling convention. From https://tip.golang.org/doc/go1.18

> Go 1.17 implemented a new way of passing function arguments and results using registers instead of the stack on 64-bit x86 architecture on selected operating systems. Go 1.18 expands the supported platforms to include 64-bit ARM (GOARCH=arm64), big- and little-endian 64-bit PowerPC (GOARCH=ppc64, ppc64le), as well as 64-bit x86 architecture (GOARCH=amd64) on all operating systems. On 64-bit ARM and 64-bit PowerPC systems, benchmarking shows typical performance improvements of 10% or more.

Re: Generics can make your Go code slower

#50

Earlier quoted context omitted.

> That said, compiling with Go 1.18 vs Go 1.17 got me a 10-15% speedup by itself. Where did you see this speedup? Other than `GOAMD64` there wasn't much in the release notes about compiler or stdlib performance improvements so I didn't rush to get 1.18-compiled binaries deployed, but maybe I should... (I do expect some nice speedups from using Cut and AvailableBuffer in a few places, but not without some rewrites.)

I've experienced that speedup on an ARM MacBook Pro. I've just checked on Linux AMD64 and there's no performance difference there.

Yeah, 1.17 got register (instead of stack) calling convention on amd64; 1.18 expanded that to arm64, which should be responsible for most of that performance improvement.
Post reply on HN