Çerçeve

Bazel'in paralel değerlendirme ve artımlılık modeli.

Veri modeli

Veri modeli aşağıdaki öğelerden oluşur:

  • SkyValue. Düğüm olarak da adlandırılır. SkyValues, derleme boyunca oluşturulan tüm verileri ve derlemenin girişlerini içeren sabit nesnelerdir. Örnekler: giriş dosyaları, çıkış dosyaları, hedefler ve yapılandırılmış hedefler.
  • SkyKey. SkyValue öğesine referans veren kısa ve sabit bir addır; örneğin, FILECONTENTS:/tmp/foo veya PACKAGE://foo.
  • SkyFunction. Anahtarlarına ve bağımlı düğümlere göre düğüm 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 artımlı değerlendirme çerçevesinin kod adını temel alır.

Değerlendirme

Derleme, derleme isteğini temsil eden düğümün değerlendirilmesinden oluşur (Bu, ulaşmak istediğimiz durumtur ancak çok fazla eski kod vardır). Öncelikle SkyFunction bulunur ve üst düzey SkyKey anahtarıyla çağrılır. İşlev daha sonra, üst düzey düğümü değerlendirmek için ihtiyaç duyduğu düğümlerin değerlendirilmesini ister. Bu durum, yaprak düğümlerine (genellikle dosya sistemindeki giriş dosyalarını temsil eden düğümler) ulaşana kadar diğer işlev çağrılarına yol açar. Son olarak, üst düzey SkyValue değerini, bazı yan etkileri (dosya sistemindeki çıkış dosyaları gibi) ve derlemede yer alan düğümler arasındaki bağımlılıkların yönlendirilmiş dairesel bir grafiğini elde ederiz.

Bir SkyFunction, işini yapması için ihtiyacı olan tüm düğümleri önceden belirleyemezse birden fazla geçişte SkyKeys isteğinde bulunabilir. Basit bir örnek, sembolik bağlantı olan bir giriş dosyası düğümünü değerlendirmektir: İşlev dosyayı okumaya çalışır, bunun bir 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 kendisi bir sembolik bağlantı olabilir. Bu durumda, orijinal işlevin hedefini de getirmesi gerekir.

İşlevler kodda SkyFunction arayüzü ve ona sağlanan hizmetler SkyFunction.Environment adlı arayüzle temsil edilir. İşlevlerin yapabileceği işlemler şunlardır:

  • env.getValue yöntemini çağırarak başka bir düğümün değerlendirilmesini isteyin. Düğüm kullanılabilir durumdaysa değeri döndürülür. Aksi takdirde, null döndürülür ve işlevin kendisinin de null 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 aynı env.getValue çağrısı bu kez null olmayan bir değer döndürür.
  • env.getValues() yöntemini çağırarak diğer birden fazla düğümün değerlendirilmesini isteyin. Bağımlı düğümler paralel olarak değerlendirilir ancak bu yöntem temelde aynıdır.
  • Çağrıları sırasında hesaplama yapabilirler
  • Dosyaların, dosya sistemine yazılması gibi yan etkileri olabilir. İki farklı işlevin birbirinin ayağına basmamasına dikkat edilmesi gerekir. Genel olarak, yan etkileri yazmak (Bazel'den dışarı doğru veri akışı olduğunda) sorun yoktur. Yan etkileri okuma (verilerin kayıtlı bir bağımlılık olmadan Bazel'e doğru aktığı durum) kabul edilmez. Çünkü bunlar kaydedilmemiş bir bağımlılıktır ve dolayısıyla hatalı artımlı derlemelere neden olabilir.

SkyFunction uygulamaları, verilere bağımlılık istemek dışında (örneğin, dosya sistemini doğrudan okuyarak) erişmemelidir. Bu durum Bazel'in okunan dosyaya veri bağımlılığını kaydetmemesine ve dolayısıyla hatalı ek derlemelere yol açar.

