[golang] runtime package についてのメモ

Created on 2018-03-05
Modified on 2018-06-25
Published on 2018-03-11


Golang 1.9 ~ 1.10くらいのときに調べた内容。 古くなっている情報を見つけたら教えてくれると嬉しいです。

Goroutine IDを取得する

標準ランタイムでは、stacktraceから取得する方法がある。 しかし、非常に遅い。

const backtraceSize = 1 << 16 // about 64KiB
const gidRegExp = regexp.MustCompile(`^goroutine (\d+)`)

// GoID returns the Goroutine ID.
func GoID() {
    var buf [backtraceSize]byte
    runtime.Stack(buf[:], false) // First line is "goroutine xxx [running]"
    matches := gidRegExp.FindSubmatch(buf[:])
    gid, err := strconv.ParseInt(string(matches[1]), 10, 64)
    if err != nil {
        log.Panic(err)
    }
    return logutil.GID(gid)
}

runtimeパッケージにこのようなパッチを当てると、高速に取得できる。

// GoID returns the Goroutine ID.
//go:nosplit
func GoID() int64 {
    gp := getg()
    return gp.goid
}

Symbol information

シンボルに関する情報は、TEXT segmentにコンパクトな形式で格納されている。 アクセスするのはちょっとめんどくさい。

闇が深そうな実装だ。。。。

// NOTE: There are *three* independent implementations of this object
// file format in the Go source tree:
//
//  - cmd/internal/goobj/read.go (used by cmd/addr2line, cmd/nm, cmd/objdump, cmd/pprof)
//  - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile)
//  - cmd/link/internal/objfile.go (used by cmd/link)

go/doc.go at release-branch.go1.10 · golang/go

全ての関数をリストアップ

こんな感じ。 全てのモジュール(通常は1個しかない)に対してループし、モジュール内部にある全ての関数に対してループするだけ。 Func構造体のアドレスは、pclntableから取得できる。

for _, md:=range runtime.activeModules() {
    for idx, ft:=range md.ftab {
        f := (*Func)(unsafe.Pointer(mrand.pclntable[ft.funcoff])
        file, line := runtime.funcline1()
    }
}

pclntableスライス

runtime.moduledata構造体のフィールドの1つ。 いろいろなデータを詰め込んだbyteスライス。

pclntableの中に入っていることを確認したデータ一覧 (順不同)

runtime._func構造体

runtime._func構造体の定義

高速化に使えそうなやつ

詳細はコンパイラのドキュメントソースコード、runtimeのHACKING.mdを参照。

スタックトレースの読み方

Stack Traces In Go Go, (Golang) Programming - Blog - Ardan Labs

eBPF対応

構造体の比較防止

==演算子で構造体をできないようにするテクニック。 IncomparableStruct同士を比較しようとすると、コンパイルエラーを起こす。

type IncomparableStruct struct {
    SomeFields int

    // This artifact prevents this struct from being compared
    // with itself. It consumes no space as long as it's not the
    // last field in the struct.
    _            [0]struct{ _ []byte }
}