Ü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ı derlemeler, 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 önceden (AOT) derleme süresi hızındaki iyileştirmeler, derleme işlemi sırasında kaynak tüketiminin azalmasını sağlayarak özellikle alt segment cihazlarda pil ömrüne ve cihazın ısınmasına olumlu katkıda bulunur.

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ı bu iyileştirmeleri Mainline güncellemeleri aracılığıyla alabilir.

Optimizasyon derleyicisini optimize etme

Derleyici optimizasyonu her zaman ödün vermeyi gerektirir. Hızı bedavaya elde edemezsiniz. Bir şeylerden vazgeçmeniz gerekir. Kendimize ç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 yapmak ve incelemek üzere 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 bir değişiklikten önce ve sonra ölçüm yapmak için aynı cihazı kullanmak ve cihazınızın termal kısıtlama yapmadığından emin olmak gibi bazı önlemler aldığınız sürece derleme süresi hızı oldukça tutarlıdır. Ayrıca, 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 yapmak istedik. Bu, çözümlerin prototipini oluşturmak için birkaç temsili 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 testlerle 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 ayrıntılarına girmeyeceğiz. Ç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örüyoruz. 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. Bu kodun tamamının ne yaptığını bilmeniz gerekmez. Ancak ilgili bölüm, bir filtreye göre bazı düğümleri silen `Kill` adlı bir yöntemi olduğunu bilmektir. Bu işlem, tüm düğümleri tek tek kontrol etmesi gerektiğinden 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ın nasıl optimize edileceğidir.

Genellikle yukarıdaki "Kill" örneğinde olduğu gibi, düğümler arasında nasıl yineleme yaptığımıza bakar ve bunu daha hızlı bir şekilde yaparız. Örneğin, işlemleri paralel olarak yapar veya algoritmanın kendisini iyileştiririz. 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ütünü gözden kaçırmak kolaydır.

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

  • Optimizasyonun değerli sonuçlar üretip üretmeyeceğine ve bu nedenle atlanıp atlanamayacağına 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ı, buna gerek yok. Bir alanın çok fazla derleme süresi tükettiğini tespit ettikten ve bu süreyi iyileştirmek 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 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 metriklerle veya sadece içgüdülerinize dayanarak tahmin yapma
  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 kullanmak istersiniz?

Daha ayrıntılı bilgi

Şimdi, 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 öğrendik. 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ı kopyalamamak 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 yapıları inceleyip optimize edebildik.

Hesaplanan değerleri önbelleğe alarak derlenen çıkışı yazan aşamayı 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 bellek gerilemesi konusunda bizi 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ğundan mükemmel değildir ancak yeni sezgisel yöntemlerimizin, performansı etkilemeden daha önce satır içi olarak eklenenlerin% 99,9'unu kapsadığını doğruladık. Bu yeni buluşsal 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. Yeniden boyutlandırılabilir BitVector sınıfını, belirli sabit boyutlu bit vektörleri için daha basit bir BitVectorView ile değiştirdik. Bu sayede bazı dolaylı işlemler ve çalışma zamanı aralığı 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 [1, 2, 3, 4, 5, 6] ile yapıldı.

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 önemli ölçüde 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