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
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
460
Rustでgemを作ろう
atomiyama
0
1.6k
技術選定で失敗したはなし
atomiyama
0
1.4k
はじめてのDocker
atomiyama
0
120
Other Decks in Programming
See All in Programming
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.6k
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
290
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.7k
自作OSでスライド発表する
uyuki234
1
3.6k
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
830
アルゴリズムは何を圧縮しているのか ─ Haskell から育った「圧縮代数」というメンタルモデル
naoya
13
2.6k
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
250
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
830
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
190
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
160
Hatena Engineer Seminar #37「言語モデルの活用に関する研究」
slashnephy
0
490
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Visualization
eitanlees
152
17k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.3k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
Navigating Weather and Climate Data
rabernat
0
280
Building Applications with DynamoDB
mza
96
7.1k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
What's in a price? How to price your products and services
michaelherold
247
13k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
300
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.7k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.6k
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