Spice: Zig’de alt nanosaniye ek yükle ince taneli paralelleştirme tekniği
(github.com/judofyr)Spice: Alt nanosaniyelik ek yükle paralel işleme
Spice, Zig’de heartbeat scheduling kullanarak son derece verimli paralel işleme sağlıyor.
- Alt nanosaniye ek yük: Bir fonksiyona paralel işleme özelliği eklendiğinde bile yalnızca nanosaniyenin altında bir ek yük oluşuyor.
- Çekişme yok: Thread’ler aynı iş için yarışmıyor. Sisteme thread eklense bile program yavaşlamıyor.
Performans karşılaştırması
- Rayon (Rust): 4 thread’de yaklaşık 15ns ek yük. 16 thread’de yaklaşık 14 kat hızlanma.
- Spice (Zig): 16 thread’de yaklaşık 11 kat hızlanma. Ek yük düşük olduğu için temel performansla neredeyse aynı.
Küçük ağaçlarda performans
- Küçük ağaçlar: Programın toplam çalışma süresi 1.56 mikrosaniye. Thread eklendikçe performans düşüyor.
- Paralel işlemede genel yaklaşım: Yeterli iş yoksa paralel işleme anlamlı değil.
Spice’ın hedefi
- Hedef: Paralel işleme eklense bile programın yavaşlamamasını sağlamak.
- Kısa çalışma süresi: Çalışma süresi kısa olduğunda çoklu thread işe yaramıyor. Eklenen thread’ler bekleme durumuna geçiyor.
Spice kullanımı
const spice = @import("spice");
fn sum(t: *spice.Task, node: *const Node) i64 {
var res: i64 = node.val;
if (node.left) |left_child| {
if (node.right) |right_child| {
var fut = spice.Future(*const Node, i64).init();
fut.fork(t, sum, right_child);
res += t.call(i64, sum, left_child);
if (fut.join(t)) |val| {
res += val;
} else {
res += t.call(i64, sum, right_child);
}
return res;
}
res += t.call(i64, sum, left_child);
}
if (node.right) |right_child| {
res += t.call(i64, sum, right_child);
}
return res;
}
- Tüm paralel fonksiyonlar parametre olarak bir task almalı.
- Fonksiyonu doğrudan çağırmak yerine
t.callkullanılmalı. - Başka bir thread’de iş kurmak için
forkçağrılmalı. - Fonksiyon kendi başına anlamlı bir iş yapmalı.
- Başka bir thread’deki işin tamamlanmasını beklemek için
joinçağrılmalı. joinnulldöndürürse iş doğrudan yapılmalı.
Work-stealing ve verimsizlikler
- Work-stealing: Her thread’in kendi yerel iş kuyruğu var. Kuyruk boşalınca başka thread’lerin işlerini çalıyor.
- Verimsizlikler: Dinamik dispatch, yerel olmayan iş kuyrukları, spin lock.
Uygulama ayrıntıları
Statik dispatch optimizasyonu
- Kod bloklarının paralel yürütülmesi: Kod blokları
forkvejoinkullanılarak paralel çalıştırılıyor. - Tekrarın kaldırılması: Kod bloğu başka bir thread’de çalıştırılmazsa sıralı olarak yürütülüyor.
Düşük ek yüklü heartbeat sinyali
- Heartbeat scheduling: Her 100 mikrosaniyede bir yerel iş kuyruğu kontrol edilip işler başka thread’lere gönderiliyor.
- Verimlilik: Heartbeat oluşmadığında fonksiyonun da verimli çalışması gerekiyor.
Global mutex
- Global mutex kullanımı: Rekabet olmadığında global mutex sorun oluşturmuyor.
Dalsız çift bağlı liste
- Çift bağlı liste: İş kuyruğunu yönetmek için kullanılıyor. Dallanma olmadan çalışıyor.
Stack kullanımını en aza indirme
- Stack kullanım optimizasyonu:
Futuredurumunu en aza indirerek stack kullanımı azaltılıyor.
Register üzerinden değer aktarma
- Register kullanımı:
Taskyapısının alanları register üzerinden aktarılıp performans optimize ediliyor.
Benchmark
- Benchmark: İlk geliştirme tek bir benchmark etrafında yapıldı.
Teşekkür
- Heartbeat scheduling araştırması: Geliştirme çeşitli araştırma makalelerine dayanıyor.
Sınırlamalar
- Kısıtlar: Yanlış kullanılırsa garip davranışlar ortaya çıkabilir.
- Yetersiz test: Test kapsamı yetersiz.
- Dizi/dilim desteği eksikliği: Diziler/dilimler için paralel işleme desteği yetersiz.
- Belgeleme eksikliği: Kullanıma dair dokümantasyon yetersiz.
- Ek benchmark eksikliği: Daha fazla benchmark gerekiyor.
- Hata işleme: Hata işleme yeterince ele alınmamış.
- ReleaseSafe testi eksikliği: ReleaseSafe modunda test gerekli.
SSS
- İsmin kökeni: Çok ince taneli paralelleştirmeyi ifade ediyor.
- Neden Zig ile uygulandı: Farklı dillerde de uygulanabilir.
- Rust’ta güvenli paralel işleme: Rust’ın katı semantiği nedeniyle ilk fikirleri keşfetmek zor.
GN⁺ özeti
- Spice, Zig’de son derece verimli paralel işleme sunan bir araştırma projesi.
- Alt nanosaniyelik ek yük ve çekişmesiz paralel işleme ile performansı en üst düzeye çıkarıyor.
- Heartbeat scheduling ile işleri verimli biçimde dağıtıyor.
- Kısıtlar ve yetersiz test gibi sınırlamaları var.
- Rust gibi diğer dillerde de benzer yaklaşımları araştırmak değerli olabilir.
1 yorum
Hacker News görüşleri
Bu uygulama, paralellik üretiminin ek yükünü dağıtarak dinamik otomatik ayrıntılandırma kontrolü sağlayan, yakın tarihli "heartbeat scheduling" araştırmasına dayanıyor
Kodun ayrıntılarını okumadım ama "sub-nanosecond overhead" ifadesi yanıltıcı ve pazarlama dili gibi görünüyor
Bu alana aşina değilim ama sunulan eşzamanlılık modelini beğendim
İlginç bir araştırma çalışması; kodun yanı sıra iyi bir mantık ve iyi yazılmış belgeler de var
Projenin sınırlamaları listesi:
Açıklamaya göre bu uygulama, çalışanların nanosaniye düzeyinde gecikme elde etmesi için busy-wait kullanıyor
Görev üreticisinin, busy-wait olmadan tüketiciyi uyandırmasının daha hızlı bir yolu olup olmadığını merak ediyorum
İlginç ve harika makalelerle bağlantılı
İşbirlikçi zamanlama, harika metriklere sahip birçok örüntünün temelidir
Harika
Benchmark ile ilgili README'ye de bakın: