2 पॉइंट द्वारा GN⁺ 2025-02-14 | 1 टिप्पणियां | WhatsApp पर शेयर करें

क्या 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 टिप्पणियां

 
GN⁺ 2025-02-14
Hacker News राय
  • Java Constraint Solver (Timefold) और CPython के बीच function calls के लिए FFI को काफी संभालना पड़ा

    • FFI की performance समस्याएँ मुख्य रूप से host language और foreign language के बीच communication के लिए proxy इस्तेमाल करने से पैदा होती हैं
    • JNI या नए foreign interface का उपयोग करने वाले direct FFI calls तेज़ होते हैं, और Java methods को सीधे call करने जैसी speed देते हैं
    • लेकिन CPython और Java के garbage collectors एक-दूसरे के साथ अच्छी तरह मेल नहीं खाते, इसलिए synchronization के लिए विशेष तकनीकों की ज़रूरत होती है
    • JPype या GraalPy जैसे proxy इस्तेमाल करने पर performance overhead आता है, क्योंकि parameters और return values को convert करना पड़ता है और अतिरिक्त FFI calls हो सकते हैं
    • जब CPython objects को Java में pass किया जाता है, तो Java के पास उन CPython objects के लिए एक proxy होता है
    • उस proxy को फिर से CPython में pass करने पर proxy का proxy बन जाता है
    • नतीजतन, JPype proxy सीधे FFI के जरिए CPython को call करने की तुलना में 1402% धीमे हैं, और GraalPy proxy 453% धीमे हैं
    • अंत में CPython bytecode को Java bytecode में convert किया गया, और इस्तेमाल की गई CPython classes के अनुरूप Java data structures बनाए गए
    • इसके परिणामस्वरूप proxy इस्तेमाल करने की तुलना में 100 गुना तेज़ performance improvement मिला
    • CPython bytecode को convert करना या पढ़ना बहुत अस्थिर है और documentation कम है, और VM की कई विशेषताओं के कारण इसे दूसरे bytecode में सीधे map करना मुश्किल है
    • अधिक जानकारी के लिए blog post देखें: लिंक
  • Rails At Scale और byroot के blog की बदौलत, अभी Ruby internals और performance पर गहराई से चल रही चर्चाओं में रुचि लेने का अच्छा समय है

    • Ruby और Rails में हाल के improvements की वजह से Rubyist होने का यह अच्छा समय है
  • external function calls के लिए 3rd party libraries को call करने के बजाय code को JIT compile किया जा सकता है या नहीं, इस पर सवाल

    • यक़ीन है कि यही LuaJIT FFI का मूल सिद्धांत है: लिंक
    • लगता है कि LuaJIT का FFI बहुत तेज़ होने का यही कारण है
  • JVMCI का उपयोग करके arm64/amd64 code को मौके पर generate कर JNI के बिना native libraries को call करने वाली library संबंधी जानकारी: लिंक

  • "जितना संभव हो उतना Ruby लिखो, खासकर क्योंकि YJIT Ruby code को optimize कर सकता है लेकिन C code को नहीं" जैसी राय

    • यह सवाल कि क्या Ruby काफ़ी धीमी भाषा नहीं है
    • अगर native में जाना है, तो जितना संभव हो उतना काम native में ही करना चाहेंगे
  • 10 साल से ज़्यादा समय से Ruby इस्तेमाल कर रहा हूँ, और हाल की प्रगति देखना बहुत दिलचस्प है

    • उत्साहित हूँ
  • JIT compilation की ज़रूरत क्यों है, इस पर सवाल

    • अगर C में लिखा जा सकता है, तो क्या load time पर compile नहीं किया जा सकता?
  • FFI - Foreign Function Interface, यानी Ruby से C को call करने का तरीका

  • सवाल कि क्या यही काम libffi नहीं करता

  • लगता है अब समझ में आता है कि tenderlovemaking.com पर क्यों नहीं गया