Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ffi & native extension
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
atomiyama
October 17, 2019
Programming
270
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ffi & native extension
heiseirb9
atomiyama
October 17, 2019
More Decks by atomiyama
See All by atomiyama
SchemaDrivenDevelopment
atomiyama
0
460
Rustでgemを作ろう
atomiyama
0
1.6k
技術選定で失敗したはなし
atomiyama
0
1.4k
はじめてのDocker
atomiyama
0
120
Other Decks in Programming
See All in Programming
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
160
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
AI時代のUIはどこへ行く?その2!
yusukebe
21
7.1k
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.1k
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
260
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
10
4.1k
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
3.9k
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
110
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
670
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4.2k
Composerを使ったサプライチェーン攻撃の様子を眺めてみる #phpstudy
o0h
PRO
2
250
Featured
See All Featured
Statistics for Hackers
jakevdp
799
230k
Being A Developer After 40
akosma
91
590k
A Tale of Four Properties
chriscoyier
163
24k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
590
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
780
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
160
The untapped power of vector embeddings
frankvandijk
2
1.8k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
310
How GitHub (no longer) Works
holman
316
150k
Docker and Python
trallard
47
3.9k
The Curious Case for Waylosing
cassininazir
1
390
Transcript
FFI & Native Extension 1
github.com/atomiyama/heiseirb9 2
whoami Akifumi Tomiyama Studyplus Inc, H3.12.16 server-side enginner github: @atomiyama
Twitter: @atomiyama1216 3
好きな⾔語はなんですか? 4
Rust & Ruby 5
RubyからRustを呼んでみたい 6
why 早いらしい 低レイヤの⾔語書いてみたかった => それを好きなRubyから呼べたら楽しそう 7
Rubyから他の⾔語を呼び出す⽅法 FFI (Foreign Function Interface) Native Extension 8
FFI (foreign function interface) ⾊々な⾔語で定義された関数とかをRubyから呼べるようにしてくれる. => Rustなりから作成した共有ライブラリの関数シンボルとシグネチャーをRubyスクリプトか ら渡すことでRustの関数を呼び出せるように橋渡しをしてくれる. ただ引数の型, 戻り値の型といった関数シグネチャーの情報は与えてあげる必要があるので使
いたい数が増えればRuby側もそれなりの記述量になるしRustで書いてRubyでも書くってちょ っと違う. 9
Native Extension (拡張ライブラリ) Rubyからは普通のライブラリと同じようにrequireするたけで呼び出せる. => ruby-ffiでやっていたような橋渡しのような役割も記述する必要があって rb_define_method などのAPIを使ってRubyを拡張してあげる必要がある.こちらのほうが 圧倒的に記述量は多いように感じるけどRuby側から関数シグネチャー渡したりしなくてよい のいい.
10
こんにちは世界! Rustで適当に関数を定義 // hello_world.rs #[no_mangle] pub extern fn hello_world() {
println!("Hello World, I am Rust!"); } コンパイルしてdylibファイル⽣成 $ rustc --crate-type="dylib" hello_world.rs # 関数シンボルが存在するか確認する $ nm libhello_world.dylib | grep hello_world 0000000000000f10 T _hello_world 0000000000090b60 S _rust_metadata_hello_world_8787f43e282added376259c1adb08b80 11
ffiでrubyから関数を呼び出す require 'ffi' module RustEx extend FFI::Library ffi_lib "libhello_world.dylib" attach_function
:hello_world, [], :void end pp RustEx::hello_world #=> "Hello World, I am Rust!" 12
ほんとに早くなってるのか 13
Rust Tutorialにあるやつ 14
10個のスレッドで500万までカウントするコード threads = [] 10.times do threads << Thread.new do
count = 0 5_000_000.times do count += 1 end count end end threads.each do |t| puts "Thread finished with count=#{t.value}" end puts "done!" 15
Rustで書く(ffi) #![crate_type="dylib"] use std::thread; #[no_mangle] pub extern fn process() {
let handles: Vec<_> = (0..10).map(|_| { thread::spawn(|| { let mut x = 0; for _ in 0..5_000_000 { x += 1 } x }) }).collect(); for h in handles { h.join().unwrap(); }; } 16
Rubyから呼ぶ require 'ffi' module FFIEx extend FFI::Library ffi_lib './liblib.dylib' attach_function
:process, [], :void end pp FFIEx.process 17
計測してみる require "./ffi/main" require "./purerb/main" require "benchmark/ips" Benchmark.ips do |x|
x.report "Ruby Func" do PureRuby.process end x.report "Rust Func" do FFIEx.process end x.compare! end 18
早い!!! $ ruby benchmark.rb Warming up -------------------------------------- Ruby Func 1.000
i/100ms Rust Func 1.000 i/100ms Calculating ------------------------------------- Ruby Func 0.526 (± 0.0%) i/s - 3.000 in 5.709806s Rust Func 1.232 (± 0.0%) i/s - 7.000 in 5.684935s Comparison: Rust Func: 1.2 i/s Ruby Func: 0.5 i/s - 2.34x slower 19
Native Extension #![allow(non_snake_case)] extern crate libc; use std::ffi::CString; use std::thread;
type VALUE = libc::c_ulong; extern { fn rb_define_module(name: *const libc::c_char) -> VALUE; fn rb_define_module_function(module: VALUE, name: *const libc::c_char, value: extern fn(), argc: libc::c_int) -> libc::c_void; } extern fn rb_process() { let handles: Vec<_> = (0..10).map(|_| { thread::spawn(move || { let mut x = 0; for _ in 0..5_000_000 { x += 1 } x }) }).collect(); for h in handles { h.join().unwrap(); }; } #[no_mangle] // Init_{filename} の関数がエントリポイントになる // e.g. hoge.bundle をruby でrequire したらInit_hoge がエントリポイントになる pub extern fn Init_rustex() { let module_name = CString::new("RustEx").unwrap(); let process = CString::new("process").unwrap(); unsafe { let rb_cRustEx = rb_define_module(module_name.as_ptr()); rb_define_module_function(rb_cRustEx, process.as_ptr(), rb_process, 0); } } 20
呼ぶ # ./target/debug/librustex.dylib が作成される $ cargo build # macOS ではDynamic
Linking とDynamic Loading が明確に区別されていてruby からrequire するときはDynamic Loading が必要なので.bundle に変更しています $ mv target/debug/librustex.dylib rustex.bundle require "./rustex.bundle" RustEx.process 21
終わり 22