Bir işlev işini yapmak için yeterli veriye sahip olduğunda, tamamlanma durumunu 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ı olduğunda aynı verilerin döndürüleceğini garanti edebilir. Gökyüzü işlevlerinin tümü deterministikse bu, yapının tamamının da deterministik olacağı anlamına gelir.
  • Artımlılık doğru ve mükemmeldir. Tüm işlevlerin tüm giriş verileri kaydedilirse, Bazel yalnızca giriş verileri değiştiğinde geçersiz kılınması gereken düğüm grubunu geçersiz kılabilir.
  • Paralellik. İşlevler yalnızca bağımlılık isteğinde bulunarak birbirleriyle etkileşim kurabildiğinden, birbirine bağımlı olmayan işlevler paralel olarak çalıştırılabilir ve Bazel, sonucun sıralı çalıştırılmış gibi sonuçlarla aynı olacağını garanti edebilir.

Artımlılık

İşlevler, giriş verilerine yalnızca diğer düğümlere bağlı olarak erişebildiğinden, Bazel giriş dosyalarından çıkış dosyalarına doğru 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ş dosyaları grubunun ters geçişli kapanması.

Özellikle, iki olası artımlılık stratejisi vardır: aşağıdan yukarıya ve yukarıdan aşağıya. Hangi seçeneğin 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 işlemi sırasında, bir grafik oluşturulduktan ve değiştirilen giriş kümesi bilindikten sonra, değiştirilen dosyalara bağlı olan tüm düğümler geçersiz kılınır. Aynı üst düzey düğümün tekrar derleneceğini biliyorsak bu optimum olur. Aşağıdan yukarıya geçersiz kılma işleminin, değiştirilip değiştirilmediğini belirlemek için önceki derlemenin tüm giriş dosyalarında stat() çalıştırmasını gerektirdiğini unutmayın. Değiştirilen dosyalar hakkında bilgi edinmek için inotify veya benzer bir mekanizma kullanılarak bu iyileştirme iyileştirilebilir.

  • Yukarıdan aşağıya geçersiz kılma işlemi sırasında, üst düzey düğümün geçişli kapanması kontrol edilir ve yalnızca geçişli kapanışı temiz olan düğümler tutulur. Mevcut düğüm grafiğinin büyük olduğunu bilirsek daha iyi olur, ancak bir sonraki derlemede bunun yalnızca küçük bir alt kümesine ihtiyacımız olur: Aşağıdan yukarıya geçersiz kılma, ikinci derlemenin küçük grafiğini gösteren yukarıdan aşağıya geçersiz kılmanın aksine, 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 gerçekleştiriyoruz.

Daha fazla artımlılık elde etmek için değişiklik ayıklama yöntemini 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 keşfedilirse bu düğümdeki bir değişiklik nedeniyle geçersiz kılınan düğümler "yeniden dikilir".

Bu, örneğin bir kullanıcının C++ dosyasındaki bir yorumu değiştirmesi durumunda yararlı olur: Bu durumda ondan oluşturulan .o dosyası aynı olur. Dolayısıyla, bağlayıcıyı tekrar çağırmamız gerekmez.

Artımlı Bağlama / Derleme

Bu modelin ana sınırlaması, bir düğümün geçersiz kılınmasının ya hep ya hiç sorunu olmasıdır: Bir bağımlılık değiştiğinde, bağımlı düğüm her zaman en baştan yeniden oluşturulur. Bu, değişikliklere göre düğümün eski değerini değiştirecek daha iyi bir algoritma olsa bile geçerlidir. Yararlı olabilecek birkaç örnek:

  • Artımlı bağlantı
  • Bir .jar dosyasında tek bir .class dosyası değiştiğinde, .jar dosyasını tekrar sıfırdan oluşturmak yerine teorik olarak değiştirebiliriz.

Bazel'in şu anda bunları ilkesel bir şekilde desteklememesinin (artan bağlantı desteği için bazı ölçümlerimiz var, ancak Skyframe'de uygulanmamasının) iki neden vardı: Performansta yalnızca sınırlı düzeyde artış elde ettik ve değişimin, temiz bir yeniden oluşturma sonucuyla aynı olacağını garanti etmek zordu ve Google değerleri, bit-bit tekrarlanabilir derlemeler geliştirdi.

