Goのコンパイル時の最適化結果を確認する（インライン化の条件についても記載）

はじめに
--------------------
下記のページの「Quick look at some compiler’s optimizations」の翻訳のようなものです。そもそも下記のページを見つけるのに結構苦労した＆日本語情報があまりなかったのでメモ。

- [Chapter 11: Tips and Tricks | Go Bootcamp | Softcover.io](http://www.golangbootcamp.com/book/tricks_and_tips)

## 最適化の結果を確認する
- `go build` や `go test` の際に `-gcflags=-m` をつけると下記のように最適化結果が出力される

```shell-session
$ go build -gcflags=-m t.go
# command-line-arguments
./t.go:15: can inline NewUser
./t.go:21: inlining call to NewUser
./t.go:10: leaking param: u
./t.go:10: leaking param: u
./t.go:12: (*User).Greetings ... argument does not escape
./t.go:15: leaking param: name
./t.go:15: leaking param: location
./t.go:17: &User literal escapes to heap
./t.go:15: leaking param: name
./t.go:15: leaking param: location
./t.go:21: &User literal escapes to heap
./t.go:22: main ... argument does not escape
```

ちなみに `t.go` はこんな感じ

```go
package main

import "fmt"

type User struct {
	Id             int
	Name, Location string
}

func (u *User) Greetings() string {
	return fmt.Sprintf("Hi %s from %s",
		u.Name, u.Location)
}

func NewUser(id int, name, location string) *User {
	id++
	return &User{id, name, location}
}

func main() {
	u := NewUser(42, "Matt", "LA")
	fmt.Println(u.Greetings())
}
```

## `can inline XXX`
> The compiler notices that it can inline the NewUser function defined on line 15 and inline it on line 21. Dave Cheney has a great post about why Go’s inlining is helping your programs run faster.

- 関数`XXX`はインライン化の条件を満たしているからインライン化できるよ

## `inlining call to XXX`
- `can inline XXX` は、あくまで「関数 `XXX` がインライン化の条件を満たしているよ」と言っているだけで、実際にインライン化はされていない
- `inlining call to XXX` は、関数 `XXX`の呼び出し箇所に対して、「実際に関数`XXX`の呼び出しをインライン化したよ」という意味

## `leaking param`
> On a few lines, you see the potentially alarming leaking param message. It doesn’t mean that there is a memory leak but that the param is kept alive even after returning. The “leaked params” are:

- メモリリークじゃないから安心して
- 関数が終わっても変数が生き続けるよ（golangだと関数内て定義した変数をreturnできる）

## `X argument does not escape`
> X argument does not escape means that the argument doesn’t “escape” the function, meaning that it’s not used outside of the function so it’s safe to store it on the stack.

- 変数 `X` は関数内でしか使用されていない（からスタックに積めるよ）

## `X escapes to heap`
> On the other hand, you can see that &User literal escapes to heap. What it means is that the address of a literal value is used outside of the function and therefore can’t be stored on the stack. The value could be stored on the stack, except a pointer to the value escapes the function, so the value has to be moved to the heap to prevent the pointer referring to incorrect memory once the function returns. This is always the case when calling a method on a value and the method uses one or more fields.

- 変数が関数外で使用されているからスタックに積めない（からヒープに移動するよ）

意外と好評なので追記
--------------------
インライン化される条件については [CompilerOptimizations · golang/go Wiki](https://github.com/golang/go/wiki/CompilerOptimizations) を参照のこと

> Only short and simple functions are inlined. To be inlined a function must contain less than ~40 expressions and does not contain complex things like function calls, loops, labels, closures, panic's, recover's, select's, switch'es, etc.

- 40 行程度より小さい関数じゃなきゃダメ
- 下記が入っててもダメ
    - 関数呼び出し
    - ループ
    - ラベル
    - クロージャ
    - panic/recover
    - select
    - switch

結構厳しいなぁ...