बेसलाइन प्रोफ़ाइल डीबग करें

इस दस्तावेज़ में, समस्याओं का पता लगाने के लिए सबसे सही तरीके और समस्या हल करने के तरीके दिए गए हैं. साथ ही, यह पक्का करने के लिए भी तरीके दिए गए हैं कि आपकी बेसलाइन प्रोफ़ाइलें सही तरीके से काम कर रही हों, ताकि आपको ज़्यादा से ज़्यादा फ़ायदा मिल सके.

बनाने से जुड़ी समस्याएं

अगर आपने Now in Android सैंपल ऐप्लिकेशन में, बेसलाइन प्रोफ़ाइल का उदाहरण कॉपी किया है, तो आपको बेसलाइन प्रोफ़ाइल टास्क के दौरान टेस्ट फ़ेल होने की समस्या आ सकती है. इसमें बताया जाता है कि टेस्ट को एम्युलेटर पर नहीं चलाया जा सकता:

./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):
        ...

ये गड़बड़ियां इसलिए होती हैं, क्योंकि Now in Android, बेसलाइन प्रोफ़ाइल जनरेट करने के लिए Gradle-मैनेज किए गए डिवाइस का इस्तेमाल करता है. टेस्ट फ़ेल हो सकते हैं, क्योंकि आम तौर पर आपको एम्युलेटर पर परफ़ॉर्मेंस बेंचमार्क नहीं चलाने चाहिए. हालांकि, बेसलाइन प्रोफ़ाइल जनरेट करते समय परफ़ॉर्मेंस मेट्रिक इकट्ठा नहीं की जाती हैं. इसलिए, अपनी सुविधा के लिए एम्युलेटर पर बेसलाइन प्रोफ़ाइल कलेक्शन चलाया जा सकता है. एम्युलेटर के साथ बेसलाइन प्रोफ़ाइलें इस्तेमाल करने के लिए, कमांड-लाइन से बिल्ड और इंस्टॉलेशन करें. साथ ही, बेसलाइन प्रोफ़ाइल के नियमों को चालू करने के लिए कोई आर्ग्युमेंट सेट करें:

installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile

इसके अलावा, Android Studio में कस्टम रन कॉन्फ़िगरेशन बनाया जा सकता है. इससे एम्युलेटर पर बेसलाइन प्रोफ़ाइलें चालू की जा सकती हैं. इसके लिए, चलाएं > कॉन्फ़िगरेशन में बदलाव करें को चुनें:

Now in Android में बेसलाइन प्रोफ़ाइलें बनाने के लिए, कस्टम रन कॉन्फ़िगरेशन जोड़ना
पहली इमेज. Now in Android में बेसलाइन प्रोफ़ाइलें बनाने के लिए, कस्टम रन कॉन्फ़िगरेशन जोड़ें.

प्रोफ़ाइल इंस्टॉल करने और उसे लागू करने की पुष्टि करना

यह देखने के लिए कि जिस APK या Android ऐप्लिकेशन बंडल (AAB) की जांच की जा रही है वह ऐसे बिल्ड वैरिएंट का है जिसमें बेसलाइन प्रोफ़ाइलें शामिल हैं, यह तरीका अपनाएं:

  1. Android Studio में, Build > Analyze APK को चुनें.
  2. अपना AAB या APK खोलें.
  3. पुष्टि करें कि baseline.prof फ़ाइल मौजूद है:

    • अगर किसी AAB की जांच की जा रही है, तो प्रोफ़ाइल /BUNDLE-METADATA/com.android.tools.build.profiles/baseline.prof पर होती है.
    • अगर किसी APK की जांच की जा रही है, तो प्रोफ़ाइल /assets/dexopt/baseline.prof पर मौजूद होती है.

      इस फ़ाइल की मौजूदगी से पता चलता है कि बिल्ड कॉन्फ़िगरेशन सही है. अगर यह मौजूद नहीं है, तो इसका मतलब है कि Android Runtime को इंस्टॉल करने के दौरान, प्री-कंपाइलेशन से जुड़े कोई भी निर्देश नहीं मिलेंगे.

      Android Studio में APK Analyzer का इस्तेमाल करके, बेसलाइन प्रोफ़ाइल की जांच करना
      दूसरी इमेज. Android Studio में APK एनालाइज़र का इस्तेमाल करके, बेसलाइन प्रोफ़ाइल की जांच करें.

