ニクニクドットミー

カッコいいおっさんを目指すエンジニアの厳かなブログ

GOTRACEBACKのメモ

182b65b9 539c 4d24 9b1f ee4a1a8756f1

GOTRACEBACKという環境変数があり、それを設定することによって、go runしたときのプログラムのトレースバックが変わるようです。

The GOTRACEBACK variable controls the amount of output generated when a Go program fails due to an unrecovered panic or an unexpected runtime condition. By default, a failure prints a stack trace for every extant goroutine, eliding functions internal to the run-time system, and then exits with exit code 2. If GOTRACEBACK=0, the per-goroutine stack traces are omitted entirely. If GOTRACEBACK=1, the default behavior is used. If GOTRACEBACK=2, the per-goroutine stack traces include run-time functions. If GOTRACEBACK=crash, the per-goroutine stack traces include run-time functions, and if possible the program crashes in an operating-specific manner instead of exiting. For example, on Unix systems, the program raises SIGABRT to trigger a core dump.

Google先生で翻訳したところ、

GOTRACEBACK = 0は、単位のゴルーチンスタックトレースが完全に省略している場合は終了コード2で終了します。

GOTRACEBACK = 1の場合、デフォルトの動作が使用されます。

GOTRACEBACK = 2場合は、単位のゴルーチンスタックトレースは、実行時の機能が含まれます。

以下のサンプルコードで試してみました。


package main


import (
        "log"
        "runtime"
)

func main(){
        log.Println(runtime.NumGoroutine()) //動いているゴルーチンの数
        select{}
}

GOTRACEBACK=0


[root@localhost vagrant]# GOTRACEBACK=0 go run sample.go
2015/02/12 13:39:00 4
fatal error: all goroutines are asleep - deadlock!
exit status 2

終了ステータスコードとエラーメッセージが出力されます。

GOTRACEBACK=1


[root@localhost vagrant]# GOTRACEBACK=1 go run sample.go
2015/02/12 13:40:02 4
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [select (no cases)]:
main.main()
    /vagrant/sample.go:11 +0xd5
exit status 2

終了ステータスコードとどの行でエラーになったか出力されます。

GOTRACEBACK=2


[root@localhost vagrant]# GOTRACEBACK=2 go run sample.go
2015/02/12 13:40:17 4
fatal error: all goroutines are asleep - deadlock!

runtime stack:
runtime.throw(0x54f7e3)
    /usr/local/go/src/runtime/panic.go:491 +0xad fp=0x7fff416d3b58 sp=0x7fff416d3b28
checkdead()
    /usr/local/go/src/runtime/proc.c:2854 +0x1f8 fp=0x7fff416d3ba8 sp=0x7fff416d3b58
mput(0x551e40)
    /usr/local/go/src/runtime/proc.c:3175 +0x47 fp=0x7fff416d3bb0 sp=0x7fff416d3ba8
stopm()
    /usr/local/go/src/runtime/proc.c:1176 +0xea fp=0x7fff416d3bd0 sp=0x7fff416d3bb0
findrunnable(0xc208012000)
    /usr/local/go/src/runtime/proc.c:1487 +0x562 fp=0x7fff416d3c08 sp=0x7fff416d3bd0
schedule()
    /usr/local/go/src/runtime/proc.c:1575 +0x151 fp=0x7fff416d3c38 sp=0x7fff416d3c08
runtime.park_m(0xc2080006c0)
    /usr/local/go/src/runtime/proc.c:1654 +0x113 fp=0x7fff416d3c60 sp=0x7fff416d3c38
runtime.mcall(0x42d204)
    /usr/local/go/src/runtime/asm_amd64.s:186 +0x5a fp=0x7fff416d3c70 sp=0x7fff416d3c60

goroutine 1 [select (no cases)]:
runtime.gopark(0x0, 0x0, 0x4ef830, 0x11)
    /usr/local/go/src/runtime/proc.go:130 +0x105 fp=0xc20802df08 sp=0xc20802ded8
runtime.block()
    /usr/local/go/src/runtime/select.go:176 +0x46 fp=0xc20802df30 sp=0xc20802df08
main.main()
    /vagrant/sample.go:11 +0xd5 fp=0xc20802df98 sp=0xc20802df30
runtime.main()
    /usr/local/go/src/runtime/proc.go:63 +0xf3 fp=0xc20802dfe0 sp=0xc20802df98
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc20802dfe8 sp=0xc20802dfe0

goroutine 2 [force gc (idle)]:
runtime.gopark(0x42edb0, 0x5516e0, 0x4e49d0, 0xf)
    /usr/local/go/src/runtime/proc.go:130 +0x105 fp=0xc20801a798 sp=0xc20801a768
runtime.goparkunlock(0x5516e0, 0x4e49d0, 0xf)
    /usr/local/go/src/runtime/proc.go:136 +0x48 fp=0xc20801a7c0 sp=0xc20801a798
runtime.forcegchelper()
    /usr/local/go/src/runtime/proc.go:99 +0xce fp=0xc20801a7e0 sp=0xc20801a7c0
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc20801a7e8 sp=0xc20801a7e0
created by runtime.init·4
    /usr/local/go/src/runtime/proc.go:87 +0x25

goroutine 3 [GC sweep wait]:
runtime.gopark(0x42edb0, 0x558978, 0x4e21f0, 0xd)
    /usr/local/go/src/runtime/proc.go:130 +0x105 fp=0xc20801df98 sp=0xc20801df68
runtime.goparkunlock(0x558978, 0x4e21f0, 0xd)
    /usr/local/go/src/runtime/proc.go:136 +0x48 fp=0xc20801dfc0 sp=0xc20801df98
runtime.bgsweep()
    /usr/local/go/src/runtime/mgc0.go:98 +0xbc fp=0xc20801dfe0 sp=0xc20801dfc0
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc20801dfe8 sp=0xc20801dfe0
created by gc
    /usr/local/go/src/runtime/mgc0.c:1383

goroutine 4 [finalizer wait]:
runtime.gopark(0x42edb0, 0x558970, 0x4e4550, 0xe)
    /usr/local/go/src/runtime/proc.go:130 +0x105 fp=0xc208019730 sp=0xc208019700
runtime.goparkunlock(0x558970, 0x4e4550, 0xe)
    /usr/local/go/src/runtime/proc.go:136 +0x48 fp=0xc208019758 sp=0xc208019730
runtime.runfinq()
    /usr/local/go/src/runtime/malloc.go:727 +0xba fp=0xc2080197e0 sp=0xc208019758
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc2080197e8 sp=0xc2080197e0
created by runtime.createfing
    /usr/local/go/src/runtime/malloc.go:707 +0x5e
exit status 2

長いです。終了ステータスコードと他に動いてるゴルーチンが出力されます。

こう思った

GOTRACEBACK=2で他のゴルーチンがわかるのは便利かも。 なぜall goroutines are asleep - deadlock!となるのかは謎。。。