9 ms·
Show HN: Go Plan9 Memo
A quick dive into the Plan9 assembly I picked up while developing my SIMD package for Go, and how it led to a 450% performance boost in calculations.
- deleted 2y ago[deleted]
- pphysch 2y agoThis is neat. Why do you think this is not already part of the standard library?
- pehringer 2y agoI think the Go std lib is focused on portability over raw performance
- pjmlp 2y agoAnd ironically loses out to Java and .NET in raw performance, because language author's bias. In this case specifically, SIMD is available, via compiler supported auto-vectorization, and intrisics, no need to go down into Assembly.
- twoodfin 2y agoI think the more interesting architecture / priorities question is why the Go compiler can't yet(?) auto-vectorize?
- lexh 2y agoA bit over my head, but I enjoyed the way the writing brings us along for the ride. This can’t be the first pass someone has made at something like this, right? There must be literal dozens of SIMD thirsty Gophers around. Would a more common pattern be to use CGO?
- dpifke 2y ago(Rejected) proposal to add something like this to the standard library gives some context: https://github.com/golang/go/issues/53171 https://github.com/golang/go/issues/53171
- chrchang523 2y agoThe problem with cgo is the high function-call overhead; you only want to use it for fairly big chunks of work. Calling an assembly function from Go is a lot cheaper. https://pkg.go.dev/github.com/grailbio/base/simd https://pkg.go.dev/github.com/grailbio/base/simd has some work I’ve done in this vein.
- Andoryuuta 2y agoI think people certainly have been trying for a while. In fact, I recall being on a (Skype?) call with my brother almost a decade ago while he was trying to write an SIMD library in Go. If I remember correctly, at that time, a bunch of the AVX instructions weren't even encodable in Go's Plan9 assembler - so we had to manually encode them as bytes [0]. The most complete library I've seen (though admittedly never used) uses CGO _partially_, with a neat hack to avoid the overhead that it comes with [1]. [0]: https://github.com/slimsag/rand/blob/f1e8d464c0021a391d5cd646d1565a71c7fd80cc/simd/vec32.s#L6-L8 https://github.com/slimsag/rand/blob/f1e8d464c0021a391d5cd64... [1]: https://github.com/alivanz/go-simd/ https://github.com/alivanz/go-simd/
- tempfile 2y agoIs Plan9 in this context related at all to Bell Labs's Plan9? Seems too similar to be coincidence.
- kibwen 2y agoGo itself is from the same people who worked on Plan9 (which is why I find the choice of name in the OP particularly confusing).
- wrs 2y agoYes, some of the same people created Go.
- saclark11 2y agoYes. Two of Go's creators, Rob Pike and Ken Thompson, were also authors of Plan 9 at Bell Labs.
- deleted 2y ago[deleted]
- pjmlp 2y agoGo is the evolution of Limbo from Inferno, which was designed based on the failure of Alef on Plan 9, combined with a minor set of Oberon-2 influences.
- 201984 2y agoFrom https://go.dev/doc/asm https://go.dev/doc/asm: > The assembler is based on the input style of the Plan 9 assemblers, which is documented in detail elsewhere. If you plan to write assembly language, you should read that document although much of it is Plan 9-specific. That first sentence links to https://9p.io/sys/doc/asm.html https://9p.io/sys/doc/asm.html. So yes, definitely not a coincidence.
- rob74 2y agoIn case it's not obvious, the "Plan 9" in the Go Assembler's name comes from https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs, and the reason for that is of course that two of the "Go founders" (Rob Pike and Ken Thompson) are Bell Labs alumni. Some more background on the Go assembler: https://go.dev/doc/asm https://go.dev/doc/asm
- colechristensen 2y agoThe same people used the same name for two computer related projects. That's certainly an ... interesting choice.
- lagniappe 2y agoDefinitely don't look into Nix then
- lloeki 2y agoIt is, essentially, the same project. Plan9 is the umbrella term for the whole operating system. https://plan9.io/sys/doc/comp.html https://plan9.io/sys/doc/comp.html IIRC before Go was self compiling, it was compiled using 9c, and its architecture inherits from 9c. EDIT: some nearby threads got the details better!
- floren 2y ago> IIRC before Go was self compiling, it was compiled using 9c, and its architecture inherits from 9c. Back in those days I actually found that, with a few small tweaks, I could compile the Plan 9 operating system using Go's C suite. We didn't pursue it further but this was one of the options we looked into for cross-compiling Plan 9 from other operating systems.
- stonogo 2y agoSince to Go C suite was ported Plan 9 compilers, I'm not sure why this would be a surprise. Since I'm obviously missing something would you share your thoughts on what challenges you expected?
- nzach 2y ago> I am not sure why the Go team went down this route. Maybe it simplifies the compiler by having this bespoke assembly format? This was to allow for easy cross-compilation. You should probably clarify that you are talking about 'golang plan9 assembly format', and not about the plan9 OS. This confused me a lot. (https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs) I didn't know you could easily hand write 'golang assembly' for your functions. This seems really useful in some cases. But I do wonder, why the std lib doesn't offer this ? EDIT: I found the anwser: https://github.com/golang/go/issues/53171 https://github.com/golang/go/issues/53171 Here is a good explanation provided by Ian Lance Taylor: > This proposal is focused on code generation rather than language, and the details of how it changes the language are difficult to understand. Go is intended to be a simple language that it is easy to understand. Introducing complex semantics for performance reasons is not a direction that the language is going to take.
- deleted 2y ago[deleted]
- pehringer 2y agoIf you want to see some Plan9 in the std library check out the math package! https://github.com/golang/go/tree/master/src/math https://github.com/golang/go/tree/master/src/math
- sph 2y agoPlan 9 has nothing to do with assembly language nor the variant Go uses. See other comments in this thread. It would be like calling the AT&T style of assembly used by GNU binutils a "Linux"
- saclark11 2y ago> Overall, pretty weird stuff. I am not sure why the Go team went down this route. Maybe it simplifies the compiler by having this bespoke assembly format? Rob Pike spoke on the design of Go's assembler at a talk in 2016 [1][2]. I think it basically came down to the observation that most assembly language is roughly the same, so why not build a common assembly language that "lets you talk to the machine at the lowest level and yet not have to learn a new syntax." It also enables them to automatically generate a working assembler given an instruction manual PDF for a new architecture as input. [1]: https://www.youtube.com/watch?v=KINIAgRpkDA https://www.youtube.com/watch?v=KINIAgRpkDA [2]: https://go.dev/talks/2016/asm.slide#1 https://go.dev/talks/2016/asm.slide#1
- alphazard 2y agoAnd it worked. Go established cross-compilation as table-stakes for new programming languages, at a time when very few were doing it well, if at all.
- p_l 2y agoGo essentially copied the design from Plan9 compilers, which it was originally based on. It's one of the many things it inherited from Plan9 environment.
- kjksf 2y agoIt's more "reused" because Plan9 compilers were designed / co-implemented by Pike / Thomson, 2 out of 3 original designers of Go. For those interested, here's Thomson's paper about Plan9 C compilers: https://9p.io/sys/doc/compiler.html https://9p.io/sys/doc/compiler.html and https://doc.cat-v.org/bell_labs/new_c_compilers/ https://doc.cat-v.org/bell_labs/new_c_compilers/
- derefr 2y agoI would love to see a deep dive on what features / architectural paradigms the Golang runtime shares with Plan9. Has anything like that been written? One that always sticks out to me personally is the use in Go of the term "dial" instead of "connect" for network connection establishment. This is, AFAICT, another Pike+Thompson-ism, as it can be seen previously in the form of the Plan9 dial(3) syscall — https://9fans.github.io/plan9port/man/man3/dial.html https://9fans.github.io/plan9port/man/man3/dial.html . --- A tangent: I have wondered before whether Pike and Thompson drafted the design for the language that would become Golang long before working at Google, initially to replace C specifically in the context of being the lingua-franca for systems programming on Plan 9. And that, therefore — at least in the designer's minds — Golang would have always had Plan9 as its secret "flagship target" that it should have a 1:1 zero-impedance abstraction mapping onto. Even if they never bothered to actually make a Plan9 Golang runtime. You could test this hypothesis by implementing an actual Golang runtime for Plan9†, and then comparing it to the Golang runtimes for other OSes — if Plan9 were the "intended home" for Golang programs, then you'd expect the Golang runtime to be very "thin" on Plan9. (To put that another way: imagine the Golang runtime as something like WINE — a virtualization layer that implements things that could be syscalls / OS library code, in the form of client-side runtime shim code. A "WINE implementation for Windows" would be an extremely thin shim, as every shim call would just point to a 1:1-API-matched piece of OS-provided code. My hypothesis here is that "Golang for Plan9" is the same kind of thing as "WINE for Windows.") † I was saying this as a thought experiment, not thinking there would actually be a Plan9 implementation of the Golang runtime... but there is! (https://go.dev/wiki/Plan9 https://go.dev/wiki/Plan9) So someone can actually check this :)
- mxey 2y ago> After doing some preliminary research I discovered that Go uses its own internal assembly language called Plan9. Is the language actually called that?
- nzach 2y agoThis is a fair question. Initially I just assumed this was true. Because someone who did research on this topic would not get something like this wrong. And besides that, if you know a little about the project this name could make some sense. But the more I look into it, the more I think this is just a LLM hallucination. The doc about the 'assembly' format doesn't give a proper name. It just calls 'go assembler'. And I think the source of this hallucination was this first paragraph: > The assembler is based on the input style of the Plan 9 assemblers, which is documented in detail elsewhere. If you plan to write assembly language, you should read that document although much of it is Plan 9-specific. The current document provides a summary of the syntax and the differences with what is explained in that document, and describes the peculiarities that apply when writing assembly code to interact with Go.
- jamal-kumar 2y agoMaybe you should actually read something from the official website before spending time writing multiple paragraphs assuming it's fake. Alot of the people involved in golang also were involved in bell lab's plan9 project, going back to the 1980s (Kernighan and Pike especially go back that far). The CSP threads from plan9 were influential in the development of the programming language. And you can find this on their official site: https://go.dev/doc/asm https://go.dev/doc/asm
- Thorrez 2y agoRuss Cox (rsc), former tech lead of Go, replied above, saying the language is not called Plan9. The link you provided doesn't say the language is called Plan9. Also, nzach quoted from that page.
- mseepgood 2y ago
- spiffistan 2y agoThere was a controversy when Go came out about the naming due to another language also being called Go, and the top voted alternative name was Plan9, and as an homage they may have used that internally instead.
- stonogo 2y agoThe top voted alternative was "Issue 9" which served as a reference to Plan 9 and happened to be the actual issue number in the Go project on Google Code opened by the guy who's programming language (named "Go!") was already out there.
- spiffistan 2y agoYou're right, my bad
- umvi 2y ago> Basically, I wanted a set of functions that would allow me to perform simd operations on slices. How is this actually used though? I searched the whole article, and no where are any operations being performed on slices. Edit: I found what I was looking for in the linked docs: https://pkg.go.dev/github.com/pehringer/simd#pkg-index https://pkg.go.dev/github.com/pehringer/simd#pkg-index So basically if you have 2 slices you want to add together, instead of a for loop you could do it in parallel with simd using: simd.AddInt32(slice1, slice2, result)
- pehringer 2y agoI should have added some examples in the docs / repo :( checkout the benchmark code at the bottom of this file for an example: https://github.com/pehringer/simd/blob/main/simd_test.go https://github.com/pehringer/simd/blob/main/simd_test.go
- joeegan2202 2y agoA couple points on Go assembly: 1. On amd64 those ints are actually 64bit. If you used int32 then they would be be word aligned in the parameter list. However, there is a gotcha with that. The return values will always start at a dword aligned offset on 64bit system. 2. NOSPLIT is defined in "textflag.h" which Go's compiler automatically provides. However, NOSPLIT is, from everything I've read, only respected on runtime.XX functions, so it's not doing anything there, and it's also not necessary. NOSPLIT tells the compiler not to insert code to check if the stack needs to split because it's going to overflow, which is technically unnecessary if the function doesn't need any stack space. It's basically only there on the function that checks for stack splits, to prevent that code from being injected into itself.
- pehringer 2y agoThank you for the explanation! That makes a lot more sense :)
- deleted 2y ago[deleted]
- pixelesque 2y agoVery minor nit, doesn't change anything about the article otherwise, but the SIMD acronym stands for *Single* Instruction, Multiple Data conventionally.
- deleted 2y ago[deleted]
- sedatk 2y ago> 4 represents “NOSPLIT” which we need for some reason For those who are curious: "In the general case, the frame size [the parameter after NOSPLIT] is followed by an argument size, separated by a minus sign. (It's not a subtraction, just idiosyncratic syntax.) The frame size $24-8 states that the function has a 24-byte frame and is called with 8 bytes of argument, which live on the caller's frame. If NOSPLIT is not specified for the TEXT, the argument size must be provided. For assembly functions with Go prototypes, go vet will check that the argument size is correct." Source: https://go.dev/doc/asm https://go.dev/doc/asm
- cmovq 2y ago> However, (as far as I can tell) Go’s compiler does not utilizes simd Can someone confirm this? Not even for straightforward copies?
- znkr 2y agoGo has a couple of SIMD uses. Copies is one of them.
- kristianp 2y agoRelevant to which processors go supports, is this section (1). Base x64 support includes SSE and SSE2. I don't know if the go compiler produces it, though. Unlike extremely complex compilers like gcc, where performance is the top priority, the go compiler favours simplicity in a Wirthian(2) fashion favouring a simple, fast compiler. (1) https://go.dev/wiki/MinimumRequirements#amd64 https://go.dev/wiki/MinimumRequirements#amd64 (2) https://irreal.org/blog/?p=7075 https://irreal.org/blog/?p=7075 https://smartgo.blog/2024/01/06/niklaus-wirth/ https://smartgo.blog/2024/01/06/niklaus-wirth/
- physicsguy 2y agoI think in practice every chip since about 2008 or so has supported SSE4.1
- imiric 2y agoThis is neat, and it's great that Go provides such simple access to low-level primitives. But for the particular case of SIMD operations, wouldn't it make more sense to use the GPU instead of the CPU? GPUs excel at parallelism and matrix operations, so the performance difference would be even greater. I suppose the lack of well maintained GPU packages and community around it don't make Go particularly well suited for this.
- physicles 2y agoFor a tool you run locally, a GPU could be an easy win. But most Go code is probably run on cloud servers. Adding requirements to your runtime environment isn't something to do lightly. - SIMD: up to 400% speed boost, most likely on the same VMs you were already using - GPU: orders of magnitude faster, but now you need to make sure your cloud servers have compatible GPUs attached If you really do need crazy performance then it's worth it. If you're already stable and right-scaled and SIMD allows you to reduce your VM spend by 25%, then you probably just take the savings and move on.
- crtc 2y agohttps://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs since the author seems to be confused in this regard.
- endofreach 2y agoI was gonna say this it seems like an LLMisinterpretation of the code. I can't think of any other way how one would know the term plan9 and how to dive into assembly while not knowing what waters he is in. And then i read others had the same thought. If this is true, i kindly ask the author to not feel embarrassed or "exposed", but be honest, so we can learn from this. I'd like to gain confidence in these type of "LLM exposed" things, but it never seems like people would admit, no matter how obvious. And of course, here it is not obvious, this is of course a wild, very judgemental guess.
- rf15 2y agoHonestly? No. Please feel embarrassed about your sheer arrogance to think that LLMs are a viable shortcut to not having to do The Work. This pisses me off so much.
- indulona 2y ago[flagged]
- sfc32 2y ago> Performace And The Future There's a typo on "Performance"
- ashvardanian 2y agoIt’s a shame that nobody mentioned PeachPy in this thread: https://github.com/Maratyszcza/PeachPy https://github.com/Maratyszcza/PeachPy
- kunley 2y agoErm... The title is rather wrong.. doesn't encourage thinking the author has actually understanding of the topic - I like to think he had, but the way he writes about the topic, also within the article, is confusing at least.. I mean, the fact that Go has own Plan9-derived format for assembler, has absoluely nothing to do with the task author aims to solve.
- kunley 2y agoFew technical comments: Go's calling convention is using registers, except when writing own assembly functions then it's stack-based; the latter is also how it worked in the past. See https://go.dev/s/regabi https://go.dev/s/regabi and https://go.dev/doc/asm https://go.dev/doc/asm Build tags have a form "go:build" not "+build" since Go 1.17, that is for couple of years already. More about build tags: using both build tags and filename suffix for arch-based conditional compilation is redundant. Just use one of them, not both.
- GarrettBodley 2y agoI would recommend checking out Avo (https://github.com/mmcloughlin/avo https://github.com/mmcloughlin/avo) if you're interesting in writing Go assembly programs. It provides type safety and does some checks to ensure you output valid assembly. It can dynamically allocate registers for you and calculate things like stack and frame size so you don't have to do that by hand. It also can handle calling convention details for you, very easy to load an argument into whatever register/location you'd like. I recently ported all of the amd64 assembly in Go's crypto libraries over to Avo. Very useful library for this sort of work!
- butterisgood 2y agoI love seeing Plan 9 here, but it’s just Go Assembly with Plan 9 syntax.