बेसलान प्रोफ़ाइलें, ऐप्लिकेशन चलाने वाले डिवाइस पर कंपाइल की जानी चाहिए. Android Studio या Gradle रैपर कमांड-लाइन टूल का इस्तेमाल करके, डीबग नहीं की जा सकने वाली बिल्ड इंस्टॉल करने पर, डिवाइस पर कंपाइलेशन अपने-आप हो जाता है. अगर आपने Google Play Store से ऐप्लिकेशन इंस्टॉल किया है, तो बैकग्राउंड में डिवाइस अपडेट होने के दौरान, बेसलाइन प्रोफ़ाइलें कंपाइल की जाती हैं. ऐसा इंस्टॉल करने के समय नहीं होता. जब ऐप्लिकेशन को अन्य टूल का इस्तेमाल करके इंस्टॉल किया जाता है, तो Jetpack ProfileInstaller लाइब्रेरी, अगली बैकग्राउंड DEX ऑप्टिमाइज़ेशन प्रोसेस के दौरान कंपाइल करने के लिए प्रोफ़ाइलें कतार में लगाने की ज़िम्मेदारी लेती है.

ऐसे मामलों में, अगर आपको यह पक्का करना है कि आपकी बेसलाइन प्रोफ़ाइलें इस्तेमाल की जा रही हैं, तो आपको बेसलाइन प्रोफ़ाइलों को कंपाइल करने के लिए मजबूर करना पड़ सकता है. ProfileVerifier की मदद से, प्रोफ़ाइल इंस्टॉल करने और कंपाइल करने की स्थिति के बारे में क्वेरी की जा सकती है. इसका उदाहरण यहां दिया गया है:

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);
    }
}

नीचे दिए गए नतीजे के कोड से, कुछ समस्याओं की वजहों के बारे में जानकारी मिलती है:

