- Vale’in bölge ödünç alımı prototipi ilk kez başarıyla derlendi; böylece jenerasyonel referanslarla bölgeleri birleştiren bellek güvenliği yaklaşımı gerçek programlarda doğrulanabilir hale geldi
- Geliştiriciler kodu C/C++’a yakın bir tarzda yazıp yalnızca gereken yerlerde pure ve bölge ödünç alımını uygulayarak jenerasyon kontrolü ek yükünü azaltabiliyor
- İlk zero-check Vale programı, roguelike seviye üretimi için bir Cellular Automata örneğiydi ve ortaya çıkan assembly,
unsafe_with_bounds modu ile neredeyse aynı seviyeye getirildi
- Benchmark’ta
safe_fastest, unsafe_with_bounds karşısında gözlemlenebilir bir yavaşlama göstermedi; unsafe_no_bounds ise iki moddan da 1.18 ± 0.01 kat daha hızlıydı
- Henüz C/Rust ile doğrudan bir karşılaştırma yapılmadı; LLVM optimizasyon gürültüsü, prototipin olgunluk düzeyi ve inline data desteğinin olmaması nedeniyle Vale’e özel bir pre-optimizer ile bölge özelliklerinin düzenlenmesi hâlâ yapılmayı bekliyor
Jenerasyonel referanslar ve bölge ödünç alımının birleşimi
- Vale’in bellek güvenliği yaklaşımı, reference counting, izlemeli garbage collection ve borrow checking kullanmama yönünde bir hedef taşıyor
- Temel yapı, geliştiricinin programı C veya C++’a yakın bir şekilde yazması ve Vale’in generational references mekanizmasının bellek güvenliğini koruması üzerine kurulu
- Ardından pure ve region borrowing uygulandığında jenerasyon kontrolü ek yükünün büyük kısmı ortadan kaldırılabiliyor
- Buna linear style da eklenirse Vale kodundaki jenerasyon kontrollerinin zero seviyesine kadar indirilebileceği düşünülüyor
- Bölge ödünç alımı tamamen opt-in olduğundan, önce rahatça yazıp yalnızca optimizasyon gereken bölümlere sonradan eklemek mümkün
- Amaç, aynı program içinde bazı kısımların Java gibi esnek, bazılarının Rust gibi hızlı ya da ikisi arasında bir noktada seçilebildiği bir yapı sunmak
Prototipi oluşturmak için gereken çalışmalar
- Son birkaç yılda derleyici altyapısı kurulurken bölge tabanlı ödünç alma sistemi ile generational references desteğinin birlikte çalışması için çalışmalar yapıldı
- Ödünç alma sisteminin kendisi karmaşık olduğu gibi, önceki şablonlardan daha güçlü full generics de gerekiyordu
- Bölgelerle jenerasyonel referansların doğal biçimde birlikte çalışması için yeni bir derleyici aşaması da gerekti
- Dahili olarak bölgeler, “pure height” tamsayılarına indirgeniyor
- Bölge generic parametresi negatif, varsayılan bölge 0, her pure block ise artan pozitif sayılarla ifade ediliyor
- Birkaç ay önce bölge prototipi tamamlandı; hâlâ pürüzlü yanları olsa da ilk kez bir şey başarıyla derlenebildi
- Sonuç olarak ilk zero-check Vale programı ortaya çıktı
--print_mem_overhead true derleyici bayrağıyla programdaki jenerasyon kontrolü sayısı sayılabiliyor
İlk zero-check programı ve assembly karşılaştırması
- İlk program, roguelike oyun seviyeleri üreten bir Cellular Automata örneğiydi
- Derleyici kodundaki küçük bir hata bile çıkan assembly’ye ek talimatlar koyarak son programda yapay ek yük oluşturabiliyor
- Sorunu izlemek için çıkan assembly sürekli olarak Vale’in unsafe modlarıyla karşılaştırıldı
unsafe_no_bounds: C’ye benzer şekilde tüm bellek güvenliği korumalarını kapatıyor ve generational references yerine raw pointer kullanıyor
unsafe_with_bounds: Rust’taki gibi dizi erişimlerine bounds checking ekliyor
- Aylar boyunca farklar izlendi ve sonunda çıkan assembly
unsafe_with_bounds modu ile neredeyse aynı hale geldi
- Beklenen tek fark, her allocation’ın başına pseudo-random bir generation number konmasıydı; bu sayı gerçek jenerasyon kontrollerinde okunmuyordu
- Dahili olarak bunu hızlı tutmak için monoton artan bir register kullanılıyor
- isolates veya unique references eklendiğinde bu fark da ortadan kaldırılabilir
Benchmark sonuçları ve ölçüm koşulları
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’in normal modu olan
safe_fastest, yalnızca bounds checking içeren moda kıyasla bir yavaşlama göstermiyor
- Bu ölçümde söz konusu yaklaşım gözlemlenebilir bir ek yük taşımıyor
- Doğrudan denemek isteyenler regions branch sürümünü derleyebilir, benchmarking scripts deposuna bakabilir ve sorularını discord server üzerinden sorabilir
- Ölçüm koşullarının belirgin sınırlamaları var
- Bu, C veya Rust gibi dillerle doğrudan karşılaştırmalı bir benchmark değil
- Bu derleyiciler yıllar boyunca geliştirilmiş ayrı optimizasyonlara sahip olduğundan deney değişkenlerini bulanıklaştırabilir
- Bellek güvenliği yaklaşımındaki farkı izole etmek için
unsafe_no_bounds ve unsafe_with_bounds ile karşılaştırma yapıldı
- Ölçüm ortamı Ubuntu 22.04 çalıştıran Razer Blade 15" 2018, 512GB SSD idi
- Ölçüm aracı hyperfine ve çalışma ortamı cset shield idi
Daha büyük programlarda ortaya çıkan optimizasyon gürültüsü
- Daha büyük programlarda kayda değer ölçüde optimizer noise gözlendi
- Bu, benchmark noise’dan farklıydı; ölçüm kurulumu
± 0.01 gibi çok tutarlı çalışma süreleri gösteriyordu
- Bir bölümdeki küçük bir değişiklik ölçüm sonuçlarını tek bir yöne kaydırabiliyordu
- Generation number boyutu değiştirildiğinde tutarlı biçimde
1.13 ± 0.01 seviyesinde negative overhead görülen bir durum da vardı
- Programda çok fazla generation number olmadığı için bu sonuç tuhaftı
- Register allocation değişimlerinin, anlamsal farklardan gelen performans farkını bastırmış olması mümkün
- Küçük bir roguelike oyun gibi daha büyük bir programda optimizer, bir
if ifadesi içindeki aynı iki branch’i birleştiremedi ve başka bariz optimizasyonları da kaçırdı
- Okunmayan bir integer’ın varlığının neyi etkilediği net değil; bunun bir LLVM hatası olması da mümkün
- Bu sonuç, Rust’taki MIR benzeri Vale’e özel bir pre-optimizer gerekebileceğine işaret ediyor
- LLVM daha çok C düşünülerek tasarlandı
- LLVM, generational references’ı kasıtlı olarak serbest bırakılmış belleğe erişim deseni olarak yorumlarsa bunu undefined behavior sayabilir
Uygulanabilirlik ve sonraki çalışmalar
- Jenerasyonel referanslar ile bölgeler birleştirildiğinde çok hızlı bir bellek güvenliği yaklaşımı ortaya çıkabiliyor
- Bu yaklaşımın iyi uyabileceği yazılım alanları şu özellikleri taşıyor
- tracing garbage collection’a kıyasla daha öngörülebilir latency istiyor
- reference counting’e göre daha iyi performans ve cache friendliness arıyor
- borrow checking’e kıyasla daha kolay prototipleme ve iterasyon yapmak istiyor
- Vale’in C veya C++ ile doğrudan karşılaştırılmasından önce yapılması gereken işler var
- LLVM optimizer’ın generation ve immutability çıkarsaması konusunda sorunları olduğundan Vale’e özel bir pre-optimizer gerekiyor
- Vale’in, şu anki tüm struct’ları heap’e koyan geçici çözüm yerine inline data desteği kazanması gerekiyor
- Bu benchmark’ta struct kullanılmadığı için inline data eksikliği bu sonuçları etkilemedi
- Bölge özellikleri hâlâ prototip aşamasında; pürüzlerin giderilip teknik borcun azaltılmasının ardından main branch’e birleştirilmesi gerekiyor
- Birleştirme sonrasında standart kütüphanenin bölgeleri kullanması planlanıyor; böylece kullanıcının main program code içinde bölgeleri doğrudan kullanması gerekmese bile bu avantajlardan yararlanması sağlanacak
- Mevcut ölçümler, zero-check programların mümkün olduğunu ve beklenen hız düzeyine ulaşabildiğini gösteriyor
1 yorum
Hacker News yorumları
Vale’i indirip denedim ama
valecderleyicisini ilk çalıştırdığımda argüman vermezsen doğrudan "(panic)" yazdırması kötü bir izlenim bıraktıpanicçok ağır bir ifade ve normal hata işleme durumlarında bundan kaçınılması gerektiğini düşünüyorum. Programın panic vermesi kontrolsüz bir durum hissi uyandırıyor, bu da hoş bir tat bırakmıyorSonra komut satırı argüman yardımına bakmaya çalıştım ama şu anda fiilen yok gibiydi; sitedeki Hello World örneğini
hello.vlolarak kaydedipvalec hello.vlçalıştırıncaUnknown subcommandçıktıBunun üzerine
valec build hello.vlçalıştırdım, bu kezUnrecognized input: hello.vlardından yine(panic)geldi;valec helpde yardımcı olmayınca sonunda vazgeçtim. Bunun nasıl kullanılacağını anlayamadımvalec-help-build.txtdosyasını doğrudancatedersen aradığın şeyin açıklandığını göreceksinDerleyici şu anda hâlâ oldukça pürüzlü bir durumda. Ağustostan mayısa kadar %100 bölge(region) prototiplemesine odaklandım; şu an yaşadığın şey de bu süreçte biriken teknik borç. Buna yardım sistemi için entegrasyon testlerinin olmaması da dahil
Son 1-2 aydır bu borcu kapatıyorum ama hâlâ 0.2 sürümündeki seviyeye geri dönebilmiş değilim. Daha fazla yardıma ihtiyacın olursa haber ver ya da Discord sunucusuna gel; yardımcı olacak çok kişi var
Yine de README bunu açıkça göstermiyor, “Try Vale” yazdığı için biraz muğlak kalıyor. Ama şu an için Ar-Ge/kavram kanıtı düzeyine daha yakın görünüyor
Kullanıcı arayüzü ya da bug’lar açısından bakarsak, 40 yıllık C++’ı 35 yıllık gdb ile debug etme deneyimi herhangi bir deneysel dille rahatlıkla yarışır. Mesela
funcname()::staticvarnameçıktısı tuhaf bir arayüz ve yarı yarıya başarısız oluyor. C++ build sistemlerinden hiç bahsetmiyorum bileDeneysel bir teknoloji söz konusuysa kavramı eleştirebilirsin ama pürüzlü bir kullanıcı arayüzünü bir yere kadar tolere edebilirim
https://github.com/ValeLang/Vale#building-a-vale-program
İzlemeli çöp toplamaya göre gecikmesi daha öngörülebilir, referans sayımına göre performansı ve cache dostluğu daha iyi, borrow checking’e göre de prototipleme ve yineleme daha kolaysa, bu merakın ötesinde gerçekten ilgi çekici
RSS akışına da abone olmaya başladım: https://verdagon.dev/rss.xml
Vale’in daha fazla destekçiye ihtiyacı var
https://github.com/sponsors/ValeLang
Bu yazı ön sayfadayken projenin aylık 3.000 dolar hedefine ulaşmasına yardımcı olunmasını isterim
Evan’ın bu işi tam zamanlı yapabilmesine yardımcı olmak istiyorum. Ben de destekçilerden biriyim. Hızlı, güvenli ve aynı zamanda prototiplemesi keyifli bir dil desteklenmeye değer
“Vale’e özel bir ön optimize edici, Rust’taki Cranelift’e benzer bir şey” muhtemelen MIR, yani orta seviye ara gösterimden söz ediyor. Bununla ilgili güzel bir blog yazısı var: https://blog.rust-lang.org/2016/04/19/MIR.html
Cranelift esas olarak JIT odaklı bir derleyici backend’i ama teorik olarak LLVM’in yerini de alabilir. Alternatif backend çalışması da sürüyor, fakat bazı kısıtları var: https://github.com/bjorn3/rustc_codegen_cranelift
Çoğu kodda bellek yönetimini düşünmek zorunda kalmadan, yalnızca sıcak kod yollarını sıfır maliyetli soyutlamalarla optimize etme seçeneği sunan bir yaklaşım iki tarafın da avantajlarını birleştiriyor gibi duruyor
Özellikle de rahatlık uğruna güvenlikten değil yalnızca performanstan ödün veriliyorsa
Paylaşımlı sahiplik kötü bir fikir olduğu için akıllı işaretçiler de kullanmıyorum
Bellek yönetimi meselesinin çoğunlukla önemsiz olduğunu düşünüyorum
Nesilsel referanslar (generational references) bağlamında güvenli denince tam olarak ne kastedildiğini merak etmeye devam ediyorum
Doğru anladıysam bu, use-after-free ve double-free’yi önlediği anlamına mı geliyor? Öyleyse beklenen nesil ile gerçek nesil eşleşmediğinde bellek erişiminde program yine de başarısız olabilir
Bu açıdan bakınca referans sayımı, izlemeli çöp toplama ve borrow checking’den daha az güvenli görünüyor
Bir referans üzerinden serbest bırakılmış belleğe erişmeye çalışırsanız öngörülebilir ve güvenli şekilde bir segmentation fault ya da assertion failure oluşması gerekir. İleride sanal adres alanını yeniden eşleyen iyileştirme gelirse segmentation fault’ları da ortadan kaldırabilecek olmamız heyecan verici
Yine de nesil indeksi kullanılıyorsa, gerçek erişim denenmeden önce erişimin geçerli olup olmadığını çalışma anında kontrol etmek de mümkün olmalı. Vale’de bunun mümkün olup olmadığını bilmiyorum
malloc/free’den daha güvenli ve başka avantajları da varcheckfonksiyonu, tahsisin nesil numarasına ihtiyaç duyduğu için tahsise erişiyor. Yani referansın o tahsise erişip erişemeyeceğini kontrol etmek için önce o tahsise erişmek gerekiyorElbette tahsis zaten serbest bırakıldıysa, o tahsise ve nesil numarasına erişmenin kendisi tanımsız davranış olduğundan bu işe yaramaz
O kadar bariz görünüyor ki benim çok büyük bir şeyi mi kaçırdığımı, yoksa burada söylenen “bellek güvenliği”nin bambaşka bir anlamı mı olduğunu anlayamıyorum
Vale, V gibi bir dil değil. V, https://mawfig.github.io/2022/06/18/v-lang-in-2022.html adresinde çok eleştirel bir inceleme aldı; isimler benzer olduğu için ben de onu Vale diye yanlış hatırlıyordum
Aynı hatayı yapan başkaları olur diye bunu not düşüyorum
Yazının içeriği artık geçerli değil ama hâlâ duruyor ve zaten o blogdaki tek yazı da bu
Şu an 2023 ve V de beta (0.4). Üstelik o yazıyı hazırlayan kişi tek kullanımlık bir GitHub hesabıyla bu inceleme/saldırıyı yayımlayıp tartışma yaratmış, sonra da kaybolmuş
O blogdaki tek yazı da V’ye saldıran bu yazı; başka inceleme yok. Kayda değer içerik taşıyan kısımlar zaten düzeltildi[1]
mawfig.githubdiye aratırsanız bunun HN’de tekrar tekrar dolaşıma sokulduğunu ve genelde karalama için kullanıldığını da görebilirsiniz[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’ı bu dönüm noktasına ulaştığı için tebrik ederim. Programlama dili tasarımı ya da derleyici konusunda deneyimim yok ama Vale yazılarını okumaktan keyif alıyorum
Artık Evan’ın Vale’i ile Adobe Software Technology Lab’in Val’i var ve bu yüzden ilgili şeyleri aratmak epey zorlaşacak gibi görünüyor
https://www.val-lang.dev
“Vale hızlıdır: Vale, LLVM ile AOT derlenir, statik tip kullanır, hız ve esneklik sunan bellek güvenliği için yeni bir nesilsel referanslar tekniği kullanır ve yakında region borrow checking ekleyerek daha da hızlanacaktır”
https://vale.dev/
İki kişinin 5 yıldır süren tartışmasına kulak misafiri oluyormuşum gibi geliyor
Burada neler olduğunu açıklayabilecek biri var mı? Yazı fazla anlaşılmaz
Kısaca özetlemek gerekirse Vale, daha temiz bir C++ benzeri dil ve zihinsel olarak ASan[1] açık çalıştırmaya benzeyen nesilsel referanslar[0] kullanıyor
Nesilsel referansların bir miktar ek yükü var ama bu, region’lar[2], daha doğrusu değişmez region borrow’ları[3] ile ortadan kaldırılabiliyor. Bu da Vale’i, bellek güvenliğini korurken yüksek performanslı bir dil olma hedefine yaklaştırıyor
[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...