Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
ffi & native extension
Search
atomiyama
October 17, 2019
Programming
280
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
470
Rustでgemを作ろう
atomiyama
0
1.6k
技術選定で失敗したはなし
atomiyama
0
1.4k
はじめてのDocker
atomiyama
0
120
Other Decks in Programming
See All in Programming
初心者DevRelとして参加者だった私が、DevRel Talks!#2に登壇するまでにしてきたこと
sokohirai
0
340
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
160
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
130
AIとGame Jamで、ゲームを完成させた話
takahirosaeki
0
110
What We Talk About When We Talk About XP
m_seki
2
410
iOS開発×AI駆動開発 〜最近使って便利だったスキルの話〜
nogu66
0
140
不幸な GC
chencmd
0
890
業務時間外もAIに働いてもらう話
colorful12
3
10k
ALB ログから Trace を気合で繋げる技術
fohte
7
880
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
130
型解析で実現する Go の言語内 DSL / Conference に Go! タイムテーブルの歩き方 for Gophers
mazrean
0
130
フロントエンドUIフレームワークのこれまでとこれから
ssssota
1
830
Featured
See All Featured
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
490
[SF Ruby Conf 2025] Rails X
palkan
2
1.4k
WENDY [Excerpt]
tessaabrams
12
39k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
270
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
Optimising Largest Contentful Paint
csswizardry
37
3.9k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
A designer walks into a library…
pauljervisheath
211
25k
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