RESULT_CODE_COMPILED_WITH_PROFILE
प्रोफ़ाइल इंस्टॉल और कंपाइल की जाती है. साथ ही, जब भी ऐप्लिकेशन चलाया जाता है, तब इसका इस्तेमाल किया जाता है. यह वह नतीजा है जो आपको देखना है.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
चलाए जा रहे APK में कोई प्रोफ़ाइल नहीं मिली. अगर आपको यह गड़बड़ी दिखती है, तो पक्का करें कि आपने ऐसे बिल्ड वैरिएंट का इस्तेमाल किया हो जिसमें बेसलाइन प्रोफ़ाइलें शामिल हों. साथ ही, यह भी पक्का करें कि APK में कोई प्रोफ़ाइल मौजूद हो.
RESULT_CODE_NO_PROFILE
ऐप्लिकेशन स्टोर या पैकेज मैनेजर से ऐप्लिकेशन इंस्टॉल करते समय, इस ऐप्लिकेशन के लिए कोई प्रोफ़ाइल इंस्टॉल नहीं की गई थी. इस गड़बड़ी कोड की मुख्य वजह यह है कि ProfileInstallerInitializer के बंद होने की वजह से, प्रोफ़ाइल इंस्टॉलर नहीं चला. ध्यान दें कि इस गड़बड़ी की शिकायत करने पर, ऐप्लिकेशन के APK में अब भी एम्बेड की गई प्रोफ़ाइल मिली है. जब एम्बेड की गई प्रोफ़ाइल नहीं मिलती है, तो गड़बड़ी कोड RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED दिखता है.
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
APK या AAB में एक प्रोफ़ाइल मिली है और उसे कंपाइल करने के लिए लाइन में लगा दिया गया है. जब ProfileInstaller किसी प्रोफ़ाइल को इंस्टॉल करता है, तो उसे कंपाइल करने के लिए कतार में रखा जाता है. ऐसा तब होता है, जब सिस्टम अगली बार बैकग्राउंड DEX ऑप्टिमाइज़ेशन की प्रोसेस को पूरा करता है. कंपाइलेशन पूरा होने तक, प्रोफ़ाइल चालू नहीं होती. जब तक कंपाइलेशन पूरा नहीं हो जाता, तब तक अपनी बेसलाइन प्रोफ़ाइलों को बेंचमार्क करने की कोशिश न करें. आपको बेसलाइन प्रोफ़ाइलों को फ़ोर्स कंपाइल करने की ज़रूरत पड़ सकती है. यह गड़बड़ी तब नहीं होगी, जब ऐप्लिकेशन को Android 9 (एपीआई 28) और उसके बाद के वर्शन वाले डिवाइसों पर Play Store या पैकेज मैनेजर से इंस्टॉल किया जाएगा. ऐसा इसलिए, क्योंकि इंस्टॉलेशन के दौरान कंपाइलेशन किया जाता है.
RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
ऐसी प्रोफ़ाइल इंस्टॉल की गई है जो मेल नहीं खाती. साथ ही, ऐप्लिकेशन को उससे कंपाइल किया गया है. यह Google Play Store या पैकेज मैनेजर के ज़रिए इंस्टॉल करने का नतीजा है. ध्यान दें कि यह नतीजा RESULT_CODE_COMPILED_WITH_PROFILE से अलग है, क्योंकि मिलान न करने वाली प्रोफ़ाइल सिर्फ़ उन तरीकों को कंपाइल करेगी जिन्हें अब भी प्रोफ़ाइल और ऐप्लिकेशन के बीच शेयर किया जाता है. प्रोफ़ाइल, उम्मीद से छोटी है. साथ ही, इसमें बेसलाइन प्रोफ़ाइल में शामिल किए गए तरीकों की तुलना में कम तरीके कंपाइल किए जाएंगे.
RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier पुष्टि के नतीजे की कैश मेमोरी वाली फ़ाइल नहीं लिख सकता. ऐसा इन वजहों से हो सकता है: ऐप्लिकेशन फ़ोल्डर की अनुमतियों में कोई गड़बड़ी हो या डिवाइस पर डिस्क में काफ़ी जगह न हो.
RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
ProfileVerifieris running on an unsupported API version of Android. ProfileVerifier सिर्फ़ Android 9 (एपीआई लेवल 28) और इसके बाद के वर्शन पर काम करता है.
RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
ऐप्लिकेशन पैकेज के लिए PackageManager को क्वेरी करते समय, PackageManager.NameNotFoundException थ्रो किया जाता है. ऐसा कभी-कभार ही होना चाहिए. ऐप्लिकेशन को अनइंस्टॉल करके, फिर से इंस्टॉल करें.
RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
पुष्टि के पिछले नतीजे की कैश फ़ाइल मौजूद है, लेकिन उसे पढ़ा नहीं जा सकता. ऐसा बहुत कम होना चाहिए. ऐप्लिकेशन को अनइंस्टॉल करके, फिर से इंस्टॉल करें.

प्रोडक्शन में ProfileVerifier का इस्तेमाल करना

प्रोडक्शन में, ProfileVerifier का इस्तेमाल Google Analytics for Firebase जैसी analytics-reporting लाइब्रेरी के साथ किया जा सकता है. इससे, प्रोफ़ाइल की स्थिति के बारे में बताने वाले Analytics इवेंट जनरेट किए जा सकते हैं. उदाहरण के लिए, अगर कोई ऐसा नया ऐप्लिकेशन वर्शन रिलीज़ किया जाता है जिसमें बेसलाइन प्रोफ़ाइलें शामिल नहीं हैं, तो यह सुविधा आपको तुरंत सूचना देती है.

