Bu dokümanda, sorunları teşhis etmenize ve temel profillerinizin en iyi şekilde fayda sağlayabilmesi için düzgün çalışmasını sağlamanıza yardımcı olacak en iyi uygulamalar gösterilmektedir.
Derleme sorunları
Android'de örnek uygulamasındaki referans profil örneğini kopyaladıysanız referans profil görevi sırasında testlerin bir emülatörde çalıştırılamayacağını belirten test hatalarıyla karşılaşabilirsiniz:
./gradlew assembleDemoRelease
Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no configuration cache is available for tasks: assembleDemoRelease
Type-safe project accessors is an incubating feature.
> Task :benchmarks:pixel6Api33DemoNonMinifiedReleaseAndroidTest
Starting 14 tests on pixel6Api33
com.google.samples.apps.nowinandroid.foryou.ScrollForYouFeedBenchmark > scrollFeedCompilationNone[pixel6Api33] FAILED
java.lang.AssertionError: ERRORS (not suppressed): EMULATOR
WARNINGS (suppressed):
...
Başarısızlıklar, Android'de Şimdi'nin referans profili oluşturmak için Gradle tarafından yönetilen bir cihaz kullanmasından kaynaklanır. Genellikle performans karşılaştırmalarını bir emülatörde çalıştırmayacağınız için bu tür hatalar beklenir. Ancak, temel profil oluştururken performans metrikleri toplamayacağınız için kolaylık sağlamak amacıyla temel profil toplama işlemini emülatörlerde çalıştırabilirsiniz. Temel profilleri bir emülatörle kullanmak için derlemeyi ve yüklemeyi komut satırından gerçekleştirin ve temel profil kurallarını etkinleştirmek için bir bağımsız değişken ayarlayın:
installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
Alternatif olarak, Çalıştır > Yapılandırmaları Düzenle'yi seçerek Android Studio'da özel bir çalıştırma yapılandırması oluşturarak temel profilleri emülatörlerde etkinleştirebilirsiniz:

Yükleme sorunları
İncelediğiniz APK veya AAB'nin, temel profilleri içeren bir derleme varyantından geldiğini kontrol edin:
- Android Studio'da Derle > APK'yı Analiz Et'i seçin.
- AAB'nizi veya APK'nızı açın.
- Bir AAB'yi inceliyorsanız profil
/BUNDLE-METADATA/com.android.tools.build.profiles/baseline.prof
adresindedir. Bir APK'yı inceliyorsanız profil/assets/dexopt/baseline.prof
adresindedir.

