2 पॉइंट द्वारा GN⁺ 2023-07-13 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Vale का region borrowing prototype पहली बार सफलतापूर्वक compile हुआ है, जिससे generational references और regions को मिलाकर memory-safe approach को वास्तविक प्रोग्राम में सत्यापित करना संभव हुआ है
  • डेवलपर C/C++ के काफ़ी करीब तरीके से code लिख सकते हैं, और केवल ज़रूरी जगहों पर pure और region borrowing लागू करके generation check overhead कम कर सकते हैं
  • पहला zero-check Vale program roguelike level generation के लिए Cellular Automata उदाहरण था, और उसका resulting assembly unsafe_with_bounds mode के लगभग समान स्तर तक पहुँच गया
  • benchmark में safe_fastest ने unsafe_with_bounds की तुलना में कोई observable slowdown नहीं दिखाया, जबकि unsafe_no_bounds दोनों modes से 1.18 ± 0.01 गुना तेज़ था
  • यह अभी C/Rust के साथ सीधी तुलना नहीं है, और LLVM optimization noise, prototype की परिपक्वता, तथा inline data के अभाव के कारण Vale-विशिष्ट pre-optimizer और region features की और सफ़ाई बाकी है

Generational references और region borrowing का संयोजन

  • Vale का memory-safe approach reference counting, tracing garbage collection, और borrow checking का उपयोग न करने की दिशा में है
  • इसकी बुनियादी संरचना में डेवलपर C या C++ के क़रीब तरीके से program लिखते हैं, और Vale के generational references memory safety बनाए रखते हैं
  • इसके बाद pure और region borrowing लागू करने पर generation check overhead का अधिकांश हिस्सा हटाया जा सकता है
  • linear style तक जोड़ने पर Vale code में generation checks को zero तक लाने की संभावना बताई गई है
  • region borrowing पूरी तरह opt-in है, इसलिए पहले आराम से लिखना और बाद में केवल optimization की ज़रूरत वाले हिस्सों में इसे जोड़ना संभव है
  • लक्ष्य ऐसी संरचना का है जहाँ एक ही program में कुछ हिस्से Java की तरह लचीले, कुछ Rust की तरह तेज़, या इनके बीच किसी भी बिंदु पर चुने जा सकें

Prototype बनाने के लिए क्या-क्या करना पड़ा

  • पिछले कुछ वर्षों में compiler की बुनियाद बनाते हुए region-based borrowing system और generational references को साथ support करने का काम किया गया
  • borrowing system ख़ुद जटिल था, और पहले के templates से अधिक शक्तिशाली full generics की ज़रूरत पड़ी
  • regions और generational references को स्वाभाविक रूप से साथ काम कराने के लिए compiler में नए चरण की भी आवश्यकता हुई
    • अंदरूनी रूप से regions को “pure height” integer में घटाया जाता है
    • region generic parameter को negative, base region को 0, और हर pure block को बढ़ते positive मान के रूप में व्यक्त किया जाता है
  • कुछ महीने पहले region prototype पूरा हुआ, और अभी काफ़ी rough edges होने के बावजूद पहली बार कुछ सफलतापूर्वक compile किया गया
  • इसका परिणाम पहला zero-check Vale program बना
    • --print_mem_overhead true compiler flag से program में generation checks की संख्या गिनी जा सकती है

पहला zero-check program और assembly तुलना

  • पहला program roguelike game level generate करने वाला Cellular Automata उदाहरण था
  • compiler code की छोटी-सी गलती भी resulting assembly में अतिरिक्त instructions जोड़कर अंतिम program में कृत्रिम overhead ला सकती है
  • समस्या का पता लगाने के लिए resulting assembly की तुलना लगातार Vale के unsafe modes से की गई
    • unsafe_no_bounds: C की तरह सभी memory safety protections बंद, और generational references की जगह raw pointers का उपयोग
    • unsafe_with_bounds: Rust की तरह array access पर bounds checking जोड़ी गई
  • कई महीनों तक अंतर ट्रैक करने के बाद resulting assembly unsafe_with_bounds mode के लगभग समान हो गई
  • एकमात्र अपेक्षित अंतर यह था कि हर allocation के शीर्ष पर pseudo-random generation number डाला जाता था, जिसे वास्तविक generation checks में पढ़ा नहीं जाता था
    • अंदरूनी रूप से इसे तेज़ रखने के लिए monotonically increasing register का उपयोग किया जाता है
    • isolates या unique references जुड़ने पर यह अंतर भी हटाया जा सकता है

Benchmark परिणाम और मापन की शर्तें

  • benchmark का सारांश इस प्रकार है
Summary
  './build_unsafe_no_bounds/main' ran
    1.18 ± 0.01 times faster than './build_unsafe_with_bounds/main'
    1.18 ± 0.01 times faster than './build_safe_fastest/main'
  • Vale के normal mode safe_fastest ने केवल bounds checking वाले mode की तुलना में slowdown नहीं दिखाया
  • इस measurement में इस approach ने कोई observable overhead नहीं दिखाया
  • इसे ख़ुद चलाने के लिए regions branch build किया जा सकता है, benchmarking scripts देखी जा सकती हैं, और discord server पर सवाल पूछे जा सकते हैं
  • measurement conditions की कुछ स्पष्ट सीमाएँ हैं
    • यह C या Rust जैसी भाषाओं के साथ सीधा benchmark नहीं है
    • उन compilers में कई वर्षों के अलग optimization मौजूद हैं, जो प्रयोग के variables को धुंधला कर सकते हैं
    • memory-safe approach के अंतर को अलग करने के लिए unsafe_no_bounds, unsafe_with_bounds से तुलना की गई
    • test environment Ubuntu 22.04 चलाने वाला Razer Blade 15" 2018, 512GB SSD था
    • measurement tool hyperfine था और इसे cset shield के भीतर चलाया गया

बड़े programs में दिखने वाला optimization noise

  • बड़े programs में optimizer noise काफ़ी देखा गया
    • यह benchmark noise से अलग है; measurement setup ने ± 0.01 जैसी बहुत consistent run times दिखाईं
    • किसी एक हिस्से में छोटा बदलाव measurement को एक दिशा में हिला सकता था
  • generation number के आकार बदलने पर लगातार 1.13 ± 0.01 का negative overhead मिलने का मामला भी सामने आया
    • program में generation numbers अधिक नहीं थे, इसलिए यह परिणाम अजीब था
    • संभव है कि register allocation में बदलाव, semantic अंतर से आने वाले performance अंतर पर भारी पड़ गया हो
  • एक बड़े program, यानी छोटे roguelike game, में optimizer if statement के भीतर समान दो branches को merge नहीं कर पाया, और अन्य स्पष्ट optimizations भी छूट गईं
  • unread integer की मौजूदगी का क्या प्रभाव पड़ता है यह स्पष्ट नहीं है, और LLVM bug की संभावना भी है
  • यह परिणाम संकेत देता है कि Rust के MIR जैसा Vale-विशिष्ट pre-optimizer आवश्यक हो सकता है
    • LLVM को अधिक C-केंद्रित सोच के साथ डिज़ाइन किया गया था
    • यदि LLVM generational references को जानबूझकर freed memory access करने वाले pattern के रूप में समझे, तो उसे undefined behavior मान सकता है

लागू होने की संभावना और अगला काम

  • generational references और regions का संयोजन बहुत तेज़ memory-safe approach दे सकता है
  • यह approach उन software domains में अच्छी तरह फिट हो सकती है जहाँ ये शर्तें हों
    • tracing garbage collection की तुलना में अधिक predictable latency चाहिए
    • reference counting की तुलना में बेहतर performance और cache friendliness चाहिए
    • borrow checking की तुलना में आसान prototyping और iteration चाहिए
  • Vale की C या C++ से सीधे टक्कर वाली तुलना से पहले अभी कुछ काम बाकी है
    • LLVM optimizer को generation और immutability infer करने में समस्या है, इसलिए Vale-विशिष्ट pre-optimizer की आवश्यकता है
    • Vale को वर्तमान अस्थायी उपाय, जिसमें सभी structs heap पर रखे जाते हैं, की जगह inline data support करना होगा
    • ऊपर वाले benchmark में structs का उपयोग नहीं हुआ, इसलिए inline data की अनुपस्थिति ने उस परिणाम को प्रभावित नहीं किया
    • region feature अभी prototype चरण में है, इसलिए rough edges को ठीक करके और technical debt घटाकर इसे main branch में merge करना होगा
  • merge के बाद योजना यह है कि standard library को regions का उपयोग करने लायक बनाया जाए, ताकि उपयोगकर्ताओं के main program code में regions सीधे न भी हों तो भी लाभ मिल सके
  • मौजूदा measurement यह दिखाती है कि zero-check program संभव है और अपेक्षित speed तक पहुँच सकता है

