What is an inline function

In many technical materials and blogs about the underlying Go language, the term “inline function” is mentioned. Some people also refer to the inline function as code inlining, function expansion, function expansion and so on. In fact, what they want to express is the optimization of function call by Go compiler. The compiler will replace some function calls directly with the code inside the called function being expanded at the call point to reduce the time consumed by the function calls. It is a common way for the Go language compiler to optimize code.

Inline functions are not unique to Go compilers. Compilers in many languages optimize inline functions when compiling code. Wikipedia explains inline functions as follows (I’ve highlighted important information in bold) :

In computer science, an inline function (sometimes called an online function or compile-time expansion function) is a programming language construct that suggests that the compiler extend inline (sometimes called an online extension) for a particular function; That is, it is recommended that the compiler insert the specified function body instead of the context where the function is called, thus saving extra time for each call. However, when choosing to use inline functions, there must be a trade-off between the space occupied by the program and the efficiency of the program execution, because too many more complex functions for inline extension will incur a large storage resource expenditure. It is also important to note that inline extensions to recursive functions can cause infinite compilation of partial compilers.

Note: Inline optimizations are generally used for functions that can execute quickly, because the time consumption of function calls is more prominent in this case, and inlining smaller functions does not significantly increase the space taken up by compiled execution files.

Inline functions in Go

For example, suppose I have a program that adds two numbers (don’t worry, it’s not an algorithm – sum of two numbers…).

package main
import "fmt"
func main(a) {
  x := 20
  y := 5
  res := add(x, y)
  fmt.Println(res)
}

func add(x int, y int) int {
 return x + y
}
Copy the code

The above function is very simple. The add function adds the two parameters. The compiler will do inline optimization when compiling the above Go code, and expand the add function body directly at the call point.

package main
import "fmt"
func main(a) {
  x := 20
  y := 5
  // Inline the function, or expand the function at the point of call
  res := x + y 
  fmt.Println(res)
}

func add(x int, y int) int {
 return x + y
}
Copy the code

Tells the compiler not to inline functions

The call to add is also not seen in the source compiled assembly code, but we can tell the compiler not to optimize it inline by adding a special comment to the add function

// Note the following line of comments, with no Spaces after "//"
//go:noinline
func add(x int, y int) int {
 return x + y
}
Copy the code

How do you verify that this comment is valid so that the compiler doesn’t do inline optimization for the add function? We can use go tool compile-s scratch.go to print the GO code is compiled into assembly code, in the assembly code we can find the call to add function.

0x0053 00083 (scratch.go:6)  CALL    "".add(SB)
Copy the code

This also reverses the fact that the Go compiler normally optimizes the add function inline.

Let the compiler tell us what optimizations will be made to the code

In addition to parsing the compiled assembly source, we can also pass the -gcflags -m argument to the go build command

$ go build -gcflags --help[...] // Passing the -m option prints the compiler's optimization decisions for the codeCopy the code

Let the compiler tell us what it’s doing to optimize the Go code as it compiles it.

Let’s build our applet with -gcFlags -m

$ go build -gcflags -m scratch.go

./scratch_16.go:10:6: can inline add
./scratch_16.go:6:12: inlining call to add
./scratch_16.go:7:13: inlining call to fmt.Println
./scratch_16.go:7:13: res escapes to heap
./scratch_16.go:7:13: main []interface {} literal does not escape
./scratch_16.go:7:13: io.Writer(os.Stdout) escapes to heap
Copy the code

As you can see from the terminal output, the compiler determines that the add function can be inlined, and it inlines the add function, as well as optimizations for FMT.Println. An output for IO.Writer(os.stdout) escapes to heap represents I/O objects escaping to the heap. Heap escape is another optimization discussed in detail in the previous Go Memory Management series — Escape analysis of the Go Memory Management code.

Which functions are not inlined

Does Go’s compiler optimize all small, fast functions inline? I checked the data and found that Go has a standard for deciding whether to inline a function:

Functions that contain closure calls, select, for, defer, and go keywords are not inlined. And beyond that, there are other limitations. When parsing the AST, Go claims 80 nodes as an inline budget. Each node consumes one budget. For example, the line a = a + 1 contains five nodes: AS, NAME, ADD, NAME, LITERAL. The following is the corresponding SSA dump:

When the cost of a function exceeds this budget, it cannot be inlined.

The above description is translated from the article: medium.com/a-journey-w…

conclusion

Inlining is an important means of high performance programming. Each function call has overhead: creating stack frames, reading and writing registers, all of which can be avoided by inlining, resulting in a performance improvement of around 5-6%. Inline copying of function bodies also increases the size of compiled binaries, but the good news is that when programming with Go, the compiler helps us decide which functions can be inlined, greatly reducing the mental burden on the user.

That’s all for today’s article, please give me a thumbs up if you like my article, AND I will share what I have learned and seen and first-hand experience through technical articles every week. Thank you for your support. Wechat search concerns the public number “network management talking BI talking” every week to teach you an advanced knowledge, there are special for the development of engineers Kubernetes tutorial.