Slide 1

Slide 1 text

GoでC/C++パーサーを作った時の flatbuffersの知見 CA.go #3

Slide 2

Slide 2 text

Souzoh confidential and proprietary Who? 2

Slide 3

Slide 3 text

Souzoh confidential and proprietary 自己紹介 ● Koichi Shiraishi (@zchee) ● GitHub: zchee ● Twitter: _zchee_ ● Go シカカケナイ ○ Go歴: 2年 ○ エンジニア歴: 4ヶ月 ● Mercari / Souzoh ソリューションチーム所属 3

Slide 4

Slide 4 text

Souzoh confidential and proprietary プロジェクト / コントリビュート ● github.com/zchee/resume ○ zchee/docker-machine-driver-xhyve ○ zchee/nvim-go ○ nsf/gocode ○ moby/hyperkit ○ docker/machine ○ gperftools/gperftools (TC Malloc) ○ tmux/tmux ○ google/flatbuffers ○ etc... 4

Slide 5

Slide 5 text

Souzoh confidential and proprietary 宣伝 5

Slide 6

Slide 6 text

Souzoh confidential and proprietary 6 https://www.wantedly.com/projects/171425

Slide 7

Slide 7 text

Souzoh confidential and proprietary はい 7

Slide 8

Slide 8 text

Souzoh confidential and proprietary GoでC/C++パーサーを作った時の flatbuffersの知見 8

Slide 9

Slide 9 text

Souzoh confidential and proprietary What is “GoでC/C++パーサー” ? 9

Slide 10

Slide 10 text

Souzoh confidential and proprietary A C/C++ AST index server using libclang written in Go github.com/zchee/clang-server 10

Slide 11

Slide 11 text

Souzoh confidential and proprietary zchee/clang-server ● Fast indexing of C/C++ AST database onto the NoSQL, which serialized by flatbuffers ○ Now using the leveldb key-value storage ○ Without C bindings using the syndtr/goleveldb, which is natively implemented leveldb in Go ● Support cross-platform and multi-architecture AST indexing ○ macOS, BSD and Windows ○ arm, arm64 m68k, mips, sparc and x86_(16|32|64) ● Server/Client architecture over the gRPC or msgpack-rpc ● Built-in compile_commands.json generator using google/kati and ninja for Makefile ○ No need make for the generating compile_commands.json Concept 11

Slide 12

Slide 12 text

Souzoh confidential and proprietary zchee/clang-server ● zchee/clang-serverプロジェクトは頓挫しました orz ● LLVMがC++でLangage Server Protocol準拠なClangDの開 発が始まったため ● 今までのC/C++パーサ(YouCompleteMe・rtags)に勝つため に開発し始めたが、さすがにLLVMに勝とうとは思わない ● 今日は供養しに来ました 注意 12

Slide 13

Slide 13 text

Souzoh confidential and proprietary zchee/clang-server ● zchee/deoplete-go はNeovim+Goのための補完プラグイン ● Shougo/deoplete.nvim の上に実装されていて、基本Python3でしか書 けない ● zchee/deoplete-clang も実はある ○ LLVMが公開しているlibclang-pythonをPython3にポートしたものを 使っている ○ が、ctypes のオーバーヘッドが大きく、ろくにキャッシュしてないので 遅い ○ Goと同じServer/Clientアーキテクチャ形式にして、Python側もgRPC で通信すれば早くなるのでは!? なぜ作ろうとしたか 13

Slide 14

Slide 14 text

Souzoh confidential and proprietary ● gRPCサーバー形式(gocode的な) ● クライアントはgRPCでリクエストを投げれば、補完やコードジャンプ場所が返ってく る ● go-clangという、libclangのcgoバインディングを使った ● パースしたC/C++のASTはでかすぎてメモリに乗り切らない ○ 正確に言うと、一つのプロジェクトだけであれば乗り切るが、プロジェ クトを変える毎に再インデックスが走るのは旨くない ● NoSQLのLevelDBを使ってディスクキャッシュするようにした ● バイナリでDBにぶち込むために、シリアライズにflatbuffersを採用 zchee/clang-server 作った(作りかけた) 14

Slide 15

Slide 15 text

Souzoh confidential and proprietary What is “flatbuffers” ? 15

Slide 16

Slide 16 text

Souzoh confidential and proprietary ● Access to serialized data without parsing/unpacking ● Memory efficiency and speed ● Flexible ● Tiny code footprint ● Strongly typed ● Convenient to use ● Cross platform code with no dependencies ● >> gRPC Support << google/flatbuffers 特徴 (Why use FlatBuffers?) 16

Slide 17

Slide 17 text

Souzoh confidential and proprietary 要はProtocol Buffersより速いらしい 17

Slide 18

Slide 18 text

Souzoh confidential and proprietary flatbuffers schemaサンプル . . // CodeCompleteResults represents a list of vim complete-items dictionary. table CodeCompleteResults { Results: [CompleteItem]; } // ここでgRPCを定義している rpc_service Clang { Completion(Location):CodeCompleteResults (streaming: "..."); } namespace symbol; /// File represents a particular source file that part of a project. table File { Name: string (required, key); // -> []byte Flags: [string]; // -> [][]byte TranslationUnit: string; // -> []byte Symbols: [Info]; Headers: [Header]; Includes: [string]; // -> [][]byte Headers: [Header]; } table Header { FileID: string (id: 0, required, key); // -> []byte Mtime: long (id: 1); // time.Time.Unix(): int64 } 18 https://github.com/zchee/clang-server/blob/master/symbol/schema.fbs

Slide 19

Slide 19 text

Souzoh confidential and proprietary flatbuffers コード生成サンプル https://github.com/zchee/clang-server/blob/master/internal/symbol/Header.go * 手抜きではありません 19

Slide 20

Slide 20 text

Souzoh confidential and proprietary flatbuffers schemaサンプル . . . // ここでgRPCを定義している rpc_service Clang { Completion(Location):CodeCompleteResults (streaming: "..."); } 20 https://github.com/zchee/clang-server/blob/master/symbol/schema.fbs

Slide 21

Slide 21 text

Souzoh confidential and proprietary // Completion implements symbol.ClangServer Completion interface. func (s *server) Completion(ctx context.Context, loc *symbol.SymbolLocation) (*flatbuffers.Builder, error) { f := string(loc.FileName()) if s.filename != f { . . . file := symbol.GetRootAsFile(buf, 0) // デシリアライズ。`buf` はDBから取ってきた[]byte if cErr := s.idx.ParseTranslationUnit2(file.Name(), file.Flags(), nil, uint32(clang.TranslationUnit_KeepGoing), &s.tu); clang.ErrorCode(cErr) != clang.Error_Success { log.Fatal(cErr) } } codeCompleteResults := new(symbol.CodeCompleteResults) . flatbuffers Go コードサンプル 21

Slide 22

Slide 22 text

Souzoh confidential and proprietary flatbuffers Go コードサンプル . . codeCompleteResults := new(symbol.CodeCompleteResults) result := codeCompleteResults.Marshal(s.tu.CodeCompleteAt(f, loc.Line(), loc.Col(), nil, clang.DefaultCodeCompleteOptions())) return result, nil } 22

Slide 23

Slide 23 text

Souzoh confidential and proprietary flatbuffers Go コードサンプル // Serve serve clang-server server with flatbuffers gRPC custom codec. func (s *server) Serve() { l, err := net.Listen("tcp", port) if err != nil { log.Fatal(err) } grpcServer := grpc.NewServer(grpc.CustomCodec(flatbuffers.FlatbuffersCodec{})) symbol.RegisterClangServer(grpcServer, s) if err := grpcServer.Serve(l); err != nil { log.Fatal(err) } } . . 23 https://github.com/zchee/clang-server/blob/master/rpc/rpc.go

Slide 24

Slide 24 text

Souzoh confidential and proprietary gRPCに対応している デシリアライズが楽 なのは分かった。 24

Slide 25

Slide 25 text

Souzoh confidential and proprietary じゃあシリアライズは? 25

Slide 26

Slide 26 text

Souzoh confidential and proprietary flatbuffers schemaサンプル . . // CodeCompleteResults represents a list of vim complete-items dictionary. table CodeCompleteResults { Results: [CompleteItem]; } // ここでgRPCを定義している rpc_service Clang { Completion(Location):CodeCompleteResults (streaming: "..."); } namespace symbol; /// File represents a particular source file that part of a project. table File { Name: string (required, key); // -> []byte Flags: [string]; // -> [][]byte TranslationUnit: string; // -> []byte Symbols: [Info]; Headers: [Header]; Includes: [string]; // -> [][]byte Headers: [Header]; } table Header { FileID: string (id: 0, required, key); // -> []byte Mtime: long (id: 1); // time.Time.Unix(): int64 } 26 https://github.com/zchee/clang-server/blob/master/symbol/schema.fbs

Slide 27

Slide 27 text

Souzoh confidential and proprietary flatbuffers シリアライズサンプル https://github.com/zchee/clang-server/blob/master/symbol/type.go#L418 https://github.com/zchee/clang-server/blob/master/symbol/type.go#L227 * 手抜きではありません 27

Slide 28

Slide 28 text

Souzoh confidential and proprietary …は? 28

Slide 29

Slide 29 text

Souzoh confidential and proprietary flatbuffers ● dgraph-io/dgraphもflatbuffersからprotobufに移行した ○ メンテが難しすぎるとのこと ● gogo/protobufで匹敵するレベルの速度は出せるとのこと ○ 自分ではベンチは取っていません 結論 29

Slide 30

Slide 30 text

Souzoh confidential and proprietary flatbuffersは 人類には早かったのかもしれない 30

Slide 31

Slide 31 text

Souzoh confidential and proprietary 31 実際にバイナリ組み立てたり、 プロジェクトでメンテナンスコストを割け るのであれば 選択の余地はありそう

Slide 32

Slide 32 text

Souzoh confidential and proprietary 32 ご静聴ありがとうございました!