Temel profillerin, uygulamanın çalıştığı cihazda derlenmesi gerekir. Uygulamayı Play Store, Android Studio veya Gradle Wrapper komut satırı aracını kullanarak yüklediğinizde cihaz üzerinde derleme otomatik olarak gerçekleşir. Uygulama diğer araçlar kullanılarak yüklendiğinde, sonraki arka plan DEX optimizasyon işlemi sırasında profillerin derleme için sıraya eklenmesi Jetpack ProfileInstaller
kitaplığının sorumluluğundadır. Bu gibi durumlarda, temel profillerinizin kullanılmasını sağlamak istiyorsanız temel profillerin derlenmesini zorlamanız gerekebilir. ProfileVerifier
, aşağıdaki örnekte gösterildiği gibi profil yükleme ve derleme durumunu sorgulamanıza olanak tanır:
Kotlin
private const val TAG = "MainActivity" class MainActivity : ComponentActivity() { ... override fun onResume() { super.onResume() lifecycleScope.launch { logCompilationStatus() } } private suspend fun logCompilationStatus() { withContext(Dispatchers.IO) { val status = ProfileVerifier.getCompilationStatusAsync().await() when (status.profileInstallResultCode) { RESULT_CODE_NO_PROFILE -> Log.d(TAG, "ProfileInstaller: Baseline Profile not found") RESULT_CODE_COMPILED_WITH_PROFILE -> Log.d(TAG, "ProfileInstaller: Compiled with profile") RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> Log.d(TAG, "ProfileInstaller: App was installed through Play store") RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST -> Log.d(TAG, "ProfileInstaller: PackageName not found") RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ -> Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read") RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE -> Log.d(TAG, "ProfileInstaller: Can't write cache file") RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") else -> Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued") } } }
Java
public class MainActivity extends ComponentActivity { private static final String TAG = "MainActivity"; @Override protected void onResume() { super.onResume(); logCompilationStatus(); } private void logCompilationStatus() { ListeningExecutorService service = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor()); ListenableFuture<ProfileVerifier.CompilationStatus> future = ProfileVerifier.getCompilationStatusAsync(); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(CompilationStatus result) { int resultCode = result.getProfileInstallResultCode(); if (resultCode == RESULT_CODE_NO_PROFILE) { Log.d(TAG, "ProfileInstaller: Baseline Profile not found"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE) { Log.d(TAG, "ProfileInstaller: Compiled with profile"); } else if (resultCode == RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING) { Log.d(TAG, "ProfileInstaller: App was installed through Play store"); } else if (resultCode == RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST) { Log.d(TAG, "ProfileInstaller: PackageName not found"); } else if (resultCode == RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ) { Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read"); } else if (resultCode == RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE) { Log.d(TAG, "ProfileInstaller: Can't write cache file"); } else if (resultCode == RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else { Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued"); } } @Override public void onFailure(Throwable t) { Log.d(TAG, "ProfileInstaller: Error getting installation status: " + t.getMessage()); } }, service); } }
Aşağıdaki sonuç kodları, bazı sorunların nedenine dair ipuçları sağlar:
RESULT_CODE_COMPILED_WITH_PROFILE
- Profil yüklenir, derlenir ve uygulama her çalıştırıldığında kullanılır. Bu, görmek istediğiniz sonuçtur.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- Çalışılan APK'da profil bulunamadı. Bu hatayı görüyorsanız temel profiller içeren bir derleme varyantı kullandığınızdan ve APK'nın bir profil içerdiğinden emin olun.
RESULT_CODE_NO_PROFILE
- Uygulama mağazası veya paket yöneticisi üzerinden yüklenirken bu uygulama için profil yüklenmedi. Bu hata kodunun başlıca nedeni,
ProfileInstallerInitializer
devre dışı bırakıldığı için profil yükleyicinin çalışmamasıdır. Bu hata bildirildiğinde uygulama APK'sında hâlâ yerleşik bir profil bulunduğunu unutmayın. Yerleştirilmiş bir profil bulunmadığında döndürülen hata koduRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
'tür. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- APK veya AAB'da bir profil bulunur ve derleme için sıraya eklenir. Bir profil
ProfileInstaller
tarafından yüklendiğinde, sistem tarafından arka planda DEX optimizasyonu çalıştırıldığında derleme için sıraya alınır. Derleme tamamlanana kadar profil etkin olmaz. Derleme tamamlanana kadar referans profillerinizi karşılaştırmaya çalışmayın. Temel profillerin derlenmesini zorlamanız gerekebilir. Derleme işlemi yükleme sırasında yapıldığından, uygulama Android 9 (API 28) ve sonraki sürümleri çalıştıran cihazlarda uygulama mağazasından veya paket yöneticisinden yüklendiğinde bu hata oluşmaz. RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
- Eşleşmeyen bir profil yüklenmiş ve uygulama bu profille derlenmiştir.
Bu, Google Play Store veya paket yöneticisi üzerinden yüklemenin sonucudur.
Eşleşmeyen profil yalnızca profil ile uygulama arasında hâlâ paylaşılan yöntemleri derleyeceğinden bu sonucun
RESULT_CODE_COMPILED_WITH_PROFILE
ile farklı olduğunu unutmayın. Profil, beklenenden daha küçüktür ve referans profilde yer alanlardan daha az yöntem derlenir. RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier
, doğrulama sonucu önbelleği dosyasını yazamıyor. Bu durum, uygulama klasör izinleriyle ilgili bir sorun olduğunda veya cihazda yeterli boş disk alanı olmadığında ortaya çıkabilir.RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
- ProfileVerifier
is running on an unsupported API version of Android. ProfileVerifier
yalnızca Android 9 (API düzeyi 28) ve sonraki sürümleri destekler. RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
- Uygulama paketi için
PackageManager
sorgulanırkenPackageManager.NameNotFoundException
hatası atılır. Bu durum nadiren gerçekleşir. Uygulamayı kaldırıp her şeyi yeniden yüklemeyi deneyin. RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- Önceki bir doğrulama sonucu önbelleği dosyası var ancak okunamıyor. Bu durum nadiren gerçekleşir. Uygulamayı kaldırıp her şeyi yeniden yüklemeyi deneyin.
ProfileVerifier'ı üretimde kullanma
Üretimde, profil durumunu belirten analiz etkinlikleri oluşturmak için ProfileVerifier
'ü Firebase için Google Analytics gibi analiz raporlama kitaplıklarıyla birlikte kullanabilirsiniz. Örneğin, bu özellik, temel profil içermeyen yeni bir uygulama sürümü yayınlandığında sizi hızlı bir şekilde uyarır.
Referans profillerinin derlenmesini zorunlu kılma
Temel profillerinizin derleme durumu RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
ise adb
kullanarak derlemeyi hemen zorlayabilirsiniz:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
ProfileVerifier olmadan derleme durumunu kontrol etme
ProfileVerifier
kullanmıyorsanız adb
'ü kullanarak derleme durumunu kontrol edebilirsiniz. Ancak adb
, ProfileVerifier
kadar ayrıntılı analizler sunmaz:
adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME
adb
kullanıldığında aşağıdakine benzer bir sonuç elde edilir:
[com.google.samples.apps.nowinandroid.demo]
path: /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/base.apk
arm64: [status=speed-profile] [reason=bg-dexopt] [primary-abi]
[location is /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/oat/arm64/base.odex]
Durum değeri, profil derleme durumunu belirtir ve aşağıdaki değerlerden biridir:
Derleme durumu | Anlamı |
---|---|
speed‑profile |
Derlenmiş bir profil mevcut ve kullanılıyor. |
verify |
Derlenmiş profil yok. |
verify
durumu, APK veya AAB'nin profil içermediği anlamına gelmez. Çünkü bir sonraki arka plan DEX optimizasyon görevi tarafından derleme için sıraya alınabilir.
Neden değeri, profilin derlenmesini neyin tetiklediğini belirtir ve aşağıdaki değerlerden biridir:
Neden | Anlamı |
---|---|
install‑dm
|
Temel Profil, uygulama yüklenirken manuel olarak veya Google Play tarafından derlenmiştir. |
bg‑dexopt
|
Cihazınız boştayken bir profil derlendi. Bu, bir referans profili veya uygulama kullanımı sırasında toplanan bir profil olabilir. |
cmdline
|
Derleme, adb kullanılarak tetiklendi. Bu, bir referans profili veya uygulama kullanımı sırasında toplanan bir profil olabilir. |
Performans sorunları
Bu bölümde, temel profillerinizden en iyi şekilde yararlanmak için bunları doğru şekilde tanımlama ve karşılaştırma ile ilgili bazı en iyi uygulamalar gösterilmektedir.
Başlatma metrikleriyle doğru şekilde karşılaştırma yapma
Başlangıç metrikleriniz iyi tanımlanmışsa referans profilleriniz daha etkili olur. İki temel metrik ilk ekrana görüntülenene kadar geçen süre (TTID) ve tam ekrana görüntülenene kadar geçen süre (TTFD)'dir.
TTID, uygulamanın ilk karesini çizdiği andır. Bir şey göstermek, kullanıcıya uygulamanın çalıştığı bilgisini verdiği için bu işlemi olabildiğince kısa tutmak önemlidir. Hatta uygulamanın duyarlı olduğunu göstermek için belirsiz bir ilerleme durumu göstergesi de gösterebilirsiniz.
TTFD, uygulamayla gerçekten etkileşim kurulabileceği zamandır. Kullanıcıların canını sıkmamak için bu işlemi mümkün olduğunca kısa tutmak önemlidir. TTFD'yi doğru şekilde işaretlerseniz sisteme, TTFD'ye giden yolda çalıştırılan kodun uygulama başlatmanın bir parçası olduğunu bildirirsiniz. Sonuç olarak, sistemin bu kodu profile yerleştirme olasılığı artar.
Uygulamanızın duyarlı olmasını sağlamak için hem TTID hem de TTFD'yi mümkün olduğunca düşük tutun.
Sistem, TTID'yi algılayabilir, Logcat'te görüntüleyebilir ve başlangıç karşılaştırmaları kapsamında raporlayabilir. Ancak sistem, TTFD'yi belirleyemez. Tam olarak çizilmiş etkileşimli bir duruma ulaşıldığında bunu bildirmek uygulamanın sorumluluğundadır. Bunu, reportFullyDrawn()
'u çağırarak veya Jetpack Compose kullanıyorsanız ReportDrawn
'i çağırarak yapabilirsiniz. Uygulamanın tamamen çizilmiş olarak kabul edilmesi için tümünün tamamlanması gereken birden fazla arka plan göreviniz varsa Başlangıç zamanlaması doğruluğunu iyileştirme bölümünde açıklandığı gibi FullyDrawnReporter
kullanabilirsiniz.
Kitaplık profilleri ve özel profiller
Profillerin etkisini karşılaştırırken, uygulamanızın profillerinin avantajlarını Jetpack kitaplıkları gibi kitaplıklar tarafından sağlanan profillerden ayırmak zor olabilir. APK'nızı derlediğinizde Android Gradle eklentisi, kitaplık bağımlılıklarındaki tüm profillerin yanı sıra özel profilinizi de ekler. Bu, genel performansı optimize etmek için iyidir ve sürüm derlemeleri için önerilir. Ancak bu, özel profilinizden ne kadar ek performans kazancı elde ettiğinizi ölçmeyi zorlaştırır.
Özel profilinizin sağladığı ek optimizasyonu manuel olarak görmenin hızlı bir yolu, özel profilinizi kaldırıp karşılaştırmalarınızı çalıştırmaktır. Ardından, pili değiştirip karşılaştırmalarınızı tekrar çalıştırın. İkisini karşılaştırarak kitaplık profillerinin tek başına ve kitaplık profillerinin yanı sıra özel profilinizin sağladığı optimizasyonları görebilirsiniz.
Profilleri karşılaştırmanın otomatik bir yolu, özel profilinizi değil yalnızca kitaplık profillerini içeren yeni bir derleme varyantı oluşturmaktır. Bu varyanttaki karşılaştırmaları, hem kitaplık profillerini hem de özel profillerinizi içeren sürüm varyantıyla karşılaştırın. Aşağıdaki örnekte, yalnızca kitaplık profillerini içeren varyantın nasıl oluşturulacağı gösterilmektedir. Profil tüketici modülünüze (genellikle uygulama modülünüz) releaseWithoutCustomProfile
adlı yeni bir varyant ekleyin:
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile(project(":baselineprofile")) } baselineProfile { variants { create("release") { from(project(":baselineprofile")) } } }
Groovy
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
Önceki kod örneğinde, baselineProfile
bağımlılığı tüm varyantlardan kaldırılır ve yalnızca release
varyantına seçici olarak uygulanır. Profil üretici modülüne olan bağımlılık kaldırılmış olsa bile kitaplık profillerinin hâlâ eklenmesi mantıksız görünebilir. Ancak bu modül yalnızca özel profilinizi oluşturmaktan sorumludur. Android Gradle eklentisi tüm varyantlar için çalışmaya devam eder ve kitaplık profillerini dahil etmekten sorumludur.
Yeni varyantı profil oluşturucu modülüne de eklemeniz gerekir. Bu örnekte yapımcı modülü :baselineprofile
olarak adlandırılmıştır.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
Groovy
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
Android Studio'dan karşılaştırmayı çalıştırırken performansı yalnızca kitaplık profilleriyle ölçmek için bir releaseWithoutCustomProfile
varyantı veya performansı kitaplık ve özel profillerle ölçmek için bir release
varyantı seçin.
G/Ç'ye bağlı uygulama başlatmayı önleyin
Uygulamanız, başlangıç sırasında çok sayıda G/Ç çağrısı veya ağ çağrısı yapıyorsa bu durum hem uygulamanın başlangıç süresini hem de başlangıç karşılaştırmasının doğruluğunu olumsuz yönde etkileyebilir. Bu ağır çağrılar, zaman içinde ve hatta aynı karşılaştırmanın iterasyonları arasında değişebilen belirsiz bir süre alabilir. G/Ç çağrıları, cihazın dışındaki ve cihazdaki faktörlerden etkilenebileceğinden genellikle ağ çağrılarından daha iyidir. Başlangıç sırasında ağ çağrılarından kaçının. Bunlardan birini kullanmak kaçınılmaz olduğunda G/Ç'yi kullanın.
Uygulama mimarinizin, yalnızca başlangıç karşılaştırması yaparken kullanmak için bile olsa ağ veya G/Ç çağrıları olmadan uygulama başlatmayı desteklemesini öneririz. Bu, karşılaştırmalarınızın farklı iterasyonları arasında mümkün olan en düşük varyansı sağlamanıza yardımcı olur.
Uygulamanız Hilt kullanıyorsa Microbenchmark ve Hilt'te karşılaştırma yaparken sahte G/Ç sınırlı uygulamalar sağlayabilirsiniz.
Tüm önemli kullanıcı yolculuklarını kapsayın
Referans profilinizi oluştururken tüm önemli kullanıcı yolculuklarını doğru şekilde kapsaması önemlidir. Kapsam dışında kalan kullanıcı yolculukları, temel profiller tarafından iyileştirilmez. En etkili temel profiller, tüm yaygın başlangıç kullanıcı yolculuklarının yanı sıra kaydırmalı listeler gibi performansa duyarlı uygulama içi kullanıcı yolculuklarını içerir.