बेसलाइन प्रोफ़ाइल को कंपाइल करने के लिए मजबूर करें

अगर आपकी बेसलाइन प्रोफ़ाइल का कंपाइलेशन स्टेटस RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION है, तो adb का इस्तेमाल करके, कंपाइलेशन को तुरंत शुरू किया जा सकता है:

adb shell cmd package compile -r bg-dexopt PACKAGE_NAME

ProfileVerifier के बिना, बेसलाइन प्रोफ़ाइल के कंपाइल होने की स्थिति की जांच करना

अगर ProfileVerifier का इस्तेमाल नहीं किया जा रहा है, तो adb का इस्तेमाल करके कंपाइलेशन की स्थिति देखी जा सकती है. हालांकि, इससे ProfileVerifier जितनी अहम जानकारी नहीं मिलती:

adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME

adb का इस्तेमाल करने पर, कुछ इस तरह का नतीजा मिलता है:

  [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]

स्टेटस वैल्यू से, प्रोफ़ाइल कंपाइल करने की स्थिति का पता चलता है. यह इनमें से कोई एक वैल्यू होती है:

कंपाइलेशन का स्टेटस मतलब
speed‑profile कंपाइल की गई प्रोफ़ाइल मौजूद है और उसका इस्तेमाल किया जा रहा है.
verify कोई कंपाइल की गई प्रोफ़ाइल मौजूद नहीं है.

verify स्टेटस का मतलब यह नहीं है कि APK या AAB में कोई प्रोफ़ाइल नहीं है. ऐसा इसलिए, क्योंकि इसे अगले बैकग्राउंड DEX ऑप्टिमाइज़ेशन टास्क के ज़रिए कंपाइल करने के लिए कतार में रखा जा सकता है.

वजह की वैल्यू से पता चलता है कि प्रोफ़ाइल को कंपाइल करने के लिए क्या ट्रिगर किया गया है. यह इनमें से कोई एक वैल्यू होती है:

वजह मतलब
install‑dm ऐप्लिकेशन इंस्टॉल करते समय, बेसलाइन प्रोफ़ाइल को मैन्युअल तरीके से या Google Play ने कंपाइल किया था.
bg‑dexopt जब आपका डिवाइस इस्तेमाल नहीं किया जा रहा था, तब एक प्रोफ़ाइल कंपाइल की गई थी. यह बेसलाइन प्रोफ़ाइल हो सकती है या ऐप्लिकेशन के इस्तेमाल के दौरान इकट्ठा की गई प्रोफ़ाइल हो सकती है.
cmdline adb का इस्तेमाल करके कंपाइलेशन ट्रिगर किया गया था. यह बेसलाइन प्रोफ़ाइल हो सकती है या ऐप्लिकेशन के इस्तेमाल के दौरान इकट्ठा की गई प्रोफ़ाइल हो सकती है.

DEX और r8.json के लिए, स्टार्टअप प्रोफ़ाइल के आवेदन की पुष्टि करना

स्टार्टअप प्रोफ़ाइल के नियमों का इस्तेमाल, R8 ऐप्लिकेशन बनाते समय करता है. इससे आपकी DEX फ़ाइलों में मौजूद क्लास के लेआउट को ऑप्टिमाइज़ किया जा सकता है. यह बिल्ड-टाइम ऑप्टिमाइज़ेशन, बेसलाइन प्रोफ़ाइल (baseline.prof) के इस्तेमाल के तरीके से अलग है. ऐसा इसलिए, क्योंकि इन्हें APK या AAB में पैकेज किया जाता है, ताकि ART डिवाइस पर कंपाइल कर सके. स्टार्टअप प्रोफ़ाइल के नियमों को बिल्ड प्रोसेस के दौरान ही लागू किया जाता है. इसलिए, आपके APK या AAB में जांच करने के लिए कोई अलग startup.prof फ़ाइल नहीं होती. स्टार्टअप प्रोफ़ाइलों का असर, DEX फ़ाइल लेआउट में दिखता है.

r8.json की मदद से DEX अरेंजमेंट की जांच करें (AGP 8.8 या इसके बाद के वर्शन के लिए सुझाव दिया गया है)

Android Gradle प्लगिन (AGP) 8.8 या इसके बाद के वर्शन का इस्तेमाल करने वाले प्रोजेक्ट के लिए, यह पुष्टि की जा सकती है कि स्टार्टअप प्रोफ़ाइल लागू की गई है या नहीं. इसके लिए, जनरेट की गई r8.json फ़ाइल की जांच करें. यह फ़ाइल, आपके AAB में पैकेज की गई है.

  1. अपने AAB संग्रह को खोलें और r8.json फ़ाइल ढूंढें.
  2. फ़ाइल में dexFiles ऐरे खोजें. इसमें जनरेट की गई DEX फ़ाइलों की सूची होती है.
  3. dexFiles ऑब्जेक्ट ढूंढें, जिसमें की-वैल्यू पेयर "startup": true शामिल हो. इससे साफ़ तौर पर पता चलता है कि स्टार्टअप प्रोफ़ाइल के नियमों को उस खास DEX फ़ाइल के लेआउट को ऑप्टिमाइज़ करने के लिए लागू किया गया था.

    "dexFiles": [
     {
       "checksum": "...",
       "startup": true // This flag confirms profile application to this DEX file
     },
     // ... other DEX files
    ]
    

AGP के सभी वर्शन के लिए, DEX के क्रम की जांच करें

अगर एजीपी का वर्शन 8.8 से कम है, तो DEX फ़ाइलों की जांच करना यह पुष्टि करने का मुख्य तरीका है कि आपकी स्टार्टअप प्रोफ़ाइल सही तरीके से लागू की गई है. अगर AGP 8.8 या उसके बाद के वर्शन का इस्तेमाल किया जा रहा है और आपको DEX लेआउट की मैन्युअल तरीके से जांच करनी है, तो इस तरीके का इस्तेमाल किया जा सकता है. उदाहरण के लिए, अगर आपको परफ़ॉर्मेंस में उम्मीद के मुताबिक सुधार नहीं दिख रहा है. डीईएक्स की व्यवस्था की जांच करने के लिए, यह तरीका अपनाएं:

  1. Android Studio में Build > Analyze APK का इस्तेमाल करके, अपना AAB या APK खोलें.
  2. पहले DEX फ़ाइल पर जाएं. उदाहरण के लिए, classes.dex.
  3. इस DEX फ़ाइल के कॉन्टेंट की जांच करें. आपको यह पुष्टि करनी होगी कि आपकी स्टार्टअप प्रोफ़ाइल फ़ाइल (startup-prof.txt) में तय की गई ज़रूरी क्लास और तरीके, इस प्राइमरी DEX फ़ाइल में मौजूद हैं. आवेदन स्वीकार होने का मतलब है कि स्टार्टअप के लिए ज़रूरी इन कॉम्पोनेंट को तेज़ी से लोड करने के लिए प्राथमिकता दी जाती है.

परफ़ॉर्मेंस से जुड़ी समस्याएं

इस सेक्शन में, अपनी बेसलाइन प्रोफ़ाइलों को सही तरीके से तय करने और उनकी तुलना करने के कुछ सबसे सही तरीके बताए गए हैं. इससे आपको उनका ज़्यादा से ज़्यादा फ़ायदा मिलेगा.

स्टार्टअप की मेट्रिक की सही तरीके से तुलना करना

अगर स्टार्टअप मेट्रिक अच्छी तरह से तय की गई हैं, तो आपकी बेसलाइन प्रोफ़ाइलें ज़्यादा असरदार होंगी. दो मुख्य मेट्रिक हैं: शुरुआती डिसप्ले में लगने वाला समय (टीटीआईडी) और पूरी तरह से डिसप्ले होने में लगने वाला समय (टीटीएफ़डी).

टीटीआईडी तब होता है, जब ऐप्लिकेशन अपना पहला फ़्रेम दिखाता है. इसे जितना हो सके उतना छोटा रखें, क्योंकि कुछ भी दिखाने से उपयोगकर्ता को पता चलता है कि ऐप्लिकेशन चल रहा है. ऐप्लिकेशन के रिस्पॉन्सिव होने की जानकारी देने के लिए, अनिश्चित प्रोग्रेस इंडिकेटर भी दिखाया जा सकता है.

टीटीएफ़डी का मतलब है कि ऐप्लिकेशन के साथ इंटरैक्ट किया जा सकता है. उपयोगकर्ताओं को परेशानी से बचाने के लिए, इस प्रोसेस को जितना हो सके उतना छोटा रखें. टीटीएफ़डी को सही तरीके से सिग्नल देने का मतलब है कि आपने सिस्टम को बताया है कि टीटीएफ़डी के लिए रन किया गया कोड, ऐप्लिकेशन के स्टार्टअप का हिस्सा है. इसलिए, सिस्टम इस कोड को प्रोफ़ाइल में रखने की संभावना ज़्यादा होती है.

अपने ऐप्लिकेशन को रिस्पॉन्सिव बनाने के लिए, टीटीआईडी और टीटीएफ़डी, दोनों को जितना हो सके उतना कम रखें.

सिस्टम, टीटीआईडी का पता लगा सकता है. साथ ही, इसे Logcat में दिखा सकता है. इसके अलावा, स्टार्टअप बेंचमार्क के हिस्से के तौर पर इसकी रिपोर्ट कर सकता है. हालांकि, सिस्टम टीटीएफ़डी का पता नहीं लगा पाता है. इसलिए, यह ऐप्लिकेशन की ज़िम्मेदारी है कि वह यह रिपोर्ट करे कि कब वह पूरी तरह से इंटरैक्टिव स्थिति में पहुँच गया है. इसके लिए, reportFullyDrawn() को कॉल करें या अगर Jetpack Compose का इस्तेमाल किया जा रहा है, तो ReportDrawn को कॉल करें. अगर आपके पास कई बैकग्राउंड टास्क हैं और ऐप्लिकेशन को पूरी तरह से रेंडर करने से पहले उन सभी को पूरा करना है, तो स्टार्टअप टाइमिंग की सटीक जानकारी को बेहतर बनाएं में बताए गए तरीके के मुताबिक, FullyDrawnReporter का इस्तेमाल किया जा सकता है.

लाइब्रेरी प्रोफ़ाइलें और कस्टम प्रोफ़ाइलें

प्रोफ़ाइलों के असर की तुलना करते समय, आपके ऐप्लिकेशन की प्रोफ़ाइलों के फ़ायदों को लाइब्रेरी से योगदान की गई प्रोफ़ाइलों से अलग करना मुश्किल हो सकता है. जैसे, Jetpack लाइब्रेरी. APK बनाते समय, Android Gradle प्लग इन, लाइब्रेरी डिपेंडेंसी के साथ-साथ आपकी कस्टम प्रोफ़ाइल में मौजूद सभी प्रोफ़ाइलें जोड़ता है. यह कुल परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए अच्छा है. साथ ही, इसे रिलीज़ बिल्ड के लिए इस्तेमाल करने का सुझाव दिया जाता है. हालांकि, इससे यह मेज़र करना मुश्किल हो जाता है कि आपकी कस्टम प्रोफ़ाइल से परफ़ॉर्मेंस में कितना फ़ायदा मिला.

कस्टम प्रोफ़ाइल से मिले अतिरिक्त ऑप्टिमाइज़ेशन को मैन्युअल तरीके से देखने का सबसे आसान तरीका यह है कि आप उसे हटा दें और अपने बेंचमार्क चलाएं. इसके बाद, इसे बदलें और बेंचमार्क फिर से चलाएं. इन दोनों की तुलना करने पर, आपको सिर्फ़ लाइब्रेरी प्रोफ़ाइलों और लाइब्रेरी प्रोफ़ाइलों के साथ-साथ आपकी कस्टम प्रोफ़ाइल से मिले ऑप्टिमाइज़ेशन दिखेंगे.

प्रोफ़ाइलों की तुलना करने का एक तरीका यह है कि एक नया बिल्ड वैरिएंट बनाया जाए. इसमें सिर्फ़ लाइब्रेरी प्रोफ़ाइलें हों और आपकी कस्टम प्रोफ़ाइल न हो. इस वैरिएंट के बेंचमार्क की तुलना, रिलीज़ वैरिएंट के बेंचमार्क से करें. रिलीज़ वैरिएंट में लाइब्रेरी प्रोफ़ाइल और आपकी कस्टम प्रोफ़ाइल, दोनों शामिल होती हैं. इस उदाहरण में, सिर्फ़ लाइब्रेरी प्रोफ़ाइलें शामिल करने वाले वैरिएंट को सेट अप करने का तरीका दिखाया गया है. अपनी प्रोफ़ाइल के उपभोक्ता मॉड्यूल में releaseWithoutCustomProfile नाम वाला नया वैरिएंट जोड़ें. यह आम तौर पर आपका ऐप्लिकेशन मॉड्यूल होता है:

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"))
    }
  }
}

ऊपर दिए गए कोड के उदाहरण में, सभी वैरिएंट से baselineProfile डिपेंडेंसी को हटा दिया गया है. साथ ही, इसे सिर्फ़ release वैरिएंट पर लागू किया गया है. ऐसा लग सकता है कि प्रोफ़ाइल प्रोड्यूसर मॉड्यूल पर निर्भरता हटाने के बाद भी, लाइब्रेरी प्रोफ़ाइलें क्यों जोड़ी जा रही हैं. हालांकि, यह मॉड्यूल सिर्फ़ आपकी पसंद के मुताबिक प्रोफ़ाइल जनरेट करने के लिए ज़िम्मेदार है. Android Gradle प्लगिन अब भी सभी वैरिएंट के लिए काम कर रहा है. साथ ही, लाइब्रेरी प्रोफ़ाइलें शामिल करने की ज़िम्मेदारी भी इसी की है.

आपको नए वैरिएंट को प्रोफ़ाइल जनरेटर मॉड्यूल में भी जोड़ना होगा. इस उदाहरण में, प्रोड्यूसर मॉड्यूल का नाम :baselineprofile है.

Kotlin

android {
  ...
    buildTypes {
      ...
      // Release build with only library profiles.
      create("releaseWithoutCustomProfile") {}
      ...
    }
  ...
}

Groovy

android {
  ...
    buildTypes {
      ...
      // Release build with only library profiles.
      releaseWithoutCustomProfile {}
      ...
    }
  ...
}

Android Studio से बेंचमार्क चलाने के दौरान, सिर्फ़ लाइब्रेरी प्रोफ़ाइलों की परफ़ॉर्मेंस मेज़र करने के लिए, releaseWithoutCustomProfile वैरिएंट चुनें. इसके अलावा, लाइब्रेरी और कस्टम प्रोफ़ाइलों की परफ़ॉर्मेंस मेज़र करने के लिए, release वैरिएंट चुनें.

I/O-बाउंड ऐप्लिकेशन को शुरू करने से बचें

अगर आपका ऐप्लिकेशन स्टार्टअप के दौरान बहुत सारे I/O कॉल या नेटवर्क कॉल करता है, तो इससे ऐप्लिकेशन के स्टार्टअप टाइम और स्टार्टअप बेंचमार्किंग की सटीक जानकारी, दोनों पर बुरा असर पड़ सकता है. इन हैवीवेट कॉल में कितना समय लगेगा, यह तय नहीं किया जा सकता. साथ ही, यह समय अलग-अलग हो सकता है. यह एक ही बेंचमार्क के अलग-अलग वर्शन के बीच भी अलग-अलग हो सकता है. आम तौर पर, नेटवर्क कॉल की तुलना में I/O कॉल बेहतर होते हैं. ऐसा इसलिए है, क्योंकि नेटवर्क कॉल पर डिवाइस के बाहर और डिवाइस के अंदर मौजूद फ़ैक्टर का असर पड़ सकता है. स्टार्टअप के दौरान, नेटवर्क कॉल से बचें. जहां एक या दूसरे का इस्तेमाल करना ज़रूरी हो वहां I/O का इस्तेमाल करें.

हमारा सुझाव है कि आप अपने ऐप्लिकेशन के आर्किटेक्चर को इस तरह से डिज़ाइन करें कि वह नेटवर्क या I/O कॉल के बिना ऐप्लिकेशन को चालू करने की सुविधा दे. भले ही, आपको इसका इस्तेमाल सिर्फ़ स्टार्टअप की परफ़ॉर्मेंस की तुलना करने के लिए करना हो. इससे यह पक्का करने में मदद मिलती है कि आपके बेंचमार्क के अलग-अलग वर्शन के बीच कम से कम अंतर हो.

अगर आपका ऐप्लिकेशन Hilt का इस्तेमाल करता है, तो Microbenchmark और Hilt में बेंचमार्किंग करते समय, I/O-बाउंड के फ़र्ज़ी इंप्लीमेंटेशन दिए जा सकते हैं.

उपयोगकर्ता की सभी अहम गतिविधियों को कवर करना

यह ज़रूरी है कि बेसलाइन प्रोफ़ाइल जनरेट करते समय, उपयोगकर्ता की सभी अहम गतिविधियों को सटीक तरीके से शामिल किया जाए. जिन उपयोगकर्ता गतिविधियों को शामिल नहीं किया गया है उनमें बेसलाइन प्रोफ़ाइलों से सुधार नहीं होगा. सबसे असरदार बेसलाइन प्रोफ़ाइल में, स्टार्टअप के सभी सामान्य उपयोगकर्ता अनुभव शामिल होते हैं. साथ ही, परफ़ॉर्मेंस के हिसाब से अहम इन-ऐप्लिकेशन उपयोगकर्ता अनुभव भी शामिल होते हैं. जैसे, स्क्रोल करने वाली सूचियां.

A/B टेस्टिंग के लिए, कंपाइल-टाइम प्रोफ़ाइल में किए गए बदलाव

स्टार्टअप और बेसलाइन प्रोफ़ाइलें, कंपाइल-टाइम ऑप्टिमाइज़ेशन होती हैं. इसलिए, Google Play Store का इस्तेमाल करके अलग-अलग APK की सीधे तौर पर A/B टेस्टिंग करना, आम तौर पर प्रोडक्शन रिलीज़ के लिए काम नहीं करता. प्रोडक्शन जैसे एनवायरमेंट में असर का आकलन करने के लिए, इन तरीकों का इस्तेमाल करें:

  • ऑफ-साइकल रिलीज़: अपने उपयोगकर्ता आधार के छोटे प्रतिशत के लिए, ऑफ-साइकल रिलीज़ अपलोड करें. इसमें सिर्फ़ प्रोफ़ाइल में बदलाव शामिल हो. इससे आपको परफ़ॉर्मेंस में अंतर से जुड़ी असल दुनिया की मेट्रिक इकट्ठा करने में मदद मिलती है.

  • स्थानीय बेंचमार्किंग: अपने ऐप्लिकेशन की स्थानीय बेंचमार्किंग करें. इसके लिए, प्रोफ़ाइल लागू करें और न करें. हालांकि, ध्यान रखें कि लोकल बेंचमार्किंग से आपको प्रोफ़ाइलों के लिए सबसे अच्छा परफ़ॉर्मेंस वाला डेटा दिखता है. ऐसा इसलिए, क्योंकि इसमें प्रोडक्शन डिवाइसों में मौजूद ART की क्लाउड प्रोफ़ाइलों के असर को शामिल नहीं किया जाता.