Şimdiye kadar, pahalı bir derleme adımını parçalara ayırıp ve kısmi yeniden değerlendirmeyi yaparak her zaman yeterince iyi bir performans elde edebiliyorduk. Bu yöntem, bir uygulamadaki tüm sınıfları birden çok gruba ayırıyor ve ayrı ayrı dexing yapıyor. Bu sayede, bir gruptaki sınıflar değişmezse dexing işleminin yeniden yapılması gerekmez.

Bazel kavramlarıyla eşleştirme

Burada, Bazel'ın bir derleme gerçekleştirmek için kullandığı bazı SkyFunction uygulamalarından kabaca bir genel bakış verilmiştir:

  • FileStateValue değerini girin. lstat() işleminin sonucu. Mevcut dosyalar için, dosyadaki değişiklikleri tespit etmek amacıyla ek bilgileri de hesaplarız. Bu, Skyframe grafiğindeki en düşük seviyedeki düğümdür ve herhangi bir bağımlılığı yoktur.
  • FileValue değeridir. Dosyanın gerçek içeriğini ve/veya çözülmüş yolunu dikkate alan öğeler tarafından kullanılır. Karşılık gelen FileStateValue öğesine ve çözülmesi gereken sembolik bağlantılara bağlıdır (örneğin, a/b için FileValue, a öğesinin çözümlenen yolunu ve a/b yolunun çözümlenmiş yolunu gerektirir). FileStateValue arasındaki ayrım, bazı durumlarda (örneğin, srcs=glob(["*/*.java"]) gibi dosya sistemi glob'larının değerlendirilmesi) dosya içeriğinin gerçekten gerekli olmamasından dolayı önemlidir.
  • DirectoryListingValue (Dizin Listesi Adı) ile belirtilir. Esasen readdir() işlevinin sonucu. Dizinle ilişkili ilişkili FileValue öğesine bağlıdır.
  • PackageValue. BUILD dosyasının ayrıştırılmış sürümünü gösterir. İlişkili BUILD dosyasının FileValue öğesine ve paketteki glob'ları çözümlemek için kullanılan DirectoryListingValue öğesine (BUILD dosyasının içeriğini dahili olarak temsil eden veri yapısı) geçişli olarak bağlıdır.
  • ConfiguredTargetValue değerleridir. Yapılandırılmış bir hedefi temsil eder. Bu, bir hedefin analizi sırasında oluşturulan işlem grubunun ve buna bağlı yapılandırılmış hedeflere sağlanan bilgilerin bir unsurudur. Karşılık gelen hedefin bulunduğu PackageValue, doğrudan bağımlılıkların ConfiguredTargetValues ve derleme yapılandırmasını temsil eden özel bir düğüme bağlıdır.
  • ArtifactValue. Kaynak veya çıkış yapıları olsun, derlemedeki bir dosyayı temsil eder (yapılar neredeyse dosyalara eşittir ve derleme adımlarının yürütülmesi sırasında dosyalara referans vermek için kullanılır). Kaynak dosyalarda bu, ilişkili düğümün FileValue değerine, çıkış yapıları içinse yapıyı oluşturan işlemin ActionExecutionValue öğesine bağlıdır.
  • ActionExecutionValue değerini alır. Bir işlemin yürütülmesini temsil eder. Giriş dosyalarının ArtifactValues öğesine bağlıdır. Yürüttüğü işlem şu anda gökyüzü anahtarının içinde yer alıyor. Bu, gökyüzü tuşlarının küçük olması gerektiği fikrine aykırıdır. Bu tutarsızlığı çözmeye çalışıyoruz (Skyframe'de yürütme aşamasını çalıştırmazsak ActionExecutionValue ve ArtifactValue değerlerinin kullanılmayacağını unutmayın).