1 puan yazan GN⁺ 2025-05-23 | 1 yorum | WhatsApp'ta paylaş
  • Rust ile yazılan rav1d AV1 çözücüsünün, C tabanlı dav1d'ye kıyasla yaklaşık %9 daha yavaş olduğu tespit edildi
  • Arabellek başlatma optimizasyonu ve yapı karşılaştırma mantığındaki iyileştirmelerle, ayrı ayrı sırasıyla %1,5 ve %0,7 hız artışı sağlandığı doğrulandı
  • Profil oluşturma aracı samply kullanılarak iki sürüm arasındaki performans farkının nedenleri somut biçimde belirlendi
  • Rust'ın varsayılan PartialEq uygulaması yerine bayt düzeyinde karşılaştırma yöntemi kullanılarak verimlilik artırıldı
  • Bu optimizasyonlarla toplam performans farkının yaklaşık %30'u giderildi, ancak hâlâ ek optimizasyon alanı bulunuyor

Arka plan ve yaklaşım

  • rav1d, dav1d AV1 çözücüsünün c2rust ile Rust'a taşındığı ve asm optimizasyon fonksiyonları ile Rust diline özgü güvenlik iyileştirmelerinin uygulandığı bir proje
  • Kamuya açık temel performans ölçütleri tanımlanmış durumda ve Rust tabanlı rav1d, C tabanlı dav1d'den yaklaşık %5 daha yavaş
  • Karmaşık video çözücünün genel yapısı yerine, aynı girdi altında ikili çalışma süresi farkına odaklanan bir analiz yapıldı
  • Performans ölçüm aracı (hyperfine) ve profiler (samply) ile sistemli bir karşılaştırma gerçekleştirildi
  • Hedef ortam macOS M3 çipi ve analiz, sadeleştirme için tek iş parçacıklı çalıştırma üzerinde yapıldı

Performans ölçümü: varsayılan karşılaştırma

  • Aynı test dosyasıyla (Chimera-AV1-8bit-1920x1080-6736kbps.ivf) her iki sürüm de derlenip kıyaslandı
  • rav1d yaklaşık 73,9 saniye, dav1d ise yaklaşık 67,9 saniye sürdü; yani yaklaşık 6 saniyelik (%9) bir çalışma süresi farkı görüldü
  • Her derleyici de (Clang, Rustc) neredeyse aynı LLVM sürümünü kullanıyor

Profil analizi

  • samply profiler'ı ile her çalıştırılabilir dosyanın fonksiyon bazlı örnek sayıları karşılaştırıldı
  • NEON (ARM SIMD) tabanlı assembly fonksiyonlarının çağrı yolları ve örnek dağılımı özellikle incelendi
  • dav1d, asm fonksiyonlarını dallanarak çağırmak için ayrı filtre fonksiyonlarına ayrılırken, rav1d hepsini tek bir dispatch fonksiyonunda yönetiyor
  • cdef_filter_neon_erased fonksiyonunun Self örnek sayısının, dav1d'deki iki fonksiyonun toplamından yaklaşık 270 daha fazla olduğu görüldü (toplamın yaklaşık %1'i)
  • Analiz sonucunda, geçici arabelleğin (zero-initialized buffer) gereksiz yere büyük ölçekte başlatıldığı bölüm yakalandı

Arabellek başlatmasını kaldırma optimizasyonu

  • Rust, güvenlik amacıyla [0u16; LEN] gibi bir yöntemle otomatik zeroing uygular
  • Ancak C tarafında (dav1d), arabellek açıkça zeroing yapılmadan bırakılır ve yalnızca gerçekten kullanılan alanlara değer yazılır
  • Rust'ta std::mem::MaybeUninit kullanılarak gereksiz başlatma maliyeti kaldırıldı
  • cdef_filter_neon_erased fonksiyonunun Self örnek sayısı 670'ten 274'e kadar ciddi biçimde düştü
  • Başka bir büyük Align16 arabelleğinde de başlatma işlemi döngünün dışına hoist edilerek bu maliyet tek seferle sınırlandı
  • Optimizasyon sonrasında benchmark sonucu yaklaşık 72,6 saniyeye indi; bu da 1,2 saniyelik (%1,5) iyileşme anlamına geliyor

Yapı karşılaştırma optimizasyonu

  • Profildeki inverted stack analizi, add_temporal_candidate fonksiyonunun beklenenden daha verimsiz çalıştığını ortaya koydu
  • Bu fonksiyon içinde Mv yapısının alan karşılaştırması (PartialEq otomatik türetimi), gereksiz yere yavaş kod üretiyordu
  • C tarafında, union kullanılarak uint32_t düzeyinde verimli bir karşılaştırma yapılıyor
  • Rust'ta ise unsafe kullanmaktan kaçınılarak zerocopy::AsBytes trait'i ile bayt dilimi düzeyinde karşılaştırma uygulandı
  • Bu optimizasyon da ek olarak 0,5 saniyelik (yaklaşık %0,7) performans artışı sağladı

Sonuç ve özet

  • İki basit optimizasyonla (arabellek başlatmasının kaldırılması ve yapıların bayt düzeyinde karşılaştırılması) çalışma süresinde toplam %2'nin üzerinde kısalma sağlandı
  • Buna rağmen hâlâ yaklaşık %6'lık bir performans farkı bulunuyor ve ek optimizasyon potansiyeli yüksek
  • Profiler anlık görüntüleri arasında karşılaştırma yapma yaklaşımının etkili olduğu görüldü
  • rav1d ve dav1d için snapshot analizine dayalı ek optimizasyon olasılığı yüksek
  • Proje bakımcılarının aktif geri bildirimi ve iş birliği sayesinde güvenlikten ödün vermeden iyileştirme sağlandı

Özet

  • Profiler (samply) ve benchmark (hyperfine) araçlarıyla rav1d ile dav1d arasındaki 6 saniyelik (%9) çalışma süresi farkı ayrıntılı biçimde analiz edildi
  • İki ana optimizasyon:
    • ARM'e özgü kodda gereksiz arabellek zeroing işleminin kaldırılması (1,2 saniye, -%1,6)
    • Küçük sayısal yapıların PartialEq uygulamasının hızlı bayt karşılaştırmasıyla değiştirilmesi (0,5 saniye, -%0,7)
  • Yeni unsafe kod eklenmeden, her optimizasyon birkaç düzine satır içinde sade biçimde uygulandı
  • Bakımcılarla iş birliği ve PR incelemeleri sayesinde hem güvenilirlik hem kalite iyileştirildi
  • Hâlâ yaklaşık %6'lık performans farkı kaldığından, profiler tabanlı ek karşılaştırmalı optimizasyon çalışmaları için geniş alan bulunuyor

Hadi siz de deneyin! Belki rav1d bir gün dav1d'den daha hızlı bile olabilir 👀🦀.

1 yorum

 
GN⁺ 2025-05-23
Hacker News görüşleri
  • u16 iki değerini karşılaştırma meselesinin ilginç bir konu olduğu paylaşılıyor; ilgili issue bağlantısı verilmiş: https://github.com/rust-lang/rust/issues/140167
    • Tartışmada store forwarding'den bahsedilmemiş olmasına şaşırıyor; -O3 altındaki kod üretiminin aşırıya kaçtığını ama -O2'de makul olduğunu, yapılardan birinin işlemden hemen sonra gelmesi halinde 32 bit yükleme denemesinin store forwarding başarısızlığına yol açarak performans kazanımını anlamsız kılabileceğini ayrıntılı biçimde açıklıyor; inline olmayan / PGO'suz durumlarda derleyicinin optimizasyon uygunluğunu değerlendirmek için gerekli bilgiye sahip olmadığını belirtiyor
    • Issue tartışmasının basitçe “ben de yaşadım” ve “ne zaman düzelecek” türü yorumlarla dolu olmamasını güzel buluyor; bir web geliştiricisi olarak GitHub issue'larından memnun olmadığını dürüstçe paylaşıyor
    • Bunun, derleyici geliştirmenin ne kadar karmaşık olduğunu gösteren bir örnek olduğu; C ailesi derleyicilerinin de bu tür sorunları çok daha iyi ele alamayacağı yönünde güven ifade ediliyor
  • Blog yazısına profiler sonuçlarının nasıl eklendiğini merak ediyor; HTML düğümlerinin doğrudan kopyalanıp kopyalanmadığını soruyor
  • Buffer başlatmayı (zeroing) atlamanın performans avantajına dair yazının, birkaç gün önceki ilgili yazının ardından gelmesini ilginç buluyor; eski yazıyı paylaşıyor: https://news.ycombinator.com/item?id=44032680
  • Yazı başlığının, gerçek sonuca kıyasla fazla çekingen olduğu söyleniyor; aslında iki iyi optimizasyon sayesinde %2,3 hız artışı olduğu vurgulanıyor
    • %1,5'lik iyileştirmenin yalnızca aarch64 için geçerli olduğu, bu yüzden bunu genel toplam gibi söylemenin pek adil olmadığı; ARM/x86 oranı düşünülürse bunun yaklaşık yarısı olarak görülmesi gerektiği savunuluyor
  • Gönderinin faydalı olduğu ve 16 bit tamsayı çiftlerinin karşılaştırılmasında verimsiz kod bulunmasının etkileyici olduğu değerlendiriliyor
    • Rust/LLVM geliştiricilerinin bu optimizasyonu mümkün olan yerlerde otomatik olarak uygulayıp uygulayamayacağı merak ediliyor; Rust'ta bellek başlatma ile ilgili bilgilerin çok daha isabetli olduğu belirtiliyor
  • Her şey eşitse, bu tür codec'lerin Rust yerine WUFFS gibi bir dilde veya ona benzer özel amaçlı bir dilde ele alınması gerektiği düşünülüyor; dav1d kadar karmaşık kodu WUFFS'a dönüştürmenin mevcut C kodunu çevirmekten ve temizlemekten çok daha zor olduğu deneyimle paylaşılıyor; buna rağmen böyle bir girişimin değerli olduğu ve uygarlık düzeyinde yatırım yapılmayı hak ettiği savunuluyor
    • WUFFS'un Matroska, webm, mp4 gibi konteynerleri parse etmek için uygun olduğu ama video decoder'lar için hiç uygun olmadığı açıklanıyor; dinamik bellek ayırma olmamasının dinamik veri işlemeyi zorlaştırdığı, video codec'lerinin yalnızca dosya parse etmekten ibaret olmayıp çok çeşitli dinamik durum yönetimi gerektirdiği vurgulanıyor
  • rav1d ödülünün ne durumda olduğunu merak edip kendi kendine soruyormuş gibi yazdığını, aynı şeyi düşünen başkalarının olmasına sevindiğini söylüyor
  • Eğlenceli bir meme ile başlayan yazıların iyi olduğuna dair bir izlenim paylaşılıyor; bunun yakın zamanda konuşulan “Rav1d AV1 Decoder Rust optimizasyonu için 20 bin dolarlık ödül” tartışmasıyla bağlantılı olduğu belirtiliyor ve bağlantı ekleniyor: https://news.ycombinator.com/item?id=43982238
    • Bunun açık bir “Nominative determinism” vakası olduğu yönünde esprili bir yorum yapılıyor
  • Dürüst olmak gerekirse ilk optimizasyonun, perf doğru kullanıldığında kolayca bulunabilecek yaygın bir tür olduğu için biraz şaşırtıcı olduğu söyleniyor; zeroing meselesinin ilk yazıda zaten tartışıldığını sandığını, ikinci optimizasyonun daha karmaşık ve ilginç olsa da yine perf'in yönlendirdiği bir keşif olduğunu vurguluyor; perf aracının faydasını küçümsememek gerektiğini öğütlüyor
    • Yalnızca perf kullanılmadığını; C sürümü ile Rust sürümü arasında diferansiyel profiling ve manuel eşleştirme yapılarak sonuca ulaşıldığını netleştiriyor; perf diff özelliği olsa da sembol adları farklı olduğu için otomatik eşleştirmenin zor olduğuna dikkat çekiyor
    • Yaklaşımın aarch64 tabanlı Apple cihazları perspektifinden geldiğini belirtiyor; farklı geçmişlerden gelen insanların, sonradan dönüp bakınca “çok bariz” görünen noktaları bile hızlı yakalayabildiğini deneyimiyle vurguluyor
  • Son dönemde ffmpeg'in Twitter hesabının Rust'la ilgili konularda açıklama yapmasına bu olayın yol açmış olabileceği tahmin ediliyor; ilgili tweet paylaşılmış: https://x.com/ffmpeg/status/1924137645988356437?s=46
    • ffmpeg'in Twitter hesabını okuyunca ffmpeg kullanımı konusunda şüpheye düştüğünü dürüstçe söylüyor; alternatif olmamasını üzücü buluyor; geliştirici topluluğunun çok toksik olduğunu belirtiyor; en yüksek performansın önemli olabileceğini ama dış dünyayla veri alışverişi yapılan ortamlarda ffmpeg'de her yıl birkaç kez uzaktan istismar edilebilir zafiyet (CVE) çıkabildiğini hatırlatıyor; güvenlik açısından sıkı bir sandbox gerekliliğini vurguluyor; hızlı ve güvenli çözümü birlikte inşa edebilecek bir orta yol gerektiğini savunuyor; bağlantı paylaşıyor: https://ffmpeg.org/security.html
    • Daha iyi tepkinin, dav1d performansını iyileştirerek verilmesi olduğu öneriliyor; spor rekorları benzetmesiyle, sadece dereceleri biraz iyileştirmenin gerçek bir dünya rekoru kırmak kadar etkileyici olmadığını söylüyor; asıl çözümün gerçekten daha hızlı ve yenilikçi sonuçlar üretmek olduğu neşeli bir dille anlatılıyor