関連記事
Goメモ-502 (cgoメモ-01)(cgoヘッダ) - いろいろ備忘録日記
Goメモ-506 (cgoメモ-02)(cgoヘッダ) - いろいろ備忘録日記
Goメモ-507 (cgoメモ-03)(C.int) - いろいろ備忘録日記
Goメモ-508 (cgoメモ-04)(C言語の構造体) - いろいろ備忘録日記
Goメモ-509 (cgoメモ-05)(C.CString)(Cの文字列) - いろいろ備忘録日記
Goメモ-510 (cgoメモ-06)(C.GoString)(Cの文字列をGoの文字列へ) - いろいろ備忘録日記
Goメモ-511 (cgoメモ-07)(C.CBytes)([]byteをCのバイト列に) - いろいろ備忘録日記
Goメモ-512 (cgoメモ-08)(C.GoBytes)(Cのバイト列をGoの[]byteへ) - いろいろ備忘録日記
Goメモ-514 (cgoメモ-09)(C.GoStringN)(C.GoStringのサイズ指定版) - いろいろ備忘録日記
Goメモ-515 (cgoメモ-10)([]byteを(void *)へ変換) - いろいろ備忘録日記
Goメモ-516 (cgoメモ-11)([]byteを(char *)へ変換) - いろいろ備忘録日記
Goメモ-518 (cgoメモ-12)(Cのmallocをcgo経由で呼び出し) - いろいろ備忘録日記
Goメモ-519 (cgoメモ-13)(ポインタ演算) - いろいろ備忘録日記
Goメモ-520 (cgoメモ-14)(Goの関数をCの世界に公開 (export)) - いろいろ備忘録日記
Goメモ-522 (cgoメモ-15)(Goでsoファイルを作成してC言語から呼び出し) - いろいろ備忘録日記
Goメモ-525 (cgoメモ-16)(C側にて関数ポインタを引数に要求する関数にGo側で定義した関数を設定) - いろいろ備忘録日記
Goメモ-526 (cgoメモ-17)(cgoとdlopen関数を使って既存ライブラリの呼び出しをフックする) - いろいろ備忘録日記
Goメモ-527 (cgoメモ-18)(cgoを利用している場合のinit関数について) - いろいろ備忘録日記
Goメモ-528 (cgoメモ-19)(cgoを利用して作成したsoファイル経由でのinit関数の呼び出し) - いろいろ備忘録日記
Goメモ-529 (cgoメモ-20)(C言語のNULLをcgoから渡す) - いろいろ備忘録日記
Goメモ-530 (cgoメモ-21)(CGOヘッダーで指定出来るCFLAGS, LDFLAGS) - いろいろ備忘録日記
Goメモ-531 (cgoメモ-22)(CGOで利用するコンパイラを変更する) - いろいろ備忘録日記
Goメモ-532 (cgoメモ-23)(CGOヘッダで使えるSRCDIR変数) - いろいろ備忘録日記
Goメモ-534 (cgoメモ-24)(C側の構造体にて固定要素数の文字配列をGo側で文字列に変換) - いろいろ備忘録日記
Goメモ-535 (cgoメモ-25)(cgo.Handleを用いてCとGoの間で値をやり取りする) - いろいろ備忘録日記
Goメモ-536 (cgoメモ-26)(C側の構造体をGo側で利用する) - いろいろ備忘録日記
Goメモ-537 (cgoメモ-27)(Go側でCの構造体のサイズを知る方法) - いろいろ備忘録日記
Goメモ-539 (cgoメモ-28)(Go側でCの文字列リスト(**char)を扱う) - いろいろ備忘録日記
Goメモ-623 (cgoメモ-29)(memcpyの呼び出し) - いろいろ備忘録日記
Goメモ-627 (cgoメモ-30)(Goでビルドした静的ライブラリのC言語からの利用) - いろいろ備忘録日記
Goメモ-628 (cgoメモ-31)(Cの関数からGoの関数をコールバックする) - いろいろ備忘録日記
Goメモ-629 (cgoメモ-32)(Cの関数からGoの関数をコールバックする(2)) - いろいろ備忘録日記
Goメモ-630 (cgoメモ-33)(LD_PRELOAD を利用したモック) - いろいろ備忘録日記
Goメモ-641 (cgoメモ-34)(C側で定義された配列の操作)(アクセサ関数を用意) - いろいろ備忘録日記
Goメモ-644 (cgoメモ-35)(マクロ定数は参照できるけどマクロは使えない) - いろいろ備忘録日記
Goメモ-654 (cgoメモ-36)(structs.HostLayout) - いろいろ備忘録日記
Goメモ-660 (cgoメモ-37)(go-md4c, MD4Cのラッパーライブラリ) - いろいろ備忘録日記
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
これまでのサンプルは以下のリポジトリにアップしています。
今回は、cgo向けの情報を取得できるランタイムメトリクスの/cgo/go-to-c-calls:callsについて。
このメトリクス値は、cgo経由でC側に呼び出しを行った回数を返してくれます。
大量に呼び出ししてるんじゃね?って部分があったりしたときの調査に使えたりします。
使い方は、普通の runtime/metrics のやり方と同じです。
サンプル
main.go
package main /* #include <stdio.h> void hello(void) { printf("[C] Hello World\n"); } int add(int x, int y) { return x + y; } */ import "C" import ( "fmt" "runtime/metrics" "sync" ) type ( _Metrics struct { samples []metrics.Sample } ) func NewMetrics() *_Metrics { m := _Metrics{samples: []metrics.Sample{{Name: "/cgo/go-to-c-calls:calls"}}} return &m } func (me *_Metrics) Print(label string) { // 現在のメトリクスを読み込み metrics.Read(me.samples) fmt.Printf("\n=== %s ===\n", label) for _, sample := range me.samples { // // 一つしか指定していないが、一応チェック // if sample.Value.Kind() == metrics.KindUint64 { fmt.Printf("%s: %d\n", sample.Name, sample.Value.Uint64()) } else { fmt.Printf("%s: (利用不可)\n", sample.Name) } } } func main() { const ( CallCount1 = 5 CallCount2 = 10 ) var ( m = NewMetrics() c = make(chan C.int) drain = func() { for v := range c { fmt.Printf("[Go] z = %d\n", int(v)) } fmt.Printf("[Go] DONE\n") } wg sync.WaitGroup ) wg.Go(drain) // // 以下の最初のメトリクス取得時の結果は 0 ではなく 1 となる。 // // これは恐らくGoのランタイムが import "C" としたタイミングでC言語側との相互運用するための // セットアップのようなものが行われていると推測。(_cgo_initとか) // // つまり、/cgo/go-to-c-calls:calls というメトリクスは、ユーザーが明示的に書いた C.xxx() 呼び出しだけでなくて // Goランタイム内部が行うC呼び出しも含めた「GoからCへの遷移の総数」をカウントしているものということになる。 // m.Print("01.Init") { // C側のhello関数をN回呼び出し for range CallCount1 { C.hello() } } m.Print("02.After C.hello()") { // C側のadd関数をN回呼び出し for i := range CallCount2 { var ( x = C.int(i) y = C.int(i + 1) z C.int ) z = C.add(x, y) c <- z } } m.Print("03.After C.add()") close(c) wg.Wait() }
実行
$ task task: [default] go run main.go === 01.Init === /cgo/go-to-c-calls:calls: 1 [C] Hello World [C] Hello World [C] Hello World [C] Hello World [C] Hello World === 02.After C.hello() === /cgo/go-to-c-calls:calls: 6 [Go] z = 1 [Go] z = 3 [Go] z = 5 [Go] z = 7 [Go] z = 9 [Go] z = 11 [Go] z = 13 [Go] z = 15 [Go] z = 17 [Go] z = 19 === 03.After C.add() === /cgo/go-to-c-calls:calls: 16 [Go] DONE
最初の値が 0 じゃなく 1 となることに注意ですね。
参考情報
- C? Go? Cgo!
- Go Wiki: cgo
- cmd/cgo
- runtime/cgo
- cgoを使ったCとGoのリンクの裏側 (1)
- cgoを使ったCとGoのリンクの裏側 (2)
- ebitengine/purego
- JupiterRider/ffi
個人的Goのおすすめ書籍
個人的に読んでとても勉強になった書籍さんたちです。
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。