Düşük seviyeli optimizasyon ve Zig
(alloc.dev)- Düşük seviyeli optimizasyon, Zig dilinde kolayca uygulanabilir
- Derleyici çoğu durumda optimizasyonu iyi yapar; ancak bazen daha iyi performans için programcının niyetini açıkça iletmesi gerekir
- Zig, derleme zamanı yürütme (comptime) özelliğiyle yüksek performanslı kod üretimini ve güçlü metaprogramlamayı destekler
- Rust ile karşılaştırıldığında Zig, anotasyonlar ve açık kod yapısı sayesinde daha hassas optimizasyonlara olanak tanır
- String karşılaştırma gibi tekrarlı işlemlerde comptime kullanılarak sıradan bir fonksiyondan daha iyi assembly kodu üretilebilir
Optimizasyon ve Zig
"Her şey mümkündür ama ilginç olanı kolay elde edilemez." şeklindeki ünlü uyarıda olduğu gibi, program optimizasyonu her zaman geliştiricilerin başlıca ilgi alanlarından biridir. Bulut altyapısı maliyetleri, gecikmeyi azaltma, sistem sadeleştirme gibi amaçlar için kod optimizasyonu zorunludur. Bu yazı, Zig'deki düşük seviyeli optimizasyon kavramını ve Zig'in güçlü yönlerini merkeze alarak açıklıyor.
Derleyiciye güvenebilir miyiz?
- Genel olarak "derleyiciye güvenin" tavsiyesi sık verilir; ancak pratikte derleyici beklentiden farklı davranabilir ya da dil belirtimini ihlal eden durumlar olabilir
- Yüksek seviyeli dillerde niyeti (intent) açık biçimde aktarmak zor olduğu için performans açısından kısıtlar oluşur
- Düşük seviyeli dillerde kodun açık yapısı sayesinde derleyici optimizasyon için gerekli bilgileri anlayabilir; örneğin JavaScript ve Zig'deki
maxArrayfonksiyonları karşılaştırıldığında Zig, açık türler, hizalama, alias olup olmama gibi bilgileri çalışma zamanında değil derleme zamanında iletir - Aynı
maxArrayişlemi Zig ve Rust ile yazıldığında neredeyse aynı yüksek performanslı assembly kodu elde edilebilir; ancak niyet ne kadar iyi ifade edilirse optimizasyon sonucu da o kadar iyileşir - Yine de derleyici performansına her zaman güvenilemeyeceği için, darboğaz bölgelerinde kodu ve derleme çıktısını doğrudan inceleyip optimizasyon yolları aranmalıdır
Zig'in rolü
- Zig; kesin açıklık, zengin yerleşik fonksiyonlar, pointer'lar ve anotasyonlar, comptime ve iyi tanımlanmış Illegal Behavior gibi özellikleri sayesinde soyut bilgilere ihtiyaç duymadan optimize edilmiş kod üretebilir
- Rust, bellek modeli sayesinde varsayılan olarak argüman alias'ının olmadığını garanti eder; Zig'de ise doğrudan noalias gibi anotasyonlar gerekir
- Yalnızca LLVM IR ölçüt alınırsa, Zig'in optimizasyon seviyesi de yüksektir
- Hepsinden önemlisi, Zig'in comptime'ı (derleme zamanı yürütme) güçlü bir optimizasyon aracıdır
comptime nedir?
- Zig'deki comptime, kod üretimi, sabit değer gömme, türe dayalı generic struct oluşturma gibi alanlarda kullanılır ve çalışma zamanı performansını artırmada önemli rol oynar
- comptime ile metaprogramlama yapılabilir
- C/C++ makroları veya Rust'un macro sistemiyle karşılaştırıldığında comptime, ayrı bir sözdizimi değil normal koddur
- comptime kodu AST'yi doğrudan değiştirmez; bunun yerine tüm türler için derleme zamanında denetleme, yansıtma ve üretim yapabilir
- comptime'ın esnekliği Rust gibi diğer dillerdeki iyileştirmeleri de etkilemiş ve Zig diline doğal biçimde entegre edilmiştir
comptime'ın sınırları
- token-pasting gibi bazı macro özellikleri, Zig comptime ile bire bir karşılanamaz
- Zig, kodun okunabilirliğine önem verdiği için kapsam dışına çıkıp değişken üretmeye veya makro tanımlamaya izin vermez
- Bunun yerine Zig comptime için type reflection, DSL uygulamaları, string parsing optimizasyonu gibi geniş metaprogramlama kullanım örnekleri vardır
comptime ile string karşılaştırma optimizasyonu
- Genel bir string karşılaştırma fonksiyonu her dilde yazılabilir; ancak Zig'de iki string'den biri comptime sırasında bilinen sabit olduğunda daha verimli assembly kodu üretilebilir
- Örneğin bir string her zaman "Hello!\n" ise, bu değer bayt bayt değil daha büyük bloklar halinde karşılaştırılarak optimize edilebilir
- Bunun için comptime kullanıldığında SIMD vektörleri, blok işleme ve kalan bayt optimizasyonu gibi yüksek performanslı kodlar derleme zamanında üretilebilir
- Bu yaklaşım sayesinde yalnızca tekrarlı string karşılaştırmaları değil, statik veriye dayalı çeşitli eşlemeler, perfect hash tabloları, AST parser'ları gibi performans odaklı pek çok yapı da gerçekleştirilebilir
Sonuç
- Zig, düşük seviyeli optimizasyon için son derece uygundur; açık kod yapısı ve güçlü comptime yetenekleri sayesinde en yüksek performans doğrudan uygulanabilir
- Rust gibi diğer dillerle karşılaştırıldığında da Zig'in derleme zamanı programlama yeteneği ve açıklığı, yüksek performanslı yazılım geliştirmede büyük avantaj sağlar
- Zig'in optimizasyon kabiliyeti, gelecekte daha da önemli bir rekabet avantajı olacaktır
1 yorum
Hacker News görüşleri
bun'a gerçekten hayranım.bunhayatımı inanılmaz kolaylaştırdı. Rust tabanlıuvde benzer bir deneyim sunuyorfor(;;);gibi açıkça sonsuz olan bir döngü gerçekten sonsuz döngü olmak zorunda ve Rust'takiloop {}için de aynı şey geçerli olmalı. Ama LLVM geliştiricileri bazen sadece C++ derleyicisi yaptıklarını sanıyor; bu yüzden Rust'ta "lütfen sonsuz döngü" denince LLVM "C++'ta öyle bir şey olmaz, optimize edelim!" diye davranıp sorun çıkarıyor. Yani yanlış dile yanlış optimizasyon uygulanmış oluyorcomptime) özelliği olmasa bile string karşılaştırmasını inline etmek ve unroll etmek C'de de gayet mümkün. İlgili örneki < x.lengthgibi döngüler yazdığı için JIT optimizasyonu devreye giriyor. Bu açıdan biraz kusur arama gibi, ama yine de küçük bir fark varcomptimekullanım örneğipurchase.calculate_tax().await.map_err(|e| TaxCalculationError { source: e })?;gibi bir kod niyet doludur, ama bunun makine kodunda nasıl görüneceğini öngörmek mümkün değildir-march=native, tüm program optimizasyonu vb.). Aslında C'de deunreachablegibi optimizasyon ipuçları dil uzantılarıyla mümkün ve Clang de constant folding konusunda çok agresif. Yani Zig'incomptime'ı ile C'nin codegen'i arasındaki farklar çoğu zaman derleyici optimizasyon ayarlarından doğuyor. TL;DR: C yavaşsa önce derleyici ayarlarını kontrol edin. Sonuçta optimizasyonun kalbi LLVMcomptime) ve tüm program derlemeye ağırlık veriyordu. Buna katılıyorum. Bu arada Virgil, 2006'dan beri compile-time'da tüm dili kullanma ve tüm program derleme desteği sunuyordu. Virgil LLVM'i hedeflemediği için hız karşılaştırması sonunda backend karşılaştırmasına dönüyor. Virgil bu yaklaşım sayesinde method call'ları önceden statik olarak bağlayabiliyor (devirtualize), kullanılmayan alanları/nesneleri büyük ölçüde temizleyebiliyor, hatta alanlardan heap nesnelerine kadar sabit yayılımı yapabiliyor ve tamamen özelleştirme sağlayabiliyorforloop sözdizimi bana çok dağınık geliyor. İki listeyi yan yana koyup hizalamak zorunda kalmak, sadece bakarken bile gözü yoruyor. Son dönem dillerin çok fazla "sihirli" sözdizimi ve özel sembol doldurmasının hata olduğunu düşünüyorum. Saatlerce bakmak isteyeceğim bir şey değil