Bu belgede, sorunları teşhis etmenize ve Temel Profillerinizin en fazla yararı sağlamak için doğru şekilde çalışmasını sağlamaya yardımcı olacak en iyi uygulamalar gösterilmektedir.
Derleme sorunları
Android'de Now örnek uygulamasındaki Temel Profiller örneğini kopyaladıysanız Temel 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):
...
Bu hatalar, Android'de Temel Profil oluşturmak için Gradle tarafından yönetilen bir cihaz kullandığından meydana gelir. Genellikle emülatörde performans karşılaştırmaları çalıştırmamanız gerektiğinden, hatalar normaldir. Ancak, Temel Profiller oluşturduğunuzda performans metrikleri toplamadığınızdan, kolaylık sağlamak için Temel Profil toplamayı emülatörlerde çalıştırabilirsiniz. Temel Profiller'i bir emülatörle kullanmak için, derleme ve yükleme işlemlerini 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 emülatörlerde Temel Profilleri etkinleştirmek için Android Studio'da özel bir çalıştırma yapılandırması oluşturabilirsiniz:
Yükleme sorunları
Derlediğiniz APK veya AAB'nin, Temel Profiller içeren bir derleme varyantından olup olmadığını kontrol edin. Bunu kontrol etmenin en kolay yolu, APK'yı Android Studio'da açmaktır. Bunun için Oluştur > APK'yı analiz et'i seçin, APK'nızı açın ve /assets/dexopt/baseline.prof
dosyasında profili arayın:
Temel Profillerin uygulamayı çalıştıran cihazda derlenmesi gerekir. Cihaz üzerinde derleme, hem uygulama mağazası yüklemeleri hem de PackageInstaller
kullanılarak yüklenen uygulamalar için uygulama yükleme işleminin bir parçası olarak gerçekleşir. Bununla birlikte, uygulama Android Studio'dan başka cihazdan yüklendiğinde veya komut satırı araçları kullanıldığında, Jetpack ProfileInstaller
kitaplığı bir sonraki arka plan DEX optimizasyon işleminde profilleri derleme için sıraya koymaktan sorumludur. Böyle durumlarda, Temel Profillerinizin kullanıldığından emin olmak isterseniz Temel Profillerin derlenmesini zorunlu kılmanız gerekebilir. ProfileVerifier
, aşağıdaki örnekte gösterildiği gibi, profil yükleme ve derleme işleminin 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 nedenleri hakkında ipuçları verir:
RESULT_CODE_COMPILED_WITH_PROFILE
- Profil yüklenir, derlenir ve uygulama her çalıştırıldığında kullanılır. Görmek istediğiniz sonuç budur.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- Çalıştırılmakta olan APK'da veya AAB'de profil bulunamadı. Bu hatayı görüyorsanız Temel Profilleri içeren bir derleme varyantı kullandığınızdan ve APK'nın bir profil içerdiğinden emin olun.
RESULT_CODE_NO_PROFILE
- Uygulama, uygulama mağazası veya paket yöneticisi üzerinden yüklenirken bu uygulama için hiç 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 yerleşik bir profilin hâlâ bulunduğunu unutmayın. Yerleştirilmiş profil bulunamadığındaRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
hata kodu döndürülür. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- APK veya AAB'de bir profil bulundu ve derleme için sıraya alındı. Bir profil
ProfileInstaller
tarafından yüklendiğinde, arka plan DEX optimizasyonu sistem tarafından tekrar ç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 zorunlu kılmanız gerekebilir. Derleme, yükleme sırasında gerçekleştirildiğinden, uygulama Android 9 (API 28) ve sonraki sürümleri çalıştıran cihazlara 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üklendi ve uygulama bununla derlendi.
Bu, Google Play Store veya paket yöneticisi üzerinden yüklemenin sonucudur.
Eşleşmeyen profil yalnızca profil ile uygulama arasında paylaşılan yöntemleri derler. Bu nedenle bu sonucun
RESULT_CODE_COMPILED_WITH_PROFILE
değerinden farklı olduğunu unutmayın. Profil, etkin bir şekilde beklenenden daha küçüktür ve Temel Profil'e eklenenden daha az yöntem derlenir. RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier
, doğrulama sonucu önbellek dosyasını yazamıyor. Bunun nedeni, uygulama klasörü izinleriyle ilgili bir sorun olması veya cihazda yeterli boş disk alanı olmaması olabilir.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ırken birPackageManager.NameNotFoundException
döndürülür. Bu durumla nadiren karşılaşılır. Uygulamayı kaldırıp her şeyi yeniden yüklemeyi deneyin. RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- Doğrulama sonucu için eski bir önbellek dosyası var, ancak bu dosya okunamıyor. Bu tür bir durumla nadiren karşılaşılabilir. Uygulamayı kaldırıp her şeyi yeniden yüklemeyi deneyin.
Üretimde ProfileDoğrufier'ı kullanma
Üretimde, profil durumunu gösteren analiz etkinlikleri oluşturmak için ProfileVerifier
aracını Firebase için Google Analytics gibi analiz raporlama kitaplıklarıyla birlikte kullanabilirsiniz. Örneğin, Temel Profiller içermeyen yeni bir uygulama sürümü yayınlanırsa bu uyarı sizi hızlı bir şekilde uyarır.
Temel Profillerin derlenmesini zorla
Temel Profillerinizin derleme durumu RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
ise adb
ile hemen derlemeyi zorunlu kılabilirsiniz:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
ProfileVerifier olmadan derleme durumunu kontrol etme
ProfileVerifier
kullanmıyorsanız derleme durumunu adb
ile kontrol edebilirsiniz. Ancak bu özellik, ProfileVerifier
kadar ayrıntılı bilgi sağlamaz:
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 gösterir ve aşağıdaki değerlerden biridir:
Derleme durumu | Anlamı |
---|---|
speed‑profile |
Derlenmiş bir profil mevcut ve şu anda kullanılıyor. |
verify |
Derlenmiş profil yok. |
verify
durumu, APK veya AAB'nin bir profil içermediği anlamına gelmez. Bu durum, APK veya AAB'nin bir sonraki arka plan DEX optimizasyon görevi tarafından derleme için sıraya alınabileceği anlamına gelir.
Neden değeri, profilin derlemesini neyin tetiklediğini gösterir ve aşağıdaki değerlerden biridir:
Neden | Anlamı |
---|---|
install‑dm
|
Uygulama yüklendiğinde Temel Profil manuel olarak veya Google Play tarafından derlendi. |
bg‑dexopt
|
Cihazınız boştayken bir profil derlendi. Bu bir Temel Profil veya uygulama kullanımı sırasında toplanan bir profil olabilir. |
cmdline
|
Derleme, adb kullanılarak tetiklendi. Bu bir Temel Profil 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 Temel Profillerinizi doğru şekilde tanımlamaya ve karşılaştırmaya yönelik bazı en iyi uygulamalar gösterilmektedir.
Başlangıç metriklerini doğru şekilde karşılaştırma
Başlangıç metrikleriniz iyi tanımlanmışsa Temel Profilleriniz daha etkili olur. İki temel metrik şunlardır: İlk ekran görüntülenene kadar geçen süre (TTID) ve tam görüntüleme süresi (TTFD).
TTID, uygulamanın ilk karesini çizdiği zamandır. Bu süreyi mümkün olduğunca kısa tutmak önemlidir, çünkü bir öğe görüntülemek kullanıcıya uygulamanın çalıştığını gösterir. Uygulamanın yanıt verdiğini göstermek için bir belirsiz ilerleme göstergesi bile görüntüleyebilirsiniz.
TTFD, uygulamayla gerçekten etkileşimde bulunulabilen zamanı ifade eder. Kullanıcıların hayal kırıklığına uğramasını önlemek için bunu mümkün olduğunca kısa tutmak önemlidir. TTFD'ye doğru şekilde sinyal verirseniz TTFD'ye giden yolda çalıştırılan kodun uygulama başlatma işleminin bir parçası olduğunu sisteme bildirmiş olursunuz. Sonuç olarak, sistemin bu kodu profile yerleştirme olasılığı artar.
Uygulamanızın duyarlı görünmesini sağlamak için hem TTID hem de TTFD'yi mümkün olduğunca düşük tutun.
Sistem TTID'yi algılayabilir, bunu Logcat'ta görüntüleyebilir ve başlangıç karşılaştırmalarının bir parçası olarak raporlayabilir. Ancak, sistem TTFD'yi belirleyemez ve tam olarak çizilmiş bir etkileşimli duruma ulaştığında bunu bildirmek uygulamanın sorumluluğudur. Bunun için reportFullyDrawn()
veya Jetpack Compose'u kullanıyorsanız ReportDrawn
yöntemini çağırabilirsiniz. Uygulamanın tamamen çizildiği kabul edilmesi için tamamlanması gereken birden fazla arka plan göreviniz varsa Başlangıç zamanlaması doğruluğunu iyileştirme bölümünde açıklandığı şekilde FullyDrawnReporter
aracını kullanabilirsiniz.
Kitaplık profilleri ve özel profiller
Profillerin etkisini karşılaştırırken uygulama profillerinizin avantajlarını Jetpack kitaplıkları gibi kitaplıklar tarafından sağlanan profillerden ayırmak zor olabilir. Android Gradle eklentisi, APK'nızı oluştururken kitaplık bağımlılıklarındaki profilleri ve özel profilinizi ekler. Bu, genel performansı optimize etmek için faydalıdır ve sürüm derlemeleriniz için önerilir. Ancak, ö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, profili kaldırıp karşılaştırmalarınızı çalıştırmaktır. Daha sonra, bu etiketi değiştirin ve karşılaştırmalarınızı tekrar çalıştırın. Bu ikisini karşılaştırdığınızda yalnızca kitaplık profilleri tarafından sağlanan optimizasyonlar ve kitaplık profilleri ile özel profiliniz gösterilir.
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. Genellikle uygulama modülünüz olan profil tüketici modülünize 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")) } } }
Modern
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
Yukarıdaki kod örneği, baselineProfile
bağımlılığını tüm varyantlardan kaldırır ve bunu seçici bir şekilde yalnızca release
varyantına uygular. Profil üretici modülüne olan bağımlılık kaldırıldığında kitaplık profillerinin eklenmeye devam etmesi mantıksız gelebilir. Ancak bu modül yalnızca özel profilinizi oluşturmaktan sorumludur. Android Gradle eklentisi tüm varyantlar için çalışmaya devam etmektedir ve kitaplık profillerini eklemekten sorumludur.
Yeni varyantı profil oluşturucu modülüne de eklemeniz gerekir. Bu örnekte üretici modülü :baselineprofile
olarak adlandırılmıştır.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
Modern
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
Karşılaştırmayı Android Studio'dan çalıştırdığınızda, performansı yalnızca kitaplık profilleriyle ölçmek için bir releaseWithoutCustomProfile
varyantı veya kitaplık ve özel profillerle performansı ölçmek için bir release
varyantı seçin.
G/Ç'ye bağlı uygulamaların başlatılmasını önleme
Uygulamanız başlatma sırasında çok sayıda G/Ç çağrısı veya ağ çağrısı yapıyorsa bu durum hem uygulama başlatma süresini hem de başlatma karşılaştırmanızın doğruluğunu olumsuz yönde etkileyebilir. Bu yoğun çağrılar belirsiz süreler alabilir. Bu süre, zaman içinde ve hatta aynı karşılaştırmanın yinelemeleri arasında farklılık gösterebilir. G/Ç çağrıları genellikle ağ aramalarından daha iyidir. Çünkü ağ aramaları, cihaz dışındaki faktörlerden ve cihazın kendisinden etkilenebilir. Başlatma sırasında ağ çağrılarından kaçının. Bunlardan birinin veya diğerinin kullanılması kaçınılmaz olduğunda I/O'yu kullanın.
Uygulama mimarinizin, ağ veya G/Ç çağrıları olmadan uygulama başlatmayı desteklemesini öneririz (yalnızca başlatma karşılaştırması yaparken kullanmak için bile). Böylece karşılaştırmalarınızın farklı yinelemeleri arasında mümkün olan en düşük değişkenliği sağlarsınız.
Uygulamanız Hilt kullanıyorsa Microbenchmark ve Hilt'te karşılaştırma yaparken sahte I/O-bound uygulamalar sağlayabilirsiniz.
Tüm önemli kullanıcı yolculuklarını kapsama dahil
Temel Profil oluşturduğunuzda önemli kullanıcı yolculuklarının tümünü doğru şekilde ele almanız gerekir. Kapsama dahil olmayan kullanıcı yolculukları Temel Profiller tarafından iyileşmez. En etkili temel profiller, tüm yaygın başlangıç kullanıcı yolculuklarının yanı sıra kaydırma listeleri gibi performans açısından hassas uygulama içi kullanıcı yolculuklarını içerir.