Live data from Hacker News

Mid-stack inlining in the Go compiler

docs.google.com

31–40 of 76 posts

Re: Mid-stack inlining in the Go compiler

#31
post #19

This is interesting work! That said, it's a little disappointing when runtimes require custom algorithms or metadata to walk the stack and construct a stack trace. It makes it harder to build debuggers that grok the state of multiple runtimes (e.g., the Go code and the C code in the same program). This also affects runtime tracing tools like DTrace, which by construction can't rely on runtime support for help.

We plan to expose all of the inlining information in the DWARF tables so debuggers won't have any problems with this. Internally, the runtime uses a different representation just so we can make it more compact and optimized for the runtime's exact needs. This way, you can also strip the debug info without breaking the runtime's own ability to walk stacks.

Isn't that what `.eh_frame` is for?

Re: Mid-stack inlining in the Go compiler

#32

9% faster, 15% bigger. I'll take that!

FWIW: This is actually not that great, but it's a good start. You should be able to get about 15-20% with about 3-5% binary increase size. In fact, with ThinLTO, we often see that gain with binary size decrease from smart inlining choices. (The heuristics for inlining take a very very long time to get right and tune) The issue they will next hit is that inlining is going to make the compiler slower until they tune th…

If I'm understanding the increase is mostly due to the "debugging" info that is added, not necessarily due to more code.

Re: Mid-stack inlining in the Go compiler

#33

Earlier quoted context omitted.

FWIW: This is actually not that great, but it's a good start. You should be able to get about 15-20% with about 3-5% binary increase size. In fact, with ThinLTO, we often see that gain with binary size decrease from smart inlining choices. (The heuristics for inlining take a very very long time to get right and tune) The issue they will next hit is that inlining is going to make the compiler slower until they tune th…

If I'm understanding the increase is mostly due to the "debugging" info that is added, not necessarily due to more code.

I strongly doubt this. It doesn't say this in the preso, and ...

1. The compiler is a lot slower, which is usually from code growth and not debugging info growth. If the compiler is that much slower from debugging info growth, they have larger issues :) 2. Usually people do not include debug info sizes in binary sizes, because DWARF/et al info can be stripped and put alongside the binary (IE it doesn't even have to be part of the binary)

Re: Mid-stack inlining in the Go compiler

#34
post #8

It doesnt look like this solves inlining library calls?

Go already performs cross-package inlining, so it can already inline library calls. (This is relatively easy to do in Go compared to other languages because packages must form a DAG. Compiling package A writes out enough information in the object file for A that compiling package B that depends on A can inline calls to functions in A.)

"Compiling package A writes out enough information in the object file for A that compiling package B that depends on A can inline calls to functions in A"

So it records the calling convention, architecture flags, alignment, and other ABI pieces etc? As well as an estimate of instruction-level inlining cost, summary info about arguments, etc, so you effectively decide whether inlining it will help or hurt, without having the IR around to try?

FWIW: Writing out the info is usually not the hard part, actually, and is unrelated to the DAG-ness of the packages.

GCC is just the perennial example here, but they refused to write it out for years for political reasons, not technical ones :)

Re: Mid-stack inlining in the Go compiler

#35
post #9

In case someone else is wondering: What is being called "mid-stack inlining" here is what is generally understood by the term "inlining".

The presentation makes a distinction between mid-stack and leaf inlining, and apparently it was only done on leaf calls before because this is less confusing in backtraces.

The point is, as usual, Go is trying to catch up to what everyone else has had for years. The use of non-standard terminology here is suspicious, raising the question that the Go people are trying to hide the fact that they are playing catch-up.

Re: Mid-stack inlining in the Go compiler

#36

Earlier quoted context omitted.

Go statically links to all Go libraries, and only dynamically links when interfacing with C code. (As of the last time I used it, a couple years ago; this may have changed since then.)

That doesn't really answer whether it can inline library functions. The fact that it statically links means it potentially could inline methods it finds in them but I don't think that it does currently since it appears that this inline functionality works when compiling source.

It can inline library functions, since, at latest, 1.4.2 (this is just what I happened to have handy on this computer). It's pretty easy to test by writing a package containing a simple function like "func Square(x int) int { return x * x }", compiling a main package that imports that package and calls Square, and then disassembling the executable to see whether it calls Square or inlines it.

Re: Mid-stack inlining in the Go compiler

#37

9% faster, 15% bigger. I'll take that!

Increased sizes lead to less effective use of instruction caches. Different use cases will be impacted differently by that, so it's worth profiling your particular application, at least until the size overhead comes down.

Re: Mid-stack inlining in the Go compiler

#38

Earlier quoted context omitted.

Go already performs cross-package inlining, so it can already inline library calls. (This is relatively easy to do in Go compared to other languages because packages must form a DAG. Compiling package A writes out enough information in the object file for A that compiling package B that depends on A can inline calls to functions in A.)

"Compiling package A writes out enough information in the object file for A that compiling package B that depends on A can inline calls to functions in A" So it records the calling convention, architecture flags, alignment, and other ABI pieces etc? As well as an estimate of instruction-level inlining cost, summary info about arguments, etc, so you effectively decide whether inlining it will help or hurt, without hav…

"So it records the calling convention, architecture flags, alignment, and other ABI pieces etc?"

No. At the moment it records the AST in the object file, because the inliner works at the Go AST level. In the future it may instead record the SSA representation (which would obviously give better cost estimates; the current heuristics are really extremely simple).

"FWIW: Writing out the info is usually not the hard part, actually, and is unrelated to the DAG-ness of the packages."

The DAG-ness means it's always available when compiling the call site, even if it's a cross-package call. It means you don't have to do it at link time.

Re: Mid-stack inlining in the Go compiler

#39
post #9

In case someone else is wondering: What is being called "mid-stack inlining" here is what is generally understood by the term "inlining".

The presentation makes a distinction between mid-stack and leaf inlining, and apparently it was only done on leaf calls before because this is less confusing in backtraces.

leaf calls, and calls must not be complicated (no function calls, no loops, no switches in calls).

I for one am very glad that more work is put into inlining

Re: Mid-stack inlining in the Go compiler

#40
post #26

What impact would that have on build times? I know a lot of work has gone into getting back to 1.4 build times, but would the added work of inlining prolong builds?

The compiler got a bit slower: https://github.com/golang/go/issues/19386 Those numbers are just for my CLs that fix stack traces but with mid-stack inlining still off. Turning it on makes builds noticeably slower: $ time ./make.bash real: 45.32s user: 118.67s cpu: 5.85s $ time GO_GCFLAGS='-l=4' ./make.bash real: 64.51s user: 167.04s cpu: 7.12s We'll need to tweak the inlining heuristic to find a good balance between…

Please have a switch where I can sacrifice build time for maximum possible runtime benefits.
Post reply on HN