1 टिप्पणियां

 
GN⁺ 2023-07-13
Hacker News की राय
  • मैंने Vale डाउनलोड करके आज़माया, लेकिन जब पहली बार valec compiler चलाया और कोई argument नहीं दिया, तो सीधे "(panic)" प्रिंट हुआ — यह अच्छा impression नहीं देता
    panic बहुत तीखा शब्द है, और मुझे लगता है कि सामान्य error handling वाली स्थितियों में इससे बचना चाहिए। किसी program का panic करना ऐसा लगता है जैसे हालत नियंत्रण से बाहर हो गई हो, इसलिए बाद में अच्छा एहसास नहीं रहता
    फिर मैंने command-line arguments की help देखने की कोशिश की, लेकिन फिलहाल वह लगभग मौजूद नहीं थी। वेबसाइट का Hello World example hello.vl में सेव करके valec hello.vl चलाया तो Unknown subcommand आया
    इसलिए valec build hello.vl चलाया, तो Unrecognized input: hello.vl के बाद फिर (panic) आया, और valec help भी मददगार नहीं था, इसलिए आखिरकार मैंने छोड़ दिया। समझ नहीं आ रहा कि इसे इस्तेमाल कैसे करना है

    • माफ़ करना। लगता है अब help file ठीक से आउटपुट नहीं हो रही। डाउनलोड में शामिल valec-help-build.txt को सीधे cat करके देखोगे तो जो जानकारी चाहिए वह समझाई गई मिलेगी
      compiler अभी काफी rough edges वाली स्थिति में है। अगस्त से मई तक हमने region prototyping पर 100% ध्यान दिया, और अभी जो तुम देख रहे हो वह उसी दौरान जमा हुआ technical debt है। इसमें help system के integration tests न होना भी शामिल है
      पिछले 1–2 महीनों से हम यह debt चुका रहे हैं, लेकिन अभी 0.2 release वाले स्तर तक वापस नहीं पहुँचे हैं। अगर और मदद चाहिए तो बताना, या Discord server पर आना — वहाँ मदद करने वाले कई लोग हैं
    • मुझे लगता है Vale अभी मूल रूप से research and development stage में ही है। उम्मीद बस इतनी करनी चाहिए कि किसी खास branch का कोई खास commit काम करेगा; यह वह stage नहीं लगता जहाँ कोई भी compiler डाउनलोड करके कुछ बना सके
      हालांकि README इस बात को साफ़ नहीं दिखाता और उसमें “Try Vale” लिखा है, इसलिए बात थोड़ी ambiguous है। फिर भी फिलहाल यह research and development / proof of concept के ज्यादा करीब लगता है
    • यह bug से ज्यादा user interface issue जैसा है। अगर चीज़ experimental है, तो असली bugs के लिए भी कुछ हद तक गुंजाइश दी जा सकती है
      user interface या bugs के लिहाज से भी देखें, तो 40 साल पुराने C++ को 35 साल पुराने gdb से debug करने का अनुभव किसी भी experimental language से अच्छी टक्कर ले सकता है। उदाहरण के लिए funcname()::staticvarname output अजीब interface है और लगभग आधी बार fail हो जाता है। C++ build systems की तो बात ही अलग है
      experimental technology हो तो concept की आलोचना की जा सकती है, लेकिन rough user interface को कुछ हद तक स्वीकार किया जा सकता है
    • GitHub README में compiler इस्तेमाल करने का तरीका दिया है
      https://github.com/ValeLang/Vale#building-a-vale-program
    • अगर software अभी alpha stage में है, तो यह लगभग expected ही है
  • tracing garbage collection की तुलना में latency ज्यादा predictable हो, reference counting की तुलना में performance और cache-friendliness बेहतर हो, और borrow checking की तुलना में prototyping व iteration आसान हों — यह सुनकर सिर्फ curiosity नहीं, सच में interest पैदा हो गया
    RSS feed भी subscribe करना शुरू कर दिया: https://verdagon.dev/rss.xml

    • आखिरकार AOT compiled languages में ऐसा नया idea आया है जिसका निष्कर्ष “बस कभी-कभी memory bug होने दो” नहीं है
  • Vale को और sponsors की ज़रूरत है
    https://github.com/sponsors/ValeLang
    जब तक यह post front page पर है, उम्मीद है कि project को $3,000 per month वाले goal तक पहुँचाने में मदद मिलेगी
    मैं चाहता हूँ कि Evan यह काम full-time कर सके। मैं खुद भी sponsor हूँ। तेज़, सुरक्षित और फिर भी prototyping में मज़ेदार language support करने लायक है

    • जिज्ञासा है कि GitHub sponsorship और Patreon sponsorship में revenue split कैसे अलग है
  • “Vale-specific pre-optimizer, Rust के Cranelift जैसा कुछ” शायद MIR, यानी mid-level intermediate representation, की बात कर रहा है। इस पर एक अच्छा blog post है: https://blog.rust-lang.org/2016/04/19/MIR.html
    Cranelift मुख्य रूप से JIT पर focused compiler backend है, लेकिन theory में यह LLVM की जगह भी ले सकता है। alternative backend पर काम भी चल रहा है, लेकिन कुछ constraints हैं: https://github.com/bjorn3/rustc_codegen_cranelift

    • लगता है सही है। Cranelift को मैं WebAssembly के लिए Rust optimizer मानता हूँ
  • ऐसा approach जिसमें ज्यादातर code में memory management की चिंता न करनी पड़े, और सिर्फ hot code paths को zero-cost abstractions से optimize करने का option मिले, दोनों तरफ़ की खूबियाँ देता लगता है
    खासकर तब, जब convenience के लिए safety नहीं बल्कि सिर्फ performance का trade-off करना पड़े

    • मैं सिर्फ C++ इस्तेमाल करता हूँ, लेकिन memory management की बिल्कुल चिंता नहीं करता
      shared ownership बुरा concept है, इसलिए smart pointers भी इस्तेमाल नहीं करता
      memory management की समस्याएँ कुल मिलाकर मामूली ही लगती हैं
  • generational references के संदर्भ में सुरक्षित कहने का मतलब क्या है, यह बात मुझे अब भी समझनी है
    अगर मैंने सही समझा है, तो इसका मतलब use-after-free और double-free को रोकना है? अगर ऐसा है, तो जब अपेक्षित generation और वास्तविक generation मेल नहीं खाते, तब memory access पर program फिर भी fail हो सकता है
    इस लिहाज से यह reference counting, tracing garbage collection और borrow checking से कम सुरक्षित लगता है

    • double-free को Vale का single ownership रोकता है, यानी C++ वाले अर्थ में single ownership, और generational references use-after-free को सुरक्षित तरीके से detect करने देती हैं
      अगर reference के ज़रिए freed memory access करने की कोशिश की जाए, तो predictable और सुरक्षित तरीके से segmentation fault या assertion failure आना चाहिए। आगे virtual address space को remap करने वाला सुधार आ जाए तो segmentation fault भी हट सकता है, इसलिए इसे लेकर उम्मीद है
    • यह उसी अर्थ में सुरक्षित है कि dangling pointer को arbitrary memory पढ़ने या लिखने देने के बजाय segmentation fault आता है
      हालांकि अगर generation index हो, तो actual access की कोशिश करने से पहले runtime में यह check करना भी संभव होना चाहिए कि access valid है या नहीं। Vale में यह संभव है या नहीं, पता नहीं
    • यह GC, borrow checking और reference counting से कम सुरक्षित है। फिर भी malloc/free से ज़्यादा सुरक्षित है, और इसके दूसरे फायदे भी हैं
    • मुझे भी जिज्ञासा है। समझ नहीं आ रहा कि यह use-after-free और double-free को कैसे रोकता है
      check function को allocation का generation number चाहिए, इसलिए वह allocation को access करता है। यानी reference उस allocation को access कर सकता है या नहीं, यह verify करने के लिए पहले उसी allocation को access करना पड़ता है
      बेशक अगर allocation पहले ही free हो चुका है, तो उस allocation और generation number को access करना ही undefined behavior है, इसलिए यह काम नहीं करेगा
      यह इतना obvious लग रहा है कि समझ नहीं आ रहा मैं कोई बड़ी बात miss कर रहा हूं, या यहां “memory safety” का मतलब बिल्कुल अलग है
    • अगर पूछा जाए कि क्या यह आपकी अपनी सीमित परिभाषा वाली “safety” से कम सुरक्षित है, तो शायद हां, हो सकता है
  • Vale, V जैसी language नहीं है। V को https://mawfig.github.io/2022/06/18/v-lang-in-2022.html पर बहुत critical review मिला था, और नाम मिलते-जुलते होने की वजह से मैंने उसे गलती से Vale समझ रखा था
    अगर किसी और ने भी यही गलती की हो, इसलिए लिख रहा हूं

    • वह “बहुत critical review” बस छोटे bugs की list है जिन्हें 1 साल पहले ठीक कर दिया गया था
      लेख की बातें अब relevant नहीं हैं, फिर भी वह पड़ा हुआ है, और वह उस blog का इकलौता लेख भी है
    • वह “critical review” मुझे पुराने spam जैसा ज़्यादा लगता है जिसे विरोधी या trolls बार-बार इस्तेमाल करते हैं। language के alpha version का “review”, असल में एक attack piece, जिसकी इसके अलावा कोई खास value नहीं लगती
      अब 2023 है और V भी beta (0.4) में है। ऊपर से वह लेख बनाने वाले व्यक्ति ने one-off GitHub account इस्तेमाल करके review/attack पोस्ट किया, विवाद बनाया और फिर गायब हो गया
      उस blog पर डाला गया इकलौता लेख भी V पर हमला ही है, कोई और reviews नहीं हैं। जिन हिस्सों में असल बात थी, वे पहले ही ठीक कर दिए गए हैं[1]
      mawfig.github खोजकर देखें तो HN पर इसे बार-बार फैलाया गया दिखता है, और आम तौर पर बदनाम करने के लिए इस्तेमाल हुआ है
      [1]: https://github.com/vlang/v/issues/14803
      [1]: https://github.com/vlang/v/issues/14787
      [1]: https://github.com/vlang/v/issues/14786
  • Evan को यह milestone हासिल करने पर बधाई। programming language design या compiler का अनुभव नहीं है, लेकिन Vale के लेख पढ़ना अच्छा लगता है

    • मेरी भी हालत कुछ ऐसी ही है, बस काश इसका नाम अलग होता
      अब Evan का Vale और Adobe Software Technology Lab का Val दोनों हैं, इसलिए related material खोजना काफी मुश्किल हो जाएगा
      https://www.val-lang.dev
    • मेरे पास भी ज्यादातर cases में लेख समझने के लिए background knowledge नहीं होती, फिर भी यह दिलचस्प लगता है
    • मुझे भी लगता है लेख बहुत अच्छे हैं और Vale का भविष्य exciting लगता है
  • “Vale तेज़ है: Vale LLVM में AOT compile होता है, static types इस्तेमाल करता है, speed और flexibility वाली memory safety के लिए नई generational references technique इस्तेमाल करता है, और जल्द ही region borrow checking लाकर और तेज़ हो जाएगा”
    https://vale.dev/

  • ऐसा लग रहा है जैसे 5 साल से चल रही दो लोगों की बहस चोरी-छिपे सुन रहा हूं
    कोई समझा सकता है कि यहां हो क्या रहा है? लेख बहुत कठिन है

    • सही है। इस लेख में background explanation काफी कम थी, और यह उन दोस्तों, sponsors और लोगों को ज़्यादा ध्यान में रखकर लिखा गया था जो Vale को लगातार follow कर रहे थे। HN जैसे general readers के लिए यह उल्टा असर करने वाली strategy है
      संक्षेप में, Vale एक ज्यादा साफ-सुथरी C++ जैसी language है, और generational references[0] का इस्तेमाल करती है, जो mentally ASan[1] चालू करके run करने जैसा है
      generational references में थोड़ा overhead होता है, लेकिन उसे regions[2], और खास तौर पर immutable region borrowing[3] से हटाया जा सकता है। इससे Vale memory safety बनाए रखते हुए high-performance language बनने के लक्ष्य के करीब पहुंचता है
      [0] https://verdagon.dev/blog/generational-references
      [1] https://github.com/google/sanitizers/wiki/AddressSanitizer
      [3] https://verdagon.dev/blog/zero-cost-borrowing-regions-overvi...
      [4] https://verdagon.dev/blog/zero-cost-borrowing-regions-part-1...