Bazel'in paralel değerlendirme ve artım modeli.
Veri modeli
Veri modeli aşağıdaki öğelerden oluşur:
SkyValue
. Düğümler olarak da adlandırılır.SkyValues
, derleme sırasında oluşturulan tüm verileri ve derlemenin girişlerini içeren değişmez nesnelerdir. Örnekler: giriş dosyaları, çıkış dosyaları, hedefler ve yapılandırılmış hedefler.SkyKey
. BirSkyValue
öğesine referans vermek için kullanılan kısa ve değiştirilemez ad (ör.FILECONTENTS:/tmp/foo
veyaPACKAGE://foo
).SkyFunction
. Anahtarlarına ve bağımlı düğümlere göre düğümler oluşturur.- Düğüm grafiği. Düğümler arasındaki bağımlılık ilişkisini içeren bir veri yapısı.
Skyframe
: Bazel'in temelini oluşturan artımlı değerlendirme çerçevesinin kod adı.
Değerlendirme
Derleme, derleme isteğini temsil eden düğümün değerlendirilmesinden oluşur (bu, ulaşmaya çalıştığımız durumdur ancak bu süreçte çok fazla eski kod vardır). Önce SkyFunction
bulunur ve üst düzey SkyKey
anahtarıyla çağrılır. Ardından işlev, üst düzey düğümü değerlendirmek için değerlendirmesi gereken düğümlerin değerlendirilmesini ister. Bu da sırayla diğer işlev çağrılarına yol açar ve bu işlem, yaprak düğümlere (genellikle dosya sistemindeki giriş dosyalarını temsil eden düğümler) ulaşılana kadar devam eder. Son olarak, üst düzey SkyValue
değeri, bazı yan etkiler (ör. dosya sistemindeki çıktı dosyaları) ve derlemeye dahil olan düğümler arasındaki bağımlılıkların yönlendirilmiş döngüsüz grafiği elde edilir.
Bir SkyFunction
, işini yapmak için gereken tüm düğümleri önceden bilemiyorsa birden fazla geçişte SkyKeys
isteğinde bulunabilir. Basit bir örnek, sembolik bağlantı olduğu anlaşılan bir giriş dosyası düğümünü değerlendirmektir: İşlev dosyayı okumaya çalışır, bunun bir sembolik bağlantı olduğunu fark eder ve böylece sembolik bağlantının hedefini temsil eden dosya sistemi düğümünü getirir. Ancak bu da sembolik bağlantı olabilir. Bu durumda orijinal işlevin de hedefini getirmesi gerekir.
İşlevler, kodda SkyFunction
arayüzü ve SkyFunction.Environment
adlı bir arayüz tarafından sağlanan hizmetlerle temsil edilir. İşlevlerin yapabileceği işlemler:
env.getValue
numaralı telefonu arayarak başka bir düğümün değerlendirilmesini isteyin. Düğüm varsa değeri döndürülür, aksi takdirdenull
döndürülür ve işlevin kendisininnull
döndürmesi beklenir. İkinci durumda, bağımlı düğüm değerlendirilir ve ardından orijinal düğüm oluşturucu tekrar çağrılır ancak bu kez aynıenv.getValue
çağrısınull
olmayan bir değer döndürür.env.getValues()
işlevini çağırarak birden fazla başka düğümün değerlendirilmesini isteyin. Bu işlev, bağımlı düğümlerin paralel olarak değerlendirilmesi dışında temelde aynı işlemi yapar.- Çağrılmaları sırasında hesaplama yapma
- Dosya sistemine dosya yazma gibi yan etkileri olabilir. İki farklı işlevin birbirini etkilememesine dikkat edilmelidir. Genel olarak, yazma yan etkileri (verilerin Bazel'den dışarıya aktığı yerler) sorunsuz çalışır. Okuma yan etkileri (verilerin kayıtlı bir bağımlılık olmadan Bazel'e aktığı yerler) ise kayıtlı olmayan bir bağımlılık oldukları ve bu nedenle yanlış artımlı derlemelere neden olabilecekleri için sorunlu çalışır.
SkyFunction
uygulamaları, bağımlılıkları istemek dışında (ör. dosya sistemini doğrudan okuyarak) verilere başka bir şekilde erişmemelidir. Aksi takdirde Bazel, okunan dosyadaki veri bağımlılığını kaydetmez ve bu da yanlış artımlı derlemelere yol açar.
Bir işlev, görevini yerine getirmek için yeterli veriye sahip olduğunda tamamlandığını belirten bir null
dışı değer döndürmelidir.
Bu değerlendirme stratejisinin çeşitli avantajları vardır:
- Sızdırmazlık. İşlevler yalnızca diğer düğümlere bağlı olarak giriş verilerini isterse Bazel, giriş durumu aynı olduğunda aynı verilerin döndürülmesini garanti edebilir. Tüm gökyüzü işlevleri deterministikse bu, tüm derlemenin de deterministik olacağı anlamına gelir.
- Artımlılığı düzeltin ve mükemmelleştirin. Tüm işlevlerin tüm giriş verileri kaydedilirse Bazel, giriş verileri değiştiğinde yalnızca geçersiz kılınması gereken tam düğüm kümesini geçersiz kılabilir.
- Paralellik. İşlevler yalnızca bağımlılık isteğinde bulunarak birbirleriyle etkileşime girebildiğinden, birbirine bağlı olmayan işlevler paralel olarak çalıştırılabilir ve Bazel, sonuçların sıralı olarak çalıştırılmış gibi olacağını garanti edebilir.
Artımlılık
İşlevler yalnızca diğer düğümlere bağlı olarak giriş verilerine erişebildiğinden Bazel, giriş dosyalarından çıkış dosyalarına kadar eksiksiz bir veri akışı grafiği oluşturabilir ve bu bilgileri yalnızca gerçekten yeniden oluşturulması gereken düğümleri (değiştirilen giriş dosyaları kümesinin ters geçişli kapanımı) yeniden oluşturmak için kullanabilir.
Özellikle iki olası artış stratejisi vardır: alttan yukarıya ve yukarıdan aşağıya. Hangisinin en iyi olduğu, bağımlılık grafiğinin nasıl göründüğüne bağlıdır.
Aşağıdan yukarıya geçersiz kılma sırasında, bir grafik oluşturulduktan ve değiştirilen girişler kümesi bilindikten sonra, değiştirilen dosyalara geçişli olarak bağlı olan tüm düğümler geçersiz kılınır. Aynı üst düzey düğümün tekrar oluşturulacağını biliyorsak bu yöntem idealdir. Alttan yukarıya geçersiz kılma işleminin, değiştirilip değiştirilmediklerini belirlemek için önceki derlemenin tüm giriş dosyalarında
stat()
komutunun çalıştırılmasını gerektirdiğini unutmayın. Bu durum, değiştirilen dosyalar hakkında bilgi edinmek içininotify
veya benzer bir mekanizma kullanılarak iyileştirilebilir.Yukarıdan aşağıya geçersiz kılma sırasında, üst düzey düğümün geçişli kapanımı kontrol edilir ve yalnızca geçişli kapanımı temiz olan düğümler tutulur. Mevcut düğüm grafiğinin büyük olduğunu ancak bir sonraki derlemede yalnızca küçük bir alt kümeye ihtiyacımız olduğunu biliyorsak bu daha iyidir: Aşağıdan yukarıya geçersiz kılma, yukarıdan aşağıya geçersiz kılmanın aksine, yalnızca ikinci derlemenin küçük grafiğini izleyen ilk derlemenin daha büyük grafiğini geçersiz kılar.
Şu anda yalnızca aşağıdan yukarıya geçersiz kılma işlemi yapıyoruz.
Daha fazla artış elde etmek için değişiklik budama özelliğini kullanırız: Bir düğüm geçersiz kılınır ancak yeniden oluşturulduğunda yeni değerinin eski değeriyle aynı olduğu anlaşılırsa bu düğümdeki değişiklik nedeniyle geçersiz kılınan düğümler "yeniden oluşturulur".
Örneğin, bir C++ dosyasındaki yorum değiştirilirse bu durum yararlı olur. Bu durumda, yorumdan oluşturulan .o
dosyası aynı olur ve bağlayıcıyı tekrar çağırmamız gerekmez.
Artımlı Bağlama / Derleme
Bu modelin temel sınırlaması, bir düğümün geçersiz kılınmasının her şeyi kapsayan bir işlem olmasıdır. Bir bağımlılık değiştiğinde, daha iyi bir algoritma olsa bile bağımlı düğüm her zaman sıfırdan yeniden oluşturulur. Bu algoritma, düğümün eski değerini değişikliklere göre değiştirir. Bu özelliğin kullanışlı olacağı birkaç örnek:
- Artımlı bağlama
.jar
içinde tek bir.class
dosyası değiştiğinde,.jar
dosyasını baştan oluşturmak yerine teorik olarak değiştirebiliriz.
Bazel'in şu anda bu özellikleri ilkeli bir şekilde desteklememesinin (artımlı bağlantı için bir miktar desteğimiz var ancak bu destek Skyframe'de uygulanmıyor) iki nedeni var: Performans kazancımız sınırlıydı ve mutasyonun sonucunun temiz bir yeniden derlemenin sonucuyla aynı olacağını garanti etmek zordu. Ayrıca Google, bit bit tekrarlanabilir derlemelere değer veriyor.
Şimdiye kadar, pahalı bir derleme adımını basitçe ayrıştırarak ve bu şekilde kısmi yeniden değerlendirme yaparak her zaman yeterince iyi bir performans elde edebiliyorduk. Bu yöntem, bir uygulamadaki tüm sınıfları birden fazla gruba ayırır ve bunları ayrı ayrı dex'e dönüştürür. Bu sayede, bir gruptaki sınıflar değişmezse dexing işleminin yeniden yapılması gerekmez.
Bazel kavramlarıyla eşleme
Aşağıda, Bazel'in derleme gerçekleştirmek için kullandığı SkyFunction
uygulamalarından bazılarıyla ilgili genel bir bakış sunulmaktadır:
- FileStateValue.
lstat()
sonucunda elde edilen değer. Mevcut dosyalar için, dosyada yapılan değişiklikleri tespit etmek amacıyla ek bilgiler de hesaplarız. Bu, Skyframe grafiğindeki en düşük seviyeli düğümdür ve bağımlılığı yoktur. - FileValue. Bir dosyanın gerçek içeriği ve/veya çözümlenmiş yoluyla ilgilenen her şey tarafından kullanılır. İlgili
FileStateValue
ve çözülmesi gereken tüm sembolik bağlantılara (ör.a/b
içinFileValue
,a
'ün çözülmüş yolunu vea/b
'nin çözülmüş yolunu gerektirir) bağlıdır. Bazı durumlarda (ör. dosya sistemi globlarını (srcs=glob(["*/*.java"])
gibi) değerlendirirken dosyanın içeriğine aslında gerek duyulmadığı içinFileStateValue
arasındaki ayrım önemlidir. - DirectoryListingValue. Temel olarak
readdir()
sonucudur. Dizinle ilişkilendirilmişFileValue
bağlıdır. - PackageValue. BUILD dosyasının ayrıştırılmış sürümünü temsil eder. İlişkili
BUILD
dosyasınınFileValue
değerine ve paketteki glob'ları (birBUILD
dosyasının içeriğini dahili olarak temsil eden veri yapısı) çözmek için kullanılan tümDirectoryListingValue
değerlerine bağlıdır. - ConfiguredTargetValue. Yapılandırılmış bir hedefi temsil eder. Bu hedef, bir hedefin analizi sırasında oluşturulan işlemler kümesinin ve bu hedefe bağlı yapılandırılmış hedeflere sağlanan bilgilerin bir demetidir.
PackageValue
, doğrudan bağımlılıklarınConfiguredTargetValues
ve derleme yapılandırmasını temsil eden özel bir düğüme bağlıdır. - ArtifactValue. Derlemedeki bir dosyayı temsil eder. Kaynak veya çıkış yapısı olabilir (yapılar, dosyalarla neredeyse eşdeğerdir ve derleme adımlarının gerçek yürütülmesi sırasında dosyalara atıfta bulunmak için kullanılır). Kaynak dosyalar için ilişkili düğümün
FileValue
, çıkış yapıtları için ise yapıtı oluşturan işleminActionExecutionValue
değerine bağlıdır. - ActionExecutionValue. Bir işlemin yürütülmesini temsil eder. Giriş dosyalarının
ArtifactValues
bağlıdır. Yürüttüğü işlem şu anda gökyüzü anahtarı içinde yer alıyor. Bu durum, gökyüzü anahtarlarının küçük olması gerektiği kavramına aykırıdır. Bu tutarsızlığı gidermek için çalışıyoruz (Skyframe'de yürütme aşamasını çalıştırmazsakActionExecutionValue
veArtifactValue
kullanılmadığını unutmayın).