Ürün Haberleri

%18 Daha Hızlı Derleme, %0 Ödün

Okuma süresi: 8 dk.

Android Çalışma Zamanı (ART) ekibi, derlenen koddan veya bellek gerilemelerinden ödün vermeden derleme süresini% 18 azalttı. Bu iyileştirme, bellek kullanımından veya derlenen kodun kalitesinden ödün vermeden derleme süresini iyileştirmeye yönelik 2025 girişimimizin bir parçasıydı.

Derleme süresi hızını optimize etmek ART için çok önemlidir. Örneğin, JIT derleme sırasında uygulamaların verimliliğini ve genel cihaz performansını doğrudan etkiler. Daha hızlı derleme, optimizasyonların devreye girmesinden önceki süreyi kısaltarak daha sorunsuz ve daha duyarlı bir kullanıcı deneyimi sağlar. Ayrıca hem JIT hem de AOT için derleme süresi hızındaki iyileştirmeler, derleme işlemi sırasında kaynak tüketiminin azalmasını sağlar. Bu da özellikle alt segment cihazlarda pil ömrü ve cihaz sıcaklığı açısından faydalıdır.

Derleme süresiyle ilgili bu hız iyileştirmelerinden bazıları Haziran 2025 Android sürümünde kullanıma sunuldu. Diğerleri ise yıl sonunda yayınlanacak Android sürümünde kullanıma sunulacak. Ayrıca, Android 12 ve sonraki sürümleri kullanan tüm Android kullanıcıları, Mainline güncellemeleri aracılığıyla bu iyileştirmeleri alabilir.

Optimizasyon derleyicisini optimize etme

Derleyici optimizasyonu her zaman ödün vermeyi gerektirir. Hızı bedavaya elde edemezsiniz, bir şeylerden vazgeçmeniz gerekir. Kendimiz için çok net ve zorlu bir hedef belirledik: Derleyiciyi daha hızlı hale getirmek ancak bunu bellek gerilemeleri olmadan ve en önemlisi, ürettiği kodun kalitesini düşürmeden yapmak. Derleyici daha hızlı olmasına rağmen uygulamalar daha yavaş çalışıyorsa başarısız olmuşuz demektir.

Bu katı kriterleri karşılayan akıllı çözümler bulmak için derinlemesine araştırma yapmaya ve kendi geliştirme süremizi harcamaya hazırdık. İyileştirme alanlarını belirlemek ve çeşitli sorunlara doğru çözümler bulmak için nasıl çalıştığımıza daha yakından bakalım.

Değerli olabilecek optimizasyonları bulma

Bir metriği optimize etmeye başlamadan önce onu ölçebilmeniz gerekir. Aksi takdirde, iyileştirme yapıp yapmadığınızdan asla emin olamazsınız. Neyse ki derleme süresi hızı, bir değişiklikten önce ve sonra ölçüm yapmak için kullandığınız cihazı kullanmak ve cihazınızın termal kısıtlama yapmadığından emin olmak gibi bazı önlemler aldığınız sürece oldukça tutarlıdır. Bunun yanı sıra, arka planda neler olup bittiğini anlamamıza yardımcı olan derleyici istatistikleri gibi deterministik ölçümlerimiz de var.

 

Bu iyileştirmeler için feda ettiğimiz kaynak geliştirme süremiz olduğundan, mümkün olduğunca hızlı bir şekilde yineleme yapabilmek istedik. Bu, çözümlerin prototipini oluşturmak için temsili birkaç uygulama (birinci taraf uygulamaları, üçüncü taraf uygulamaları ve Android işletim sisteminin kendisi) seçtiğimiz anlamına geliyordu. Daha sonra, hem manuel hem de otomatik testleri yaygın bir şekilde kullanarak nihai uygulamanın buna değdiğini doğruladık.

 

Özenle seçilmiş bu APK'larla yerel olarak manuel derleme tetikler, derlemenin profilini alır ve zamanımızı nerede harcadığımızı görselleştirmek için pprof'u kullanırız.

image.png

pprof'ta bir profilin alev grafiği örneği

pprof aracı çok güçlüdür ve verileri dilimlememize, filtrelememize ve sıralamamıza olanak tanır. Böylece, örneğin hangi derleyici aşamalarının veya yöntemlerinin en çok zaman aldığını görebiliriz. pprof'un kendisi hakkında ayrıntılı bilgi vermeyeceğiz. Sadece çubuğun daha büyük olmasının, derlemenin daha uzun sürdüğü anlamına geldiğini bilmeniz yeterlidir.

Bu görünümlerden biri, en çok zaman alan yöntemleri görebileceğiniz "aşağıdan yukarıya" görünümüdür. Aşağıdaki resimde, derleme süresinin% 1'inden fazlasını oluşturan Kill adlı bir yöntem çağrısı görebilirsiniz. Diğer en iyi yöntemlerden bazıları da blog yayınında daha sonra ele alınacaktır.

image.png

Profilin aşağıdan yukarıya görünümü

Optimizasyon derleyicimizde Global Value Numbering (GVN) adlı bir aşama vardır. Kodun tamamının ne yaptığını bilmeniz gerekmez. Önemli olan, kodun `Kill` adlı bir yöntemi olduğunu ve bu yöntemin bir filtreye göre bazı düğümleri sileceğini bilmektir. Tüm düğümleri tek tek kontrol etmesi gerektiğinden bu işlem zaman alır. Bazı durumlarda, o anda etkin olan düğümlerden bağımsız olarak kontrolün yanlış olacağını önceden bildiğimizi fark ettik. Bu gibi durumlarda, yinelemeyi tamamen atlayarak %1,023'ten yaklaşık% 0,3'e düşürebilir ve GVN'nin çalışma süresini yaklaşık %15 oranında iyileştirebiliriz.

Değerli optimizasyonlar uygulama

Zamanın nerede harcandığını nasıl ölçeceğinizi ve tespit edeceğinizi ele aldık ancak bu sadece başlangıç. Bir sonraki adım, derleme için harcanan zamanı optimize etmektir.

Genellikle yukarıdaki "Kill" örneğinde olduğu gibi, düğümler arasında nasıl yineleme yaptığımıza bakar ve işlemleri paralel olarak gerçekleştirerek veya algoritmayı iyileştirerek daha hızlı yaparız. Aslında ilk başta bunu denedik ve yapacak bir şey bulamadığımızda "Bir dakika..." dedik ve çözümün (bazı durumlarda) hiç yineleme yapmamak olduğunu gördük. Bu tür optimizasyonlar yaparken ayrıntılara odaklanıp büyük resmi gözden kaçırmak kolaydır.

Diğer durumlarda ise aşağıdakiler de dahil olmak üzere birkaç farklı teknik kullandık:

  • Bir optimizasyonun kayda değer sonuçlar üretmeyeceğine ve bu nedenle atlanabileceğine karar vermek için sezgisel yöntemler kullanma
  • Hesaplanan verileri önbelleğe almak için ek veri yapıları kullanma
  • Hız Bonusu elde etmek için mevcut veri yapılarını değiştirme
  • Bazı durumlarda döngüleri önlemek için sonuçları geç hesaplama
  • Doğru soyutlamayı kullanın. Gereksiz özellikler kodu yavaşlatabilir.
  • Sık kullanılan bir işaretçiyi birçok yükleme boyunca takip etmekten kaçınma

Optimizasyonların uygulamaya değer olup olmadığını nasıl anlarız?

İşin güzel tarafı da bu, yapmanıza gerek yok. Bir alanın çok fazla derleme süresi tükettiğini tespit ettikten ve bu süreyi iyileştirmeye çalışmak için geliştirme süresi ayırdıktan sonra bazen çözüm bulamayabilirsiniz. Belki de yapılacak bir şey yoktur, uygulanması çok uzun sürecektir, başka bir metriği önemli ölçüde geriletecektir, kod tabanı karmaşıklığını artıracaktır vb. Bu blog yayınında görebileceğiniz her başarılı optimizasyon için, sonuç vermeyen sayısız başka optimizasyon olduğunu bilin.

Benzer bir durumdaysanız mümkün olduğunca az iş yaparak metriği ne kadar iyileştireceğinizi tahmin etmeye çalışın. Bu, sırasıyla şu anlama gelir:

  1. Daha önce topladığınız metrikleri kullanarak veya sadece içgüdülerinize dayanarak tahmin yürütme
  2. Hızlı ve basit bir prototiple tahmin yapma
  3. Çözüm uygulama

Çözümünüzün dezavantajlarını tahmin etmeyi unutmayın. Örneğin, ek veri yapıları kullanacaksanız ne kadar bellek kullanmaya hazırsınız?

Daha ayrıntılı bilgi

Lafı daha fazla uzatmadan, yaptığımız değişikliklerden bazılarına göz atalım.

FindReferenceInfoOf adlı yöntemi optimize etmek için bir değişiklik yaptık. Bu yöntem, bir girişi bulmak için vektörde doğrusal arama yapıyordu. Bu veri yapısını, talimatın kimliğine göre dizine eklenecek şekilde güncelledik. Böylece FindReferenceInfoOf, O(n) yerine O(1) olur. Ayrıca, yeniden boyutlandırmayı önlemek için vektörü önceden tahsis ettik. Vektöre kaç giriş eklediğimizi sayan fazladan bir alan eklememiz gerektiğinden bellek kullanımını biraz artırdık. Ancak en yüksek bellek kullanımı artmadığı için bu küçük bir fedakarlıktı. Bu sayede LoadStoreAnalysis aşamamız% 34-66 oranında hızlandı. Bu da derleme süresinde yaklaşık% 0,5-1,8 oranında iyileşme sağladı.

Birçok yerde kullandığımız özel bir HashSet uygulamamız var. Bu veri yapısını oluşturmak çok zaman alıyordu ve bunun nedenini bulduk. Yıllar önce bu veri yapısı, yalnızca çok büyük HashSet'lerin kullanıldığı birkaç yerde kullanılıyordu ve buna göre optimize edilecek şekilde ayarlanmıştı. Ancak günümüzde, yalnızca birkaç girişle ve kısa bir kullanım ömrüyle ters yönde kullanılıyordu. Bu, devasa bir HashSet oluşturarak döngüleri boşa harcadığımız ancak bunu yalnızca birkaç giriş için kullanıp attığımız anlamına geliyordu. Bu değişiklikle derleme süresini yaklaşık% 1,3-2 oranında iyileştirdik. Ayrıca, eskisi kadar büyük veri yapıları kullanmadığımız için bellek kullanımı yaklaşık% 0,5-1 oranında azaldı.

Veri yapılarını kopyalamaktan kaçınmak için lambda'ya referans olarak ileterek derleme süresini yaklaşık% 0,5-1 oranında iyileştirdik. Bu, ilk incelemede gözden kaçan ve yıllarca kod tabanımızda kalan bir sorundu. pprof'taki profillere göz attığımızda bu yöntemlerin çok sayıda veri yapısı oluşturup yok ettiğini fark ettik. Bu sayede, bu yöntemleri inceleyip optimize edebildik.

Hesaplanan değerleri önbelleğe alarak derlenen çıkışı yazma aşamasını hızlandırdık. Bu da toplam derleme süresinde yaklaşık% 1,3-2,8 oranında iyileşme sağladı. Maalesef ek kayıt tutma işlemi çok fazlaydı ve otomatik testlerimiz bizi bellek gerilemesi konusunda uyardı. Daha sonra aynı koda tekrar göz attık ve yalnızca bellek gerilemesini düzeltmekle kalmayıp derleme süresini de yaklaşık %0,5-1,8 oranında iyileştiren yeni bir sürüm uyguladık. Bu ikinci değişiklikte, iki veri yapısından birini ortadan kaldırmak için bu aşamanın nasıl çalışması gerektiğini yeniden düzenlememiz ve yeniden tasarlamamız gerekti.

Optimizasyon derleyicimizde, daha iyi performans elde etmek için işlev çağrılarını satır içine alan bir aşama vardır. Satır içi yapılacak yöntemleri seçmek için hem hesaplama yapmadan önce buluşsal yöntemleri hem de çalışmayı yaptıktan sonra ancak satır içi işlemi tamamlamadan hemen önce son kontrolleri kullanırız. Bunlardan herhangi biri satır içi işleminin değmeyeceğini tespit ederse (örneğin, çok fazla yeni talimat eklenirse) yöntem çağrısını satır içi yapmayız.

Zaman alan hesaplamalar yapmadan önce satır içi işleminin başarılı olup olmayacağını tahmin etmek için iki kontrolü "son kontroller" kategorisinden "sezgisel" kategorisine taşıdık. Bu bir tahmin olduğu için mükemmel değildir ancak yeni buluşsal yöntemlerimizin, performansı etkilemeden daha önce satır içi olanların% 99,9'unu kapsadığını doğruladık. Bu yeni sezgisel yöntemlerden biri gerekli DEX kayıtları (~% 0,2-1,3 iyileştirme), diğeri ise talimat sayısı (~% 2 iyileştirme) ile ilgiliydi.

Birkaç yerde kullandığımız özel bir BitVector uygulamamız var. Belirli sabit boyutlu bit vektörleri için yeniden boyutlandırılabilir BitVector sınıfını daha basit bir BitVectorView ile değiştirdik. Bu sayede bazı dolaylı işlemler ve çalışma zamanı aralık kontrolleri ortadan kalkar ve bit vektörü nesnelerinin oluşturulması hızlanır.

Ayrıca BitVectorView sınıfı, temel depolama türünde şablonlaştırıldı (eski BitVector gibi her zaman uint32_t kullanmak yerine). Bu sayede, Union() gibi bazı işlemler 64 bit platformlarda iki kat daha fazla biti birlikte işleyebilir. Android OS derlenirken etkilenen işlevlerin örnekleri toplamda% 1'den fazla azaltıldı. Bu işlem birkaç değişiklik yapılarak gerçekleştirildi [1, 2, 3, 4, 5, 6]

Tüm optimizasyonlardan ayrıntılı olarak bahsetmeye kalkarsak bütün günümüzü alır. Daha fazla optimizasyonla ilgileniyorsanız uyguladığımız diğer değişikliklere göz atın:

Sonuç

ART'ın derleme süresi hızını artırma konusundaki kararlılığımız, önemli iyileştirmeler sağladı. Bu sayede Android daha akıcı ve verimli hale gelirken pil ömrü ve cihaz sıcaklığı da iyileşti. Optimizasyonları titizlikle belirleyip uygulayarak bellek kullanımından veya kod kalitesinden ödün vermeden derleme süresinde önemli kazanımlar elde etmenin mümkün olduğunu gösterdik.

Bu süreçte pprof gibi araçlarla profil oluşturma, yineleme yapma ve bazen daha az verimli yolları terk etme gibi yöntemler kullandık. ART ekibinin ortak çalışmaları, derleme süresini kayda değer bir oranda azaltmakla kalmadı, aynı zamanda gelecekteki gelişmelerin de temelini attı.

Tüm bu iyileştirmeler, 2025 yıl sonu Android güncellemesinde ve ana hat güncellemeleri aracılığıyla Android 12 ve sonraki sürümlerde kullanılabilir. Optimizasyon sürecimizi ayrıntılı bir şekilde ele aldığımız bu yazının, derleyici mühendisliğinin karmaşıklığı ve avantajları hakkında değerli bilgiler sağladığını umuyoruz.

Okumaya devam et