Bazel'in paralel değerlendirme ve artımlı model.
Veri modeli
Veri modeli aşağıdaki öğelerden oluşur:
SkyValue
. Düğüm 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
:SkyValue
'a referans vermek için kullanılan kısa ve değiştirilemeyen bir ad (ör.FILECONTENTS:/tmp/foo
veyaPACKAGE://foo
).SkyFunction
. Anahtarlarına ve bağımlı düğümlerine göre düğümler oluşturur.- Düğüm grafiği. Nodlar arasındaki bağımlılık ilişkisini içeren bir veri yapısı.
Skyframe
. Bazel'in temel aldığı artımlı değerlendirme çerçevesinin kod adı.
Değerlendirme
Derleme, derleme isteğini temsil eden düğümü değerlendirmekten oluşur (Bu, ulaşmaya çalıştığımız durumdur ancak bu yolda çok fazla eski kod vardır). Öncelikle 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 ihtiyaç duyduğu düğümlerin değerlendirilmesini ister. Bu da, yaprak düğümlere (genellikle dosya sistemindeki giriş dosyalarını temsil eden düğümler) ulaşılana kadar diğer işlev çağrılarına neden olur. Son olarak, üst düzey SkyValue
değerini, bazı yan etkileri (ör. dosya sistemindeki çıkış dosyaları) ve derlemede yer alan düğümler arasındaki bağımlılıkların yönlendirilmiş döngüsüz grafiğini elde ederiz.
Bir SkyFunction
, görevini yapmak için ihtiyaç duyduğu tüm düğümleri önceden söyleyemiyorsa SkyKeys
'yi birden fazla geçişte isteyebilir. Basit bir örnek, sembolik bağlantı olduğu ortaya çıkan bir giriş dosyası düğümünü değerlendirmektir: İşlev dosyayı okumaya çalışır, sembolik bağlantı olduğunu anlar ve böylece sembolik bağlantının hedefini temsil eden dosya sistemi düğümünü getirir. Ancak bu da bir sembolik bağlantı olabilir. Bu durumda, orijinal işlevin kendi hedefini de getirmesi gerekir.
İşlevler kodda SkyFunction
arayüzü ve kendisine sağlanan hizmetler SkyFunction.Environment
adlı bir arayüz tarafından temsil edilir. İşlevler şunları yapabilir:
env.getValue
çağrısı yaparak başka bir düğümün değerlendirilmesini isteyin. Düğüm kullanılabilir durumdaysa 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 yeniden çağrılır ancak bu kez aynıenv.getValue
çağrısınull
olmayan bir değer döndürür.env.getValues()
çağrısı yaparak birden fazla düğümün değerlendirilmesini isteyin. Bu yöntem, bağımlı düğümlerin paralel olarak değerlendirilmesi dışında temel olarak aynı işlemi gerçekleştirir.- Çağrılmaları sırasında hesaplama yapma
- Dosya sistemine dosya yazma gibi yan etkileri olabilir. İki farklı işlevin birbirinin alanına girmediğinden emin olun. Genel olarak yazma yan etkileri (verilerin Bazel'den dışarıya aktığı durumlar) kabul edilir. Okuma yan etkileri (verilerin kayıtlı bir bağımlılık olmadan Bazel'e içeriye aktığı durumlar) ise kayıtlı bir bağımlılık olmadığı ve bu nedenle yanlış artımlı derlemelere neden olabileceği için kabul edilmez.
SkyFunction
uygulamaları, verilere bağımlılık isteğinde bulunmaktan (ör. dosya sistemini doğrudan okuyarak) başka bir şekilde erişmemelidir. Aksi takdirde Bazel, veri bağımlılığını okunan dosyaya kaydetmez ve bu da yanlış artımlı derlemelere neden olur.
Bir işlev, görevini yapacak kadar veriye sahip olduğunda, tamamlanmayı belirten null
olmayan bir değer döndürmelidir.
Bu değerlendirme stratejisinin çeşitli avantajları vardır:
- Hermetiklik. İşlevler yalnızca diğer düğümlere bağlı olarak giriş verileri istiyorsa Bazel, giriş durumu aynıysa aynı verilerin döndürüleceğini garanti edebilir. Tüm sky işlevleri deterministikse derlemenin tamamı da deterministik olur.
- Doğru ve mükemmel artımlılık. Tüm işlevlerin tüm giriş verileri kaydedilirse Bazel, giriş verileri değiştiğinde yalnızca geçersiz kılınması gereken düğüm kümesini geçersiz kılar.
- Paralellik. İşlevler yalnızca bağımlılık isteğinde bulunarak birbirleriyle etkileşim kurabileceğinden, birbirine bağlı olmayan işlevler paralel olarak çalıştırılabilir ve Bazel, sonucun sırayla çalıştırılmış işlevlerle aynı 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 yeniden oluşturmak için kullanabilir: değiştirilen giriş dosyası grubunun ters geçişli kapatması.
Özellikle, iki olası artımlı strateji vardır: aşağıdan yukarıya ve yukarıdan aşağıya. Hangisinin en uygun olduğu, bağımlılıklar grafiğinin nasıl göründüğüne bağlıdır.
Aşağıdan yukarıya doğru geçersiz kılma işlemi sırasında, bir graf oluşturulduktan ve değiştirilen girişler belirlendikten 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ı biliyorsanız bu en uygun seçenektir. Aşağıdan yukarı doğru geçersiz kılma işleminde, önceki derlemenin tüm giriş dosyalarında
stat()
'ün çalıştırılarak değiştirilip değiştirilmediğinin belirlenmesi gerektiğini unutmayın. Değişen dosyalar hakkında bilgi edinmek içininotify
veya benzer bir mekanizma kullanılarak bu durum iyileştirilebilir.Yukarıdan aşağı doğru geçersiz kılma sırasında, üst düzey düğümün geçişli kapatması kontrol edilir ve yalnızca geçişli kapatması temiz olan düğümler tutulur. Mevcut düğüm grafiğinin büyük olduğunu biliyoruz ancak sonraki derlemede yalnızca küçük bir alt kümesine ihtiyacımız varsa bu yöntem daha iyidir: Aşağıdan yukarı doğru geçersiz kılma, yalnızca ikinci derlemenin küçük grafiğini gezen yukarıdan aşağı doğru geçersiz kılma işleminin aksine, ilk derlemenin daha büyük grafiğini geçersiz kılar.
Şu anda yalnızca aşağıdan yukarı doğru geçersiz kılma işlemi yapıyoruz.
Daha fazla artımlılık elde etmek için değişiklik budamasını kullanırız: Bir düğüm geçersiz kılınırsa ancak yeniden oluşturulduktan sonra yeni değerinin eski değeriyle aynı olduğu anlaşılırsa bu düğümdeki bir değişiklik nedeniyle geçersiz kılınan düğümler "yeniden canlandırılır".
Örneğin, bir C++ dosyasındaki yorum değiştirilirse bu özellik faydalıdır: Bu durumda, bu dosyadan oluşturulan .o
dosyası aynı olur ve bu nedenle 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 "ya hep ya hiç" şeklinde olmasıdır: Bir bağımlılık değiştiğinde, düğümün eski değerini değişikliklere göre değiştirecek daha iyi bir algoritma olsa bile bağımlı düğüm her zaman sıfırdan yeniden oluşturulur. Bunun yararlı olacağı birkaç örnek:
- Artımlı bağlantı
- Bir
.jar
'da tek bir.class
dosyası değiştiğinde, teorik olarak.jar
dosyasını sıfırdan yeniden oluşturmak yerine değiştirebiliriz.
Bazel'in şu anda bu özellikleri temelli bir şekilde desteklememesinin (artımlı bağlantı için bir miktar desteğimiz olsa da Skyframe'da uygulanmıyor) iki nedeni vardır: Yalnızca sınırlı performans kazançları elde ettik ve mutasyonun sonucunun temiz bir yeniden derlemenin sonucuyla aynı olacağını garanti etmek zordu. Ayrıca Google, bit bit tekrarlanabilir derlemeleri önemser.
Şimdiye kadar, pahalı bir derleme adımını basitçe parçalayarak ve bu şekilde kısmi yeniden değerlendirme yaparak her zaman yeterince iyi performans elde edebiliyorduk: Bu yöntem, uygulamadaki tüm sınıfları birden fazla gruba ayırır ve bunları ayrı ayrı dizine ekler. Bu sayede, bir gruptaki sınıflar değişmezse dizin oluşturma işleminin yeniden yapılması gerekmez.
Bazel kavramlarıyla eşleme
Aşağıda, Bazel'in derleme yapmak için kullandığı SkyFunction
uygulamalarından bazılarına genel bir bakış verilmiştir:
- FileStateValue. Bir
lstat()
sonucu. Mevcut dosyalar için dosyada yapılan değişiklikleri tespit etmek amacıyla ek bilgiler de hesaplanır. Bu, Skyframe grafiğindeki en alt düzey düğümdür ve bağımlılığı yoktur. - FileValue. Bir dosyanın gerçek içeriği ve/veya çözümlenmiş yolu ile ilgilenen her şey tarafından kullanılır. İlgili
FileStateValue
'e ve çözülmesi gereken tüm sembolik bağlantılara bağlıdır (örneğin,a/b
içinFileValue
,a
'in vea/b
'nin çözüldüğü yoluna ihtiyaç duyar). Bazı durumlarda (örneğin, dosya sistemi glob'larını (srcs=glob(["*/*.java"])
gibi) değerlendirme) dosyanın içeriğine gerçekten ihtiyaç duyulmadığı içinFileStateValue
arasındaki ayrım önemlidir. - DirectoryListingValue. Temel olarak
readdir()
sonucudur. Dizinle ilişkiliFileValue
öğesine bağlıdır. - PackageValue. Bir BUILD dosyasının ayrıştırılmış sürümünü temsil eder. İlişkili
BUILD
dosyasınınFileValue
değerine ve ayrıca paketteki glob'leri (BUILD
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. Yapılandırılmış hedef, bir hedefin analizi sırasında oluşturulan işlemler grubunun ve yapılandırılmış hedeflere sağlanan, bu hedefe bağlı bilgilerin bir tuple'sidir. İlgili hedefin bulunduğu
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. Kaynak veya çıkış yapıları (yapılar neredeyse dosyalarla eşdeğerdir ve derleme adımlarının gerçekte yürütülmesi sırasında dosyalara referans vermek için kullanılır) olsun, derlemedeki bir dosyayı temsil eder. Kaynak dosyalar için ilişkili düğümün
FileValue
değerine, çıkış yapıları için ise yapıyı 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
değerine bağlıdır. Şu anda yürüttüğü işlem, gökyüzü anahtarında yer alıyor. Bu durum, gökyüzü anahtarlarının küçük olması gerektiği fikrine aykırıdır. Bu tutarsızlığı çözmek için çalışıyoruz (Skyframe'da yürütme aşamasını çalıştırmazsakActionExecutionValue
veArtifactValue
'un kullanılmadığını unutmayın).