Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ruby-ffiについてざっくり解説

707 views

Published on

Ruby FFIについての解説

Shinjuku.rb #50 PyCallを中心に機械学習やFFIなどを勉強しよう
https://shinjukurb.connpass.com/event/58526/
の発表資料です

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

ruby-ffiについてざっくり解説

  1. 1. ruby-f についてざっくり解説 ota42y 2017/06/24 Shinjuku.rb #50
  2. 2. 自己紹介 ota42y ヘルスケア系の会社勤務(人募集中) rubyとかgoとかC++とか Railsで複合PK、以外といけるのでは?
  3. 3. ruby-f https://github.com/f /f rubyでForeign function interfaceを扱うgem 他言語の関数とかをやりとりするインタフェース 内部的にはlibf を使ってる
  4. 4. How to use Create C library int calc(int a, int b){ return a* b; } gcc -c -fPIC foo.c -o foo.o gcc -shared -o libfoo.so foo.o
  5. 5. Call C library from Ruby require 'ffi' module FooLib extend FFI::Library ffi_lib "libfoo.so" attach_function :calc, [:int, :int], :int end puts FooLib.calc(6, 7) gem i ffi ruby ffi.rb # => 6*7 = 42
  6. 6. Go Go build c-shared library so it works. package main import "C" //export calc func calc(a, b int) int { return (a + b) * 42 } func main() {} go build -buildmode=c-shared -o libfoo.so foo.go # インタフェース変えてないのでそのままで動く ruby ffi # => ((6+7)*42) = 546
  7. 7. Why we need FFI? Cで高速化 既存資産の再利用 例 natto は mecab.so のためにFFI使ってる https://github.com/buruzaemon/natto # Lattice interface attach_function :mecab_lattice_destroy, [:pointer], :void attach_function :mecab_lattice_clear, [:pointer], :void attach_function :mecab_lattice_is_available, [:pointer], :int
  8. 8. Why we need FFI? Cで高速化 既存資産の再利用 例 spring-watcher-listen の依存関係にあるrb-inotify が inotify のために使ってるので、 Rails開発だと知らずのうちに使ってる https://github.com/guard/rb-inotify https://github.com/guard/rb- inotify/blob/master/lib/rb-inotify/native.rb#L9
  9. 9. f 良い C拡張書かなくて良いところとか
  10. 10. more detail
  11. 11. How ruby-f call libf 内部的にはlibf を利用し、 ruby-f はruby~cの橋渡しをしてる。
  12. 12. libf の使い方 #include <stdio.h> #include <ffi.h> #include <dlfcn.h> int main() { ffi_cif cif; ffi_type *args[2]; void *values[2]; ffi_arg rc; char *libname = "libfoo.so"; void* handle; void* address; int a = 6; int b = 7;
  13. 13. handle = dlopen(libname, 1); address = dlsym(handle, "calc"); args[0] = &ffi_type_sint32; args[1] = &ffi_type_sint32; values[0] = &a; values[1] = &b; ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint32, args) ffi_call(&cif, address, &rc, values); printf("result: %dn", (int)rc); return 0; } # 手元の環境によって違う。ちゃんとしてればlibffiの指定は不要 gcc -I /usr/local/opt/libffi/lib/libffi-3.0.13/include/ useffi.c ./a.out
  14. 14. libfoo.soの関数の実行手順 dlopen でlibfoo.soを開く dlsym で関数のポインタ取得(const_getみたいなの) ffi_prep_cif で実行に必要な情報(cif)をセット ffi_call にcifと関数ポインタを渡すと 良い感じに呼び出してくれる rubyにC拡張があるので、この手順を再現してるだけ (FFIでC拡張を書かなくてすむが、FFI自体はC拡張を 使わなければいけないジレンマ…)
  15. 15. rubyのf require 'ffi' module FooLib extend FFI::Library ffi_lib "libfoo.so" attach_function :calc, [:int, :int], :int end puts FooLib.calc(6, 7) 関係するのは以下の三つ f _libメソッド attach_functionメソッド 実際の関数呼びだし(FooLib.calc)
  16. 16. f _libメソッド dlopen関数でlibfoo.soを開く 読んだ.soファイルは変数に保存 https://github.com/f /f /blob/ed67c2852e8854e bdfa2482d4fb4c2edf3da21a0/lib/f /library.rb#L9 6 https://github.com/f /f /blob/f19254bb9ad24f9a 668acd04b9cfab5e3797a05b/ext/f _c/DynamicLi brary.c#L114
  17. 17. attach_function dlsym関数で呼び出す関数のポインタを取得 https://github.com/f /f /blob/ed67c2852e885 4ebdfa2482d4fb4c2edf3da21a0/lib/f /library.r b#L236 nd_function≒library_dlsym →dlsym https://github.com/f /f /blob/f19254bb9ad24f 9a668acd04b9cfab5e3797a05b/ext/f _c/Dyna micLibrary.c#L153
  18. 18. attach_function 取得したポインタや引数の情報を FFI::Functionオブジェクトにして保存 この過程でcifも設定している https://github.com/f /f /blob/c52ceb17328807 3a321a94b401243ff40110d910/ext/f _c/Funct ionInfo.c#L192 FFI::Function.callを呼び出すメソッドをeval https://github.com/f /f /blob/d942f7c10bf283 bf313c2df3775c71996925b145/lib/f /variadic .rb#L62
  19. 19. 関数呼びだし 対応するFFI::Functionのcallメソッドで、 保存された関数の情報を元にlibf を使っている。 呼び出しに必要なcifと関数ポインタは FFI::Functionの初期化時に用意してある なので呼び出すだけ (一応スレッド対応とかの事前準備もやってる) https://github.com/f /f /blob/c52ceb17328807 3a321a94b401243ff40110d910/ext/f _c/Call.c #L430
  20. 20. まとめ ruby-f のやってること f _libメソッド(.soファイルを開く) attach_functionメソッド(関数の呼び出し準備) 関数呼びだし attach_function時に用意した情報と引数とを 組み合わせてf _call呼ぶ やってることは簡単∩(・ω・)∩ (実際はruby→cの受け渡しで色々な処理がある)

×