12 ms·
The Go Compiler Needs to Be Smarter
- hactually 6y agoThis[0] PR should fix some of it is my understanding but will have to wait and see -- not playing with /tip! [0] https://github.com/golang/go/commit/fff7509d472778cae5e652dbe2479929c666c24f https://github.com/golang/go/commit/fff7509d472778cae5e652db...
- bitwize 6y agoSure, if your goal is to build a compiler that outputs the fastest possible code. If your goal is to apply the "principle of least surprise" to the generated machine code, then that eliminates or constrains most interesting optimizations, including procedure inlining, dead code elision, and compile-time evaluation. Go is a "principle of least surprise" language, based on a vision of simplicity for C that hasn't existed among actual C implementations (outside of maybe Plan 9) for decades now. It's yet more suckless idiocy: sacrifice everything, including utility and friendliness to end users, to buy "simplicity" for hackers. No wonder the suckless folks love Go so much.
- tgv 6y agoThat seems rather unwarranted attempt at vilification of the language, worded in an odd way: if something sucks, it's bad, so suckless would actually be positive? But why? What's Go done to you? A few if err != nil { ... } statements too many?
- oehtXRwMkIs 6y agoLook up suckless. It has a specific meaning and history.
- dgellow 6y agoSuckless is promoting C99 and disregards anything with a GC. https://suckless.org/coding_style/ https://suckless.org/coding_style/
- MaxBarraclough 6y ago> All variable declarations at top of block. And they say they want their C code to suck less? Why voluntarily open the door to read-before-write undefined-behaviour? The lifetime of a local should be as short as it reasonably can be.
- panpanna 6y agoDoesn't C99 warn you if you make such mistakes?
- flohofwoe 6y agoOn some compilers (gcc and clang at least) only when the warning is enabled (e.g. with -Wall). But I agree that it's a bit silly to on hand recommend C99, and on the other hand, not take advantage of C99 features. It seems like the rules have been written against C89, and the "use unextended C99" only slipped in later.
- yvdriess 6y agoMy take on this: pro: - Storage concerns are separated and grouped at the top. - Logic code is more compact, helping readability. - Stack use can be determined at a glance. - Looking up a variable's type is faster in cases where a variable is used throughout the code block. This is good to optimize, as you constantly need to look up variables when reading C code. - Reflects that object lifetime of any stack storage object is the same regardless of where it is declared in the code block. cons: - For long functions, the distance between use an declaration lines can impair looking up a var's type. (having to scroll to get to the top of your function is a sign you need to break it up though) - In many cases, a variable is only used in one location in the block and has a meaningful static initialization. Local declarations in this case readability, as it does not have to be looked up. - "-Wuninitialized" exists, but passing pointer and defining 'default' value style can still cause read-before-write. I tend to an in-between style, where code is grouped where it makes sense with group-local variables declared in front. Variables that are used throughout the entire code block body are declared at the very top.
- raverbashing 6y agoWell but that's not what's at play here Inlining basic functions shouldn't be surprising to anyone since the 80's? 90's? Unless you compile with -O0 or has a good reason to not inline it. Compilers are usually good at it. Same with the runtime checking every time if a given processor flag exists. What I suppose most runtimes do is replace a function pointer or have a function shin then add a call dynamically to the correct function. Not calling a function repeatedly to check if a processor feature exists.
- lloeki 6y ago> Go is a "principle of least surprise" language, based on a vision of simplicity for C that hasn't existed among actual C implementations (outside of maybe Plan 9) for decades now. It's yet more suckless idiocy Have you considered that this Go opinion might not be “idiocy” but desirable qualities in some use cases? It seems quite inappropriate to bash on Go for realising a vision that solves such a use case, in turn assuming no such use case exists, just as it is inappropriate to vilify Ruby or Python for for having a very dynamic object model and method calling/message passing, witch results in non-optimisable call paths because they have to be resolved every single time. Go’s consistency, reliability, and ease in debugging and exploring is definitely a really good feature that I gladly trade a few microseconds for.
- jashmatthews 6y ago> Ruby or Python for for having a very dynamic object model and method calling/message passing, witch results in non-optimisable call paths because they have to be resolved every single time. The Ruby implementations don't really do that. They use "inline caches" so this lookup normally only happens once per call-site.
- monocasa 6y agoIf there's only one backing type being looked up. If there's more than one, the inline cache thrashs like they're saying.
- jashmatthews 6y agoJRuby has had polymorphic inline caches for like a decade and CRuby will actually cache multiple types in the method cache as long as they cache the same method since https://github.com/ruby/ruby/pull/2583 https://github.com/ruby/ruby/pull/2583
- monocasa 6y agoJRuby is JVM and not really what I'm talking about. And still on CRuby if you have any dynacism, you thrash your cache.
- michaelcampbell 6y agoIndeed. My impression was that go was meant not to "produce the quickest code" but to "produce the code the quickest". The compile speed is one huge use case.
- Someone 6y agoFor the popcnt example, I think that, if a compiler takes it upon itself to detect, at runtime, whether the CPU supports it, it also should make sure it does so reasonably efficiently. After all, the reason this was added must have been because it’s faster than a hand-coded version. The alternative of doing neither would be fine to, and could better fit that “principle of least surprise”, but, of course, also would leave more low-level work to do for go programmers.
- OnlyOneCannolo 6y ago> Go is more about software engineering than programming language research. Or to rephrase, it is about language design in the service of software engineering. [1] This isn't suckless philosophy applied for the sole benefit of compiler writers. It's a compiler whose primary customers explicitly include tool developers. [1] https://talks.golang.org/2012/splash.article https://talks.golang.org/2012/splash.article
- sitkack 6y agoIt will be a whole lot smarter on June 8th at 7am pacific, https://www.youtube.com/watch?v=Dq0WFigax_c https://www.youtube.com/watch?v=Dq0WFigax_c
- mrath 6y agoI skimmed over the paper once. I could not get all of it but whatever I understood seemed nice. Hopefully it can be implemented to full(not subset) golang and I hope it can be implemented soon. I started learning golang recently. I already have few places of `interface{}`. Having done lot of Java and a little Rust, I appreciate the simplicity and quick compile of golang, but I do feel it much more verbose than both. If generics can be implemented nicely, it would be a huge boon to golang's usability.
- rob74 6y agoMore verbose than Java? Is that even possible?
- entha_saava 6y agoNice try Pike.
- vips7L 6y agoI honestly don't understand how anyone thinks go is LESS verbose than java. Go is full of manually iteration loops and doesn't have anyform of pattern matching/switch expressions.
- geodel 6y agoWell I agree and disagree. Agree in sense many individual expressions are same or more verbose in Go. Disagree in sense at a project level for roughly same amount of functionality idiomatic Java take at least ~5 times the code and directories than idiomatic Go code.
- sk0g 6y ago
- dirtydroog 6y agoThis is a very interesting at a time when we're seeing what we can replace C++ with. (yes, rusticles, I know rust exists)
- panpanna 6y agoI think go is mostly used to replace Python and Java & co.
- atilaneves 6y agoAnd yet, it's worse than both.
- hectorchu 6y agoI believe the correct term is 'rustaceans'.
- stunt 6y agoGo mostly has been only picking up easy wins so far. I haven't seen any attempt to go further than that. Which is fair strategy for first few years since everything comes with a cost. But, people now expect to see more obviously specially the more it's being compared to more sophisticated languages and compilers.
- gizzlon 6y ago> But, people now expect to see more obviously [..] I don't. I mean, yay for improvements, but it's already working great for my usecases.
- ozo9Caej 6y agoSame here. Go is now my daily driver and main language, and I'm perfectly satisfied with it. Quite the opposite of expecting more, I'm very fearful on what may change or be added in go-2 (which is actually a reason why I'm currently learning C, just in case).
- Cthulhu_ 6y agoPersonally, if Go takes a bad turn, I'm likely to just go back to JVM languages. Not Scala though, they went overboard with that one.
- pstuart 6y agoDisclaimer: I'm a Go fanboy so I'm biased. > if Go takes a bad turn The conservative nature of the Go team seems to recognize this worry. It's been bashed from the beginning for no generics but they are working on it. They just haven't found something that "feels right". Of course there's just no pleasing all the people all the time.
- dirtydroog 6y agoWhat are your usecases, if you don't mind me asking? I am considering replacing our HTTP-heavy processes currently written in C++ with Go. However, after reading this thread I'm not so sure. Compilation time isn't that big of an issue for us, but having a simpler way of doing networking would be a win. I can't tell if that ease of use would be trumped by poor performance.
- gautamcgoel 6y agoThe optimization I care about most is vectorization. A lot of ML and data science basically boils down to numerical linear algebra and optimization; vectorization is the key optimization for these kinds of problems. I bet if Go got a better autovectorizer it would compare more favorably against languages like Rust and C++ for numerical tasks. The trade-off, of course, is longer compile times, which I suspect will be unacceptable to the core Go team.
- pjmlp 6y agoEven Java and .NET do better on auto vectorization. Intel has recently published an article on using Go, their advice? Manually use cgo or Go Assembly for the AVX.
- hu3 6y agoApples to orange comparison. Java and .NET have different goals, around 2 decades of optimization and a lot more money thrown at them. Also, hi again pjmlp! Another Go thread, another nonconstructive Go bashing coming from you. From your other comments here I see you got pretty combative this time.
- pjmlp 6y agoStating facts is hardly bashing.
- hu3 6y agoVague statements without sources are not facts. And even without sources comparing Go to Java and .NET doesn't even make sense in the context.
- pjmlp 6y agoSince it is so hard for you to use Google, here you go: https://cr.openjdk.java.net/~vlivanov/talks/2017_Vectorization_in_HotSpot_JVM.pdf https://cr.openjdk.java.net/~vlivanov/talks/2017_Vectorizati... https://www.codeproject.com/Articles/1223361/Benchmarking-NET-Core-SIMD-performance-vs-Intel-IS https://www.codeproject.com/Articles/1223361/Benchmarking-NE... https://clearlinux.org/blogs-news/performant-containerized-go-applications-intel-advanced-vector-extensions-512-clear https://clearlinux.org/blogs-news/performant-containerized-g... Now go play with your facts.
- bjoli 6y agoI find it hard to fathom that many programming languages still don't use partial evaluation. That a popular language avoids inlining is even beyond that. Inlining us hard to do in ways that makes sure you always produce the optimal code, but simple conservative inlining is probably among the simplest and most efficient optimisations you can do. Edit: one of my favourite quotes is about the hardships of the heuristics of inliners: "I don't know how many of you have tried to write a good inliner. It is like barely being able to restrain a rabid dog on a leash". I probably mangled that, but originally it is a quote by Andy Wingo when talking about the improved optimisations of guile 2.2.
- kjksf 6y agoGo does inlining and their inlining heuristic has been tweaked over time.
- bjoli 6y agoThe example in the article is a typical function where I would expect inlining. Overly shy seems almost like an understatement.
- Thaxll 6y agoYou can see the reason actually: go build -gcflags="-m -m" . # _/tmp/inline ./main.go:7:6: cannot inline sum: unhandled op RANGE ./main.go:15:6: can inline fun as: func() uint64 { x := []uint64 literal; return sum(x) } ./main.go:3:6: can inline main as: func() { _ = fun() } ./main.go:4:9: inlining call to fun func() uint64 { x := []uint64 literal; return sum(x) } ./main.go:7:10: sum x does not escape ./main.go:4:9: main []uint64 literal does not escape ./main.go:16:15: fun []uint64 literal does not escape package main func main() { _ = fun() } func sum(x []uint64) uint64 { var sum = uint64(0) for _, v := range x { sum += v } return sum } func fun() uint64 { x := []uint64{10, 20, 30} return sum(x) } Go does not inline range operation.
- uryga 6y ago
- gautamcgoel 6y agoAnother pain point in Go I vaguely recall is that functions written in assembly are never inlined, so you always pay some penalty for using such functions (this may have changed in a more recent version of Go).
- ldeangelis 6y agoCorrect me if I'm wrong but comparing Go against Swift, C, C++, and Rust isn't really fair since one of Go's goals is compilation speed, in which it seems to shine against these other languages. From what I understand, you're going to trade performance against compilation speed, and Go is on the opposite side of these choices compared to the other languages.
- onei 6y agoRealistically, compilation speed is something every major language is going to try to improve upon to improve adoption. I haven't looked at the internals of the go compiler, but it seems a bit simplistic perhaps in the interest of improving speed. For example, it stops outputting errors after a point when it can clearly go further after having demonstrated that it's parser can recover. The error messages have lots of room for improvement, particularly compared to Rust.
- ldeangelis 6y agoI think one of the pain points that Go addresses is the compilation speed of large C++ projects at Google, and it's one of the reasons it was made in the first place. From what I know C++ and Rust are in the same ballpark in terms of compilation speed, while Go gives a noticeable improvement.
- pjmlp 6y agoWe could compare it with D, Ada, Object Pascal or Delphi, and it would lose on compilation speed, language features and quality of generated code.
- jhoechtl 6y agoClaims without a proof are just - claims
- pjmlp 6y agoClaims?!? Anyone can get the compilers and try them for themselves (except for Ada, which you can only get the free GNAT one). Language features are quite obvious, one just needs to look a language reference manual. The only claim is being lazy to accept facts and acknowledge that even Turbo Pascal for MS-DOS did it before Go.
- drej 6y agoA frustrating thing about inlining in Go is that there's a fairly arbitrary cost model and you sometimes end up fighting it (lookup George Tankersley's talks on YouTube). There have been tons of discussions about whether or not it should be user configurable, if inlining hints should happen at the call sites or function definitions etc. It's quite a nice discussion that helps people understand the toolchain. It also goes to show that while a self hosted build system is nice, you forgo decades of gcc/llvm optimisations. https://github.com/golang/go/issues/17566 https://github.com/golang/go/issues/17566
- pjmlp 6y agoThose optimizations could be taken advantage of via gccgo. Also many other languages keep having backend issues, because those optimizations are too focused on C and C++ code semantics.
- entha_saava 6y ago> Also many other languages keep having backend issues, because those optimizations are too focused on C and C++ code semantics. Attribute it to LLVM monoculture.
- jcranmer 6y agoAttribute it to benchmarks people care about being written in C/C++ (with maybe a dash of Fortran). e.g., SPEC CPU.
- JTenerife 6y agoNo benchmarks or any other numbers. I wonder how much faster some typical Go code (some CLIs, Hugo or webservices) will run? Around 1%, 5% or 10%? The Go compiler doesn't need to be smarter for Go's usecase. If it can be made smarter, fine. For best possible performance look at C/C++ or Rust.
- jorangreef 6y ago"No benchmarks or any other numbers." And yet plenty of logical argument. The author assumes a level of optimization experience on the part of the reader, for example that the reader appreciates the physical cost of branch mispredictions.
- bfrog 6y agoIt's too bad Go has poor performance calling C functions, if it didn't I think most issues with the language could be worked around.
- q3k 6y agoDoes it really, though? Go really isn't meant for number crunching, or any CPU-bound code, really. I think it's just fine for a language to not strive to emit the fastest possible code. I don't mind having an ecosystem where build times are fast in return for less optimized code. We already have plenty of languages that do the opposite (Rust, C++, Haskell, ...), and I would personally hate to see Go's compilation/link times creep up that level.
- Thaxll 6y agoHmm I disagree, Go is a language that should have workload that is CPU bound, Go is not Python or Ruby it's more C++ in that case. It can do heavy computation, I think it's just a balance of compiler optimization vs compile time.
- cies 6y agoGo is a Google project. You may disagree all you like but it's their project and hence their priorities. I would have loved for Go not to copy in the "null mistake", to have generics available to all and to have proper sum types built in. But it does not and Google is not keen on fixing this. So I look elsewhere: Rust, Kotlin, Reason/OCaml, ...
- sanderjd 6y agoMy take on this has long been that Go created a lot of confusion by initially selling itself as a better C++ when it is actually much closer to a better Python (outside of the data science use cases). Edit to add: Or a better / easier to deploy / less reviled / hipper Java. Go is a good and valuable language, but I think perhaps more than any language I know of, a lot of people go into it expecting it to be something that it is not.
- Touche 6y agoWhy am I using a language with pointers if it doesn't care about being fast? Another problem with not having a smart compiler is the gigantic binaries it produces. For wasm, an officially supported target, this makes it a non-starter.
- josefx 6y ago> In less fanciful languages like C or C++, the programmer needs to check what the processor supports themselves. I think by now most C++ compilers can target multiple combinations of feature flags and select a supported code path during program startup. The Intel compiler could do it years ago, but the resulting code was crippled on AMD CPUs.
- _wldu 6y ago"I do not mind that Go lacks exceptions or generics. These features are often overrated." I agree 100%. I've used them both in C++. I hope Go never gets them.
- alharith 6y agoGenerics, I would certainly be ecstatic for if it was done in a way that is novel and feels Go-like, so not Java or C# or C++'s implementations. This has certainly been the stance of the Go team since the beginning of time. It has never been "anti-generics" it's always been "we've studied all the generics implementations out there, and didn't feel like any one of them were good enough, so rather than shoehorn them in, we are being patient." This approach needs to be celebrated more. Exceptions, OTOH, I hope never see the light of day in Go. Curse them.
- jjice 6y agoWhat's wrong with the way that Java, C# a, and C++ handle generics? I see this complaint fairly regularly, but I was never sure why. Is it how the compiler handles it, or how the language defines it that is the reason for this dislike? Genuine curiosity.
- alharith 6y agoThis is the lazy answer I know, but I wanted to at least answer your genuine curiosity: There is ample research available online on the subject that explains it in depth and far better than I ever could. However, I will leave you with a few quotes that help at least paint the picture. From the Golang FAQ: > Generics are convenient but they come at a cost in complexity in the type system and run-time. We haven’t yet found a design that gives value proportionate to the complexity Quote from Russ Cox: > The generic dilemma is this: do you want slow programmers, slow compilers and bloated binaries, or slow execution times? Finally, one of the reasons the C++ or Java approach has never been palatable to Go core devs is summarized from this Rob Pike quote from his famous "Less is Exponentially More" blog post: > If C++ and Java are about type hierarchies and the taxonomy of types, Go is about composition So therefore it really is also a matter of finding a generics approach that lives up to that spirit as well. Contracts I think are approaching that. All that said, user defined generics (since technically speaking, Go has many generic capabilities today already) are coming to Go, they just aren't being rushed. I think we will be happy with the generics implementation in Go within the next year.
- vmchale 6y agothat would require rob pike to read papers written after 1970
- wwarner 6y agoWith its well defined AST, I think Go can "easily" accommodate optimizations as described, but obviously at the expense of compililation time. And I gotta tell you that keeping compile times down is the more important optimization for me. However, I happily add automated scans for safety and correctness into my release candidates, and I would gladly pay for optimizations at that point. As long as I can test rapidly with the knowledge that I can add an "-O3" flag just before release would be a perfect compromise for me.
- cogman10 6y agoI may have missed it, but this discussion seems to be lacking a key motivation of go. That is, the go devs have preferred a fast compiler over fast code output. I have a hard time imagining them adding a bunch of optimizations around code generation when those optimizations will almost certainly: * Slow down compile times * Increase compiler complexity * Be worse than what something like LLVM would produce. Maybe it makes sense to integrate a "release" build which targets LLVM? IDK. But I do know that so long as compilation speed is a major goal for the language the you simply won't see optimizations being seriously considered.
- zamadatix 6y agoDid you catch the note at the end about how gccgo is slower? If so how does pivoting to LLVM solve the issues seen there?
- cogman10 6y agoYou can read about the why here. https://stackoverflow.com/questions/25811445/what-are-the-primary-differences-between-gc-and-gccgo https://stackoverflow.com/questions/25811445/what-are-the-pr... The short answer is that there are optimizations that the GC is doing which gccgo is not doing. The long answer is that gc will do escape analysis which can avoid allocating on the heap, gccgo doesn't do that. Why might LLVM be better suited? Primarily because the framework also supports JIT and has efforts from the likes of Azul to make their JVM faster. Most optimizations that would benefit Java will benefit go. https://llvm.org/devmtg/2017-10/slides/Reames-FalconKeynote.pdf https://llvm.org/devmtg/2017-10/slides/Reames-FalconKeynote....