क्या CRuby में FFI की गति बढ़ाने का कोई तरीका है?
- जब Ruby से native code कॉल करना हो, तो जहाँ तक संभव हो उतना Ruby code लिखना बेहतर है। वजह यह है कि YJIT Ruby code को optimize कर सकता है, लेकिन C code को optimize नहीं कर सकता।
- Native library को कॉल करते समय, बेहतर यह है कि ज़्यादातर काम Ruby में किया जाए और native function call के लिए एक सरल API देने वाला native extension लिखा जाए।
- FFI, native extension जितनी performance नहीं देता। उदाहरण के लिए, अगर
strlen C function को FFI से wrap किया जाए, तो C extension की तुलना में इसकी performance कम होती है।
बेंचमार्क परिणाम
String#bytesize को सीधे कॉल करना सबसे तेज़ है, और इसे baseline माना जा सकता है।
- C extension के ज़रिए
strlen कॉल करना दूसरा सबसे तेज़ है, और उसके बाद परोक्ष रूप से String#bytesize को कॉल करना आता है।
- FFI implementation सबसे धीमी है। यह दिखाता है कि FFI के ज़रिए native function call करने पर काफ़ी overhead आता है।
क्या यह हक़ीक़त बदली जा सकती है?
- Chris Seaton के एक विचार के आधार पर, external function कॉल करने के लिए JIT code generate करने की संभावना पर काम चल रहा है।
- FFI wrapper उदाहरण में,
attach_function कॉल होने पर wrapper function define किए जाने के समय ही ज़रूरी machine code generate किया जा सकता है।
RJIT का उपयोग
- RJIT, Ruby में लिखा गया एक JIT compiler है, जो Ruby के साथ bundled आता है।
- RJIT को gem के रूप में निकाला गया ताकि 3rd-party JIT compiler, Ruby data structures को आसानी से map कर सकें।
- JIT entry function pointer को हमेशा execute किया जाता है ताकि 3rd-party JIT machine code में register कर सके।
concept proof
- "FJIT" नाम के एक छोटे concept proof के ज़रिए, runtime पर machine code generate करके external function कॉल किया जा सकता है।
- बेंचमार्क परिणामों में, FJIT द्वारा generate किया गया machine code, C extension से भी तेज़ है और FFI call की तुलना में 2 गुना से अधिक तेज़ है।
निष्कर्ष
- यह दिखाता है कि C extension जैसी गति (या उससे भी तेज़ गति) बनाए रखते हुए, जहाँ तक संभव हो उतना Ruby code लिखना संभव हो सकता है।
- Ruby को FFI के बिना native code कॉल करने का फ़ायदा मिल सकता है।
सावधानियाँ
- फ़िलहाल यह केवल ARM64 platform तक सीमित है। इसमें x86_64 backend जोड़ना होगा।
- यह सभी parameter types और return types को handle नहीं करता। अभी केवल एक single parameter और return को handle किया जा सकता है।
- Ruby को
--rjit --rjit-disable flags के साथ चलाना होगा। Kokubun की सुविधा लागू होने पर यह समस्या हल हो जाएगी।
- अभी यह केवल Ruby head पर ही चल सकता है।
1 टिप्पणियां
Hacker News राय
Java Constraint Solver (Timefold) और CPython के बीच function calls के लिए FFI को काफी संभालना पड़ा
Rails At Scale और byroot के blog की बदौलत, अभी Ruby internals और performance पर गहराई से चल रही चर्चाओं में रुचि लेने का अच्छा समय है
external function calls के लिए 3rd party libraries को call करने के बजाय code को JIT compile किया जा सकता है या नहीं, इस पर सवाल
JVMCI का उपयोग करके arm64/amd64 code को मौके पर generate कर JNI के बिना native libraries को call करने वाली library संबंधी जानकारी: लिंक
"जितना संभव हो उतना Ruby लिखो, खासकर क्योंकि YJIT Ruby code को optimize कर सकता है लेकिन C code को नहीं" जैसी राय
10 साल से ज़्यादा समय से Ruby इस्तेमाल कर रहा हूँ, और हाल की प्रगति देखना बहुत दिलचस्प है
JIT compilation की ज़रूरत क्यों है, इस पर सवाल
FFI - Foreign Function Interface, यानी Ruby से C को call करने का तरीका
सवाल कि क्या यही काम libffi नहीं करता
लगता है अब समझ में आता है कि tenderlovemaking.com पर क्यों नहीं गया