बेसलाइन प्रोफ़ाइल की मदद से ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाएं

1. शुरू करने से पहले

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

आपको इन चीज़ों की ज़रूरत होगी

आपको क्या करना होगा

  • बेसलाइन प्रोफ़ाइल जनरेटर का इस्तेमाल करने के लिए, प्रोजेक्ट सेट अप करें.
  • ऐप्लिकेशन के स्टार्टअप और स्क्रोलिंग की परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, बेसलाइन प्रोफ़ाइल जनरेट करें.
  • Jetpack Macrobenchmark लाइब्रेरी की मदद से, परफ़ॉर्मेंस में हुए सुधारों की पुष्टि करें.

आपको क्या सीखने को मिलेगा

  • बेसलाइन प्रोफ़ाइलें और वे ऐप्लिकेशन की परफ़ॉर्मेंस को कैसे बेहतर बना सकती हैं.
  • बेसलाइन प्रोफ़ाइलें जनरेट करने का तरीका.
  • बेसलाइन प्रोफ़ाइलों की परफ़ॉर्मेंस में हुई बढ़ोतरी.

2. सेट अप करना

शुरू करने के लिए, कमांड लाइन से GitHub के डेटा स्टोर करने की जगह को क्लोन करें. इसके लिए, यह कमांड इस्तेमाल करें:

$ git clone https://github.com/android/codelab-android-performance.git

इसके अलावा, दो ZIP फ़ाइलें डाउनलोड की जा सकती हैं:

प्रोजेक्ट को Android Studio में खोलें

  1. 'Android Studio में आपका स्वागत है' विंडो में, 61d0a4432ef6d396.png कोई मौजूदा प्रोजेक्ट खोलें को चुनें.
  2. फ़ोल्डर [Download Location]/codelab-android-performance/baseline-profiles चुनें. पक्का करें कि आपने baseline-profiles डायरेक्ट्री चुनी हो.
  3. जब Android Studio प्रोजेक्ट को इंपोर्ट करता है, तो पक्का करें कि आप बाद में जिस ऐप्लिकेशन के साथ काम करना चाहते हैं उसे बनाने के लिए app मॉड्यूल चला सकते हैं.

सैंपल ऐप्लिकेशन

इस कोडलैब में, JetSnack सैंपल ऐप्लिकेशन का इस्तेमाल किया जा सकता है. यह एक वर्चुअल स्नैक ऑर्डरिंग ऐप्लिकेशन है, जो Jetpack Compose का इस्तेमाल करता है.

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

23633b02ac7ce1bc.png

3. बेसलाइन प्रोफ़ाइल क्या हैं

बेसलाइन प्रोफ़ाइलें, शामिल किए गए कोड पाथ के लिए, कोड को समझने और जस्ट-इन-टाइम (JIT) कंपाइलेशन के चरणों को रोककर, कोड को चलाने की स्पीड को पहले लॉन्च से करीब 30% तक बेहतर बनाती हैं. किसी ऐप्लिकेशन या लाइब्रेरी में बेसलाइन प्रोफ़ाइल शिप करने पर, Android Runtime (ART), पहले से (AOT) कंपाइलेशन की मदद से शामिल किए गए कोड पाथ को ऑप्टिमाइज़ कर सकता है. इससे, हर नए उपयोगकर्ता और ऐप्लिकेशन के हर अपडेट के लिए परफ़ॉर्मेंस बेहतर होती है. प्रोफ़ाइल के हिसाब से ऑप्टिमाइज़ेशन (PGO) की मदद से, ऐप्लिकेशन को स्टार्टअप ऑप्टिमाइज़ करने, इंटरैक्शन में आने वाली रुकावट को कम करने, और पहले लॉन्च से ही असली उपयोगकर्ताओं के लिए रनटाइम की परफ़ॉर्मेंस को बेहतर बनाने में मदद मिलती है.

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

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

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

4. बेसलाइन प्रोफ़ाइल जनरेटर मॉड्यूल सेट अप करें

इंस्ट्रूमेंटेशन टेस्ट क्लास की मदद से बेसलाइन प्रोफ़ाइलें जनरेट की जा सकती हैं. इसके लिए, आपको अपने प्रोजेक्ट में एक नया Gradle मॉड्यूल जोड़ना होगा. इसे अपने प्रोजेक्ट में जोड़ने का सबसे आसान तरीका, Android Studio मॉड्यूल विज़र्ड का इस्तेमाल करना है. यह विज़र्ड, Android Studio Hedgehog या इसके बाद के वर्शन में उपलब्ध है.

प्रोजेक्ट पैनल में, अपने प्रोजेक्ट या मॉड्यूल पर राइट क्लिक करके नई मॉड्यूल विज़र्ड विंडो खोलें. इसके बाद, नया > मॉड्यूल चुनें.

232b04efef485e9c.png

खुलने वाली विंडो में, टेंप्लेट पैनल से बेसलाइन प्रोफ़ाइल जनरेटर चुनें.

b191fe07969e8c26.png

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

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

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

नए मॉड्यूल के बारे में सभी जानकारी तय करने के बाद, मॉड्यूल बनाने के लिए पूरा करें पर क्लिक करें.

मॉड्यूल विज़र्ड की मदद से किए गए बदलाव

मॉड्यूल विज़र्ड आपके प्रोजेक्ट में कई बदलाव करता है.

यह baselineprofile या विज़र्ड में चुना गया नाम वाला Gradle मॉड्यूल जोड़ता है.

यह मॉड्यूल, com.android.test प्लग इन का इस्तेमाल करता है. यह Gradle को आपके ऐप्लिकेशन में शामिल न करने के लिए कहता है, ताकि इसमें सिर्फ़ टेस्टिंग कोड या मानदंड शामिल किए जा सकें. यह androidx.baselineprofile प्लग इन भी लागू करता है, जिससे बेसलाइन प्रोफ़ाइलें अपने-आप जनरेट होती हैं.

विज़र्ड आपके चुने गए टारगेट ऐप्लिकेशन मॉड्यूल में भी बदलाव करता है. खास तौर पर, यह androidx.baselineprofile प्लग इन लागू करता है, androidx.profileinstaller डिपेंडेंसी जोड़ता है, और नए बनाए गए मॉड्यूल build.gradle(.kts) में baselineProfile डिपेंडेंसी जोड़ता है:

plugins {
  id("androidx.baselineprofile")
}

dependencies {
  // ...
  implementation("androidx.profileinstaller:profileinstaller:1.3.0")
  "baselineProfile"(project(mapOf("path" to ":baselineprofile")))
}

androidx.profileinstaller डिपेंडेंसी जोड़ने पर ये काम किए जा सकते हैं:

  • जनरेट की गई बेसलाइन प्रोफ़ाइलों की परफ़ॉर्मेंस में हुई बढ़ोतरी की स्थानीय तौर पर पुष्टि करें.
  • Android 7 (एपीआई लेवल 24) और Android 8 (एपीआई लेवल 26) पर बेसलाइन प्रोफ़ाइलों का इस्तेमाल करें. ये प्रोफ़ाइलें, Cloud प्रोफ़ाइलों के साथ काम नहीं करतीं.
  • उन डिवाइसों पर बेसलाइन प्रोफ़ाइलों का इस्तेमाल करना जिनमें Google Play services नहीं है.

baselineProfile(project(":baselineprofile")) डिपेंडेंसी से Gradle को यह पता चलता है कि जनरेट की गई बेसलाइन प्रोफ़ाइल को किस मॉड्यूल से लेना है.

प्रोजेक्ट सेट होने के बाद, बेसलाइन प्रोफ़ाइल जनरेटर क्लास लिखें.

5. बेसलाइन प्रोफ़ाइल जनरेटर लिखें

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

मॉड्यूल विज़र्ड, एक बुनियादी BaselineProfileGenerator टेस्ट क्लास बनाता है. यह आपके ऐप्लिकेशन के स्टार्टअप के लिए बेसलाइन प्रोफ़ाइल जनरेट कर सकता है. यह इस तरह दिखता है:

@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {

    @get:Rule
    val rule = BaselineProfileRule()

    @Test
    fun generate() {
        rule.collect("com.example.baselineprofiles_codelab") {
            // This block defines the app's critical user journey. This is where you
            // optimize for app startup. You can also navigate and scroll
            // through your most important UI.

            // Start default activity for your app.
            pressHome()
            startActivityAndWait()

            // TODO Write more interactions to optimize advanced journeys of your app.
            // For example:
            // 1. Wait until the content is asynchronously loaded.
            // 2. Scroll the feed content.
            // 3. Navigate to detail screen.

            // Check UiAutomator documentation for more information about how to interact with the app.
            // https://d.android.com/training/testing/other-components/ui-automator
        }
    }
}

इस क्लास में जांच के BaselineProfileRule नियम का इस्तेमाल किया जाता है. साथ ही, इसमें प्रोफ़ाइल जनरेट करने के लिए, जांच करने का एक तरीका शामिल होता है. प्रोफ़ाइल जनरेट करने के लिए एंट्रीपॉइंट, collect() फ़ंक्शन है. इसके लिए, सिर्फ़ दो पैरामीटर की ज़रूरत होती है:

  • packageName: आपके ऐप्लिकेशन का पैकेज.
  • profileBlock: आखिरी LAMBDA पैरामीटर.

profileBlock लैंब्डा फ़ंक्शन में, उन इंटरैक्शन के बारे में बताया जाता है जो आपके ऐप्लिकेशन के सामान्य उपयोगकर्ता सफ़र को कवर करते हैं. लाइब्रेरी, profileBlock को कई बार चलाती है, कॉल की गई क्लास और फ़ंक्शन इकट्ठा करती है, और ऑप्टिमाइज़ किए जाने वाले कोड के साथ डिवाइस पर बेसलाइन प्रोफ़ाइल जनरेट करती है.

डिफ़ॉल्ट रूप से, जनरेटर क्लास में आपके डिफ़ॉल्ट Activity को शुरू करने के लिए इंटरैक्शन होते हैं. साथ ही, यह तब तक इंतज़ार करता है, जब तक आपके ऐप्लिकेशन का पहला फ़्रेम startActivityAndWait() तरीके का इस्तेमाल करके रेंडर नहीं हो जाता.

कस्टम जर्नी की मदद से जनरेटर को बेहतर बनाना

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

हमारे सैंपल ऐप्लिकेशन में, इन सफ़र की पहचान करने के लिए, ये काम करें:

  1. ऐप्लिकेशन शुरू करें. जनरेट की गई क्लास में यह जानकारी पहले से ही शामिल है.
  2. कॉन्टेंट के एसिंक्रोनस रूप से लोड होने तक इंतज़ार करें.
  3. स्नैक की सूची को स्क्रोल करें.
  4. स्नैक की जानकारी वाले पेज पर जाएं.

जनरेटर को बदलकर, नीचे दिए गए स्निपेट में सामान्य गतिविधियों को कवर करने वाले फ़ंक्शन शामिल करें:

// ...
rule.collect("com.example.baselineprofiles_codelab") {
    // This block defines the app's critical user journey. This is where you
    // optimize for app startup. You can also navigate and scroll
    // through your most important UI.

    // Start default activity for your app.
    pressHome()
    startActivityAndWait()

    // TODO Write more interactions to optimize advanced journeys of your app.
    // For example:
    // 1. Wait until the content is asynchronously loaded.
    waitForAsyncContent()
    // 2. Scroll the feed content.
    scrollSnackListJourney()
    // 3. Navigate to detail screen.
    goToSnackDetailJourney()

    // Check UiAutomator documentation for more information about how to interact with the app.
    // https://d.android.com/training/testing/other-components/ui-automator
}
// ...

अब, बताई गई हर यात्रा के लिए इंटरैक्शन लिखें. इसे MacrobenchmarkScope के एक्सटेंशन फ़ंक्शन के तौर पर लिखा जा सकता है, ताकि आपके पास इसके पैरामीटर और फ़ंक्शन का ऐक्सेस हो. इस तरह से लिखने पर, परफ़ॉर्मेंस में हुई बढ़ोतरी की पुष्टि करने के लिए, मानदंडों के साथ इंटरैक्शन का फिर से इस्तेमाल किया जा सकता है.

एसिंक्रोनस कॉन्टेंट का इंतज़ार करना

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

  1. फ़ीड स्नैक्स की सूची ढूंढें.
  2. जब तक सूची में मौजूद कुछ आइटम स्क्रीन पर न दिख जाएं, तब तक इंतज़ार करें.
fun MacrobenchmarkScope.waitForAsyncContent() {
   device.wait(Until.hasObject(By.res("snack_list")), 5_000)
   val contentList = device.findObject(By.res("snack_list"))
   // Wait until a snack collection item within the list is rendered.
   contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
}

स्क्रोल की जा रही सूची

स्क्रॉल की जा सकने वाली स्नैक लिस्ट (scrollSnackListJourney) के लिए, ये इंटरैक्शन अपनाए जा सकते हैं:

  1. स्नैक लिस्ट का यूज़र इंटरफ़ेस (यूआई) एलिमेंट ढूंढें.
  2. सिस्टम नेविगेशन को ट्रिगर न करने के लिए, जेस्चर मार्जिन सेट करें.
  3. सूची को स्क्रोल करें और यूज़र इंटरफ़ेस (यूआई) के सेट होने तक इंतज़ार करें.
fun MacrobenchmarkScope.scrollSnackListJourney() {
   val snackList = device.findObject(By.res("snack_list"))
   // Set gesture margin to avoid triggering gesture navigation.
   snackList.setGestureMargin(device.displayWidth / 5)
   snackList.fling(Direction.DOWN)
   device.waitForIdle()
}

'खरीदारी के अनुभव की जानकारी' पर जाएं

लास्ट जर्नी (goToSnackDetailJourney) इन इंटरैक्शन को लागू करता है:

  1. स्नैक की सूची और ऐसे सभी स्नैक आइटम ढूंढें जिनका इस्तेमाल किया जा सकता है.
  2. सूची में से कोई आइटम चुनें.
  3. आइटम पर क्लिक करें और जानकारी वाली स्क्रीन लोड होने तक इंतज़ार करें. स्नैक की सूची अब स्क्रीन पर नहीं दिखेगी. इसका फ़ायदा लिया जा सकता है.
fun MacrobenchmarkScope.goToSnackDetailJourney() {
    val snackList = device.findObject(By.res("snack_list"))
    val snacks = snackList.findObjects(By.res("snack_item"))
    // Select snack from the list based on running iteration.
    val index = (iteration ?: 0) % snacks.size
    snacks[index].click()
    // Wait until the screen is gone = the detail is shown.
    device.wait(Until.gone(By.res("snack_list")), 5_000)
}

बेसलाइन प्रोफ़ाइल जनरेटर के सभी ज़रूरी इंटरैक्शन को चलाने के लिए, आपको यह तय करना होगा कि यह किस डिवाइस पर चलेगा.

6. जनरेटर को चलाने के लिए कोई डिवाइस तैयार करना

बेसलाइन प्रोफ़ाइल जनरेट करने के लिए, हमारा सुझाव है कि Gradle से मैनेज किया जाने वाला डिवाइस जैसे एम्युलेटर का इस्तेमाल करें या Android 13 (एपीआई 33) या इसके बाद के वर्शन पर काम करने वाले डिवाइस पर.

इस प्रोसेस को दोहराया जा सकता है और बेसलाइन प्रोफ़ाइलें अपने-आप जनरेट होने की सुविधा चालू की जा सकती है. इसके लिए, Gradle मैनेज किए जाने वाले डिवाइसों का इस्तेमाल किया जा सकता है. Gradle से मैनेज किए जाने वाले डिवाइस, आपको Android एम्युलेटर पर टेस्ट चलाने की सुविधा देते हैं. इसके लिए, आपको ऐप्लिकेशन को मैन्युअल तरीके से लॉन्च और बंद करने की ज़रूरत नहीं होती. Gradle से मैनेज किए जाने वाले डिवाइसों के बारे में ज़्यादा जानने के लिए, Gredle से मैनेज किए जाने वाले डिवाइसों की मदद से जांच बढ़ाएं पर जाएं.

Gradle से मैनेज किए जा रहे डिवाइस की जानकारी देने के लिए, :baselineprofile मॉड्यूल build.gradle.kts फ़ाइल में उसकी परिभाषा जोड़ें. इसके लिए, नीचे दिए गए स्निपेट का इस्तेमाल करें:

android {
  // ...

  testOptions.managedDevices.devices {
    create<ManagedVirtualDevice>("pixel6Api31") {
        device = "Pixel 6"
        apiLevel = 31
        systemImageSource = "aosp"
    }
  } 
}

इस मामले में, हम Android 11 (एपीआई लेवल 31) का इस्तेमाल करते हैं और aosp सिस्टम इमेज को रूट किया गया ऐक्सेस कर सकते हैं.

इसके बाद, तय किए गए Gradle मैनेज किए जाने वाले डिवाइस का इस्तेमाल करने के लिए, Baseline Profile Gradle प्लग इन को कॉन्फ़िगर करें. ऐसा करने के लिए, managedDevices प्रॉपर्टी में डिवाइस का नाम जोड़ें और useConnectedDevices को बंद करें. इसके लिए, नीचे दिए गए स्निपेट का इस्तेमाल करें:

android {
  // ...
}

baselineProfile {
   managedDevices += "pixel6Api31"
   useConnectedDevices = false
}

dependencies {
  // ...
}

इसके बाद, बेसलाइन प्रोफ़ाइल जनरेट करें.

7. बेसलाइन प्रोफ़ाइल जनरेट करना

डिवाइस तैयार होने के बाद, बेसलाइन प्रोफ़ाइल बनाई जा सकती है. बेसलाइन प्रोफ़ाइल Gradle प्लग इन, Gradle टास्क बनाता है, ताकि जनरेटर टेस्ट क्लास को चलाने और आपके ऐप्लिकेशन में जनरेट की गई बेसलाइन प्रोफ़ाइल लागू करने की पूरी प्रोसेस को अपने-आप किया जा सके.

नए मॉड्यूल विज़र्ड ने रन कॉन्फ़िगरेशन बनाया है, ताकि सभी ज़रूरी पैरामीटर के साथ Gradle टास्क को तुरंत चलाया जा सके. इसके लिए, आपको टर्मिनल और Android Studio के बीच स्विच करने की ज़रूरत नहीं है

इसे चलाने के लिए, Generate Baseline Profile रन कॉन्फ़िगरेशन ढूंढें और रन बटन 599be5a3531f863b.png पर क्लिक करें.

6911ecf1307a213f.png

यह टास्क, पहले से तय की गई एमुलेटर इमेज को शुरू करता है. BaselineProfileGenerator टेस्ट क्लास से इंटरैक्शन को कई बार चलाएं. इसके बाद, एम्युलेटर को बंद करें और Android Studio को आउटपुट दें.

जनरेटर के काम पूरा होने के बाद, Gradle प्लग इन जनरेट किए गए baseline-prof.txt को आपके टारगेट ऐप्लिकेशन (:app मॉड्यूल) में src/release/generated/baselineProfile/ फ़ोल्डर में अपने-आप डाल देता है.

fa0f52de5d2ce5e8.png

(ज़रूरी नहीं) कमांड-लाइन से जनरेटर चलाना

इसके अलावा, कमांड-लाइन से जनरेटर को चलाया जा सकता है. Gradle के मैनेज किए जा रहे डिवाइस—:app:generateBaselineProfile से बनाए गए टास्क का फ़ायदा लिया जा सकता है. यह कमांड, baselineProfile(project(:baselineProfile)) डिपेंडेंसी से तय किए गए प्रोजेक्ट में सभी टेस्ट चलाता है. इस मॉड्यूल में, परफ़ॉर्मेंस में हुई बढ़ोतरी की बाद में पुष्टि करने के लिए भी मानदंड शामिल होते हैं. इसलिए, ये टेस्ट किसी एमुलेटर पर मानदंड चलाने के ख़िलाफ़ चेतावनी के साथ पूरे नहीं होते.

android
   .testInstrumentationRunnerArguments
   .androidx.benchmark.enabledRules=BaselineProfile

इसके लिए, सभी बेसलाइन प्रोफ़ाइल जनरेटर को नीचे दिए गए इंस्ट्रूमेंटेशन रनर आर्ग्युमेंट की मदद से फ़िल्टर किया जा सकता है. साथ ही, सभी मानदंडों को स्किप किया जा सकता है:

पूरा निर्देश कुछ ऐसा दिखता है:

./gradlew :app:generateBaselineProfile -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile

बुनियादी प्रोफ़ाइल की मदद से अपना ऐप्लिकेशन डिस्ट्रिब्यूट करना

बेसलाइन प्रोफ़ाइल जनरेट हो जाने और आपके ऐप्लिकेशन के सोर्स कोड में कॉपी हो जाने पर, अपने ऐप्लिकेशन का प्रोडक्शन वर्शन उसी तरह बनाएं जैसा कि आप आम तौर पर करते हैं. आपको अपने उपयोगकर्ताओं में बेसलाइन प्रोफ़ाइल बांटने के लिए कुछ और करने की ज़रूरत नहीं है. इन्हें बिल्ड के दौरान Android Gradle प्लग इन चुनता है और आपके AAB या APK में शामिल करता है. इसके बाद, बिल्ड को Google Play पर अपलोड करें.

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

अगले चरण में, यह पुष्टि करने का तरीका बताया गया है कि बेसलाइन प्रोफ़ाइलों की मदद से, ऐप्लिकेशन की परफ़ॉर्मेंस कितनी बेहतर हुई है.

8. (ज़रूरी नहीं) बेसलाइन प्रोफ़ाइल जनरेट करने की सुविधा को पसंद के मुताबिक बनाएं

Baseline Profiles Gradle प्लग इन में, प्रोफ़ाइलों को अपनी ज़रूरतों के हिसाब से जनरेट करने के तरीके को पसंद के मुताबिक बनाने के विकल्प शामिल हैं. बिल्ड स्क्रिप्ट में baselineProfile { } कॉन्फ़िगरेशन ब्लॉक की मदद से, इस व्यवहार को बदला जा सकता है.

:baselineprofile मॉड्यूल में मौजूद कॉन्फ़िगरेशन ब्लॉक से इस बात पर असर पड़ता है कि managedDevices जोड़ने की संभावना वाले जनरेटर को कैसे चलाया जाए. साथ ही, यह तय किया जा सकता है कि useConnectedDevices को मैनेज करना है या Gradle से मैनेज किए जाने वाले डिवाइसों को.

:app टारगेट मॉड्यूल में मौजूद कॉन्फ़िगरेशन ब्लॉक से यह तय होता है कि प्रोफ़ाइलें कहां सेव की जाती हैं या उन्हें कैसे जनरेट किया जाता है. इन पैरामीटर में बदलाव किया जा सकता है:

  • automaticGenerationDuringBuild: यह सेटिंग चालू होने पर, प्रोडक्शन रिलीज़ बिल्ड बनाते समय बेसलाइन प्रोफ़ाइल जनरेट की जा सकती है. यह सुविधा, ऐप्लिकेशन को शिप करने से पहले सीआई पर बिल्ड करते समय मददगार होती है.
  • saveInSrc: इससे पता चलता है कि जनरेट की गई बेसलाइन प्रोफ़ाइलें src/ फ़ोल्डर में सेव की गई हैं या नहीं. इसके अलावा, :baselineprofile बिल्ड फ़ोल्डर से भी फ़ाइल को ऐक्सेस किया जा सकता है.
  • baselineProfileOutputDir: इससे यह तय होता है कि जनरेट की गई बेसलाइन प्रोफ़ाइलों को कहां सेव करना है.
  • mergeIntoMain: डिफ़ॉल्ट रूप से, हर बिल्ड वैरिएंट (प्रॉडक्ट फ़्लेवर और बिल्ड टाइप) के लिए बेसलाइन प्रोफ़ाइल जनरेट होती हैं. अगर आपको सभी प्रोफ़ाइलों को src/main में मर्ज करना है, तो इस फ़्लैग को चालू करें.
  • filter: जनरेट की गई बेसलाइन प्रोफ़ाइल में, शामिल करने या बाहर रखने के लिए क्लास या तरीकों को फ़िल्टर किया जा सकता है. यह उन लाइब्रेरी डेवलपर के लिए मददगार हो सकता है जिन्हें सिर्फ़ लाइब्रेरी का कोड शामिल करना है.

9. ऐप्लिकेशन के शुरू होने की परफ़ॉर्मेंस में हुए सुधारों की पुष्टि करना

बेसलाइन प्रोफ़ाइल जनरेट करने और उसे अपने ऐप्लिकेशन में जोड़ने के बाद, पुष्टि करें कि इसका असर आपके ऐप्लिकेशन की परफ़ॉर्मेंस पर ठीक से हो रहा है.

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

क्लास इस तरह दिखती है:

@RunWith(AndroidJUnit4::class)
@LargeTest
class StartupBenchmarks {

    @get:Rule
    val rule = MacrobenchmarkRule()

    @Test
    fun startupCompilationNone() =
        benchmark(CompilationMode.None())

    @Test
    fun startupCompilationBaselineProfiles() =
        benchmark(CompilationMode.Partial(BaselineProfileMode.Require))

    private fun benchmark(compilationMode: CompilationMode) {
        rule.measureRepeated(
            packageName = "com.example.baselineprofiles_codelab",
            metrics = listOf(StartupTimingMetric()),
            compilationMode = compilationMode,
            startupMode = StartupMode.COLD,
            iterations = 10,
            setupBlock = {
                pressHome()
            },
            measureBlock = {
                startActivityAndWait()

                // TODO Add interactions to wait for when your app is fully drawn.
                // The app is fully drawn when Activity.reportFullyDrawn is called.
                // For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
                // from the AndroidX Activity library.

                // Check the UiAutomator documentation for more information on how to
                // interact with the app.
                // https://d.android.com/training/testing/other-components/ui-automator
            }
        )
    }
}

यह MacrobenchmarkRule का इस्तेमाल करता है, जो आपके ऐप्लिकेशन के लिए मानदंड चलाने और परफ़ॉर्मेंस मेट्रिक इकट्ठा करने में सक्षम है. बेंचमार्क लिखने के लिए, नियम में मौजूद measureRepeated फ़ंक्शन का इस्तेमाल किया जाता है.

इसके लिए कई पैरामीटर ज़रूरी हैं:

  • packageName: किस ऐप्लिकेशन को मेज़र करना है.
  • metrics: मानदंड के दौरान, आपको किस तरह की जानकारी को मेज़र करना है.
  • iterations: बेंचमार्क कितनी बार दोहराया जाता है.
  • startupMode: मानदंड की शुरुआत पर, आपको अपना ऐप्लिकेशन कैसे शुरू करना है.
  • setupBlock: मेज़र करने से पहले, आपके ऐप्लिकेशन के साथ क्या इंटरैक्शन होने चाहिए.
  • measureBlock: आपके ऐप्लिकेशन के साथ होने वाले इंटरैक्शन जिन्हें आप मानदंड के दौरान मेज़र करना चाहते हैं.

टेस्ट क्लास में दो टेस्ट भी होते हैं: startupCompilationeNone() और startupCompilationBaselineProfiles(). ये अलग-अलग compilationMode के साथ benchmark() फ़ंक्शन को कॉल करते हैं.

CompilationMode

CompilationMode पैरामीटर से यह तय होता है कि ऐप्लिकेशन को मशीन कोड में पहले से कैसे कंपाइल किया जाता है. इसमें ये विकल्प होते हैं:

  • DEFAULT: उपलब्ध होने पर, यह बेसलाइन प्रोफ़ाइल का इस्तेमाल करके ऐप्लिकेशन को कुछ हद तक पहले से कंपाइल करता है. इसका इस्तेमाल तब किया जाता है, जब कोई compilationMode पैरामीटर लागू न किया गया हो.
  • None(): यह ऐप्लिकेशन को इकट्ठा करने की प्रोसेस की स्थिति को रीसेट करता है और ऐप्लिकेशन को पहले से कंपाइल नहीं करता है. हालांकि, ऐप्लिकेशन को चलाने के दौरान, जस्ट-इन-टाइम कंपाइलेशन (JIT) अब भी चालू रहता है.
  • Partial(): ऐप्लिकेशन को बेसलाइन प्रोफ़ाइलों या वॉर्म अप रन या दोनों के साथ पहले से कंपाइल करता है.
  • Full(): पूरे ऐप्लिकेशन कोड को पहले से इकट्ठा करता है. Android 6 (एपीआई 23) और इससे पहले के वर्शन पर, यह ही एक विकल्प है.

अगर आपको अपने ऐप्लिकेशन की परफ़ॉर्मेंस को ऑप्टिमाइज़ करना है, तो DEFAULT कंपाइलेशन मोड चुनें. ऐसा इसलिए, क्योंकि इस मोड में ऐप्लिकेशन की परफ़ॉर्मेंस, Google Play से इंस्टॉल किए गए ऐप्लिकेशन की परफ़ॉर्मेंस जैसी ही होती है. अगर आपको बेसलाइन प्रोफ़ाइलों से मिलने वाले परफ़ॉर्मेंस फ़ायदों की तुलना करनी है, तो कंपाइलेशन मोड None और Partial के नतीजों की तुलना करें.

कॉन्टेंट का इंतज़ार करने के लिए मानदंड में बदलाव करना

बेंचमार्क, आपके ऐप्लिकेशन के साथ इंटरैक्शन लिखकर, बेसलाइन प्रोफ़ाइल जनरेटर की तरह ही लिखे जाते हैं. डिफ़ॉल्ट रूप से, बनाए गए बेंचमार्क सिर्फ़ पहले फ़्रेम के रेंडर होने का इंतज़ार करते हैं—जैसा कि BaselineProfileGenerator ने किया था—इसलिए, हमारा सुझाव है कि असाइनोक्रोनस कॉन्टेंट के इंतज़ार के लिए इसे बेहतर बनाएं.

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

// ...
measureBlock = {
   startActivityAndWait()

   // The app is fully drawn when Activity.reportFullyDrawn is called.
   // For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
   // from the AndroidX Activity library.
   waitForAsyncContent() // <------- Added to wait for async content.

   // Check the UiAutomator documentation for more information on how to
   // interact with the app.
   // https://d.android.com/training/testing/other-components/ui-automator
}

बेंचमार्क चलाना

आप मानदंडों को उसी तरह चला सकते हैं जैसे आप इंस्ट्रुमेंट्ड टेस्ट करते हैं. टेस्ट फ़ंक्शन या उसके बगल में मौजूद गटर आइकॉन की मदद से, पूरी क्लास को चलाया जा सकता है.

587b04d1a76d1e9d.png

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

94e0da86b6f399d5.png

बेंचमार्क चलाने के बाद, आपका ऐप्लिकेशन फिर से बनाया जाता है. इसके बाद, वह आपके बेंचमार्क चलाता है. आपके तय किए गए iterations के आधार पर, बेंचमार्क आपके ऐप्लिकेशन को कई बार शुरू, बंद, और फिर से इंस्टॉल करते हैं.

बेंचमार्क पूरा होने के बाद, आपको Android Studio के आउटपुट में समय दिखेगा. इसकी जानकारी यहां दिए गए स्क्रीनशॉट में दी गई है:

282f90d5f6ff5196.png

स्क्रीनशॉट से पता चलता है कि हर CompilationMode के लिए, ऐप्लिकेशन के शुरू होने में लगने वाला समय अलग-अलग है. मीडियन वैल्यू, नीचे दी गई टेबल में दिखाई गई हैं:

timeToInitialDisplay [ms]

timeToFullDisplay [ms]

कोई नहीं

202.2

818.8

BaselineProfiles

193.7

637.9

सुधार

4%

28%

timeToFullDisplay के लिए कंपाइलेशन मोड के बीच का अंतर 180 मिलीसेकंड है. सिर्फ़ बेसलाइन प्रोफ़ाइल होने से,इसमें ~28% की बढ़ोतरी हुई है. CompilationNone की परफ़ॉर्मेंस खराब होती है, क्योंकि ऐप्लिकेशन के स्टार्टअप के दौरान डिवाइस को ज़्यादातर JIT कंपाइलेशन करना पड़ता है. CompilationBaselineProfiles की परफ़ॉर्मेंस बेहतर होती है, क्योंकि Baseline Profiles AOT के साथ कुछ हिस्से को कंपाइल करने की सुविधा, उस कोड को कंपाइल करती है जिसका इस्तेमाल उपयोगकर्ता सबसे ज़्यादा कर सकता है. साथ ही, यह ज़रूरी नहीं है कि ग़ैर-ज़रूरी कोड को पहले से कंपाइल किया जाए, ताकि उसे तुरंत लोड न करना पड़े.

10. (ज़रूरी नहीं) स्क्रोल करने की परफ़ॉर्मेंस में हुए सुधार की पुष्टि करना

पिछले चरण की तरह ही, स्क्रोलिंग की परफ़ॉर्मेंस को मेज़र और पुष्टि की जा सकती है. सबसे पहले, मानदंड के नियम और जांच के दो तरीकों के साथ ScrollBenchmarks टेस्ट क्लास बनाएं, जो अलग-अलग कंपाइलेशन मोड का इस्तेमाल करती हैं:

@LargeTest
@RunWith(AndroidJUnit4::class)
class ScrollBenchmarks {

   @get:Rule
   val rule = MacrobenchmarkRule()

   @Test
   fun scrollCompilationNone() = scroll(CompilationMode.None())

   @Test
   fun scrollCompilationBaselineProfiles() = scroll(CompilationMode.Partial())

   private fun scroll(compilationMode: CompilationMode) {
       // TODO implement
   }
}

scroll तरीके में, ज़रूरी पैरामीटर के साथ measureRepeated फ़ंक्शन का इस्तेमाल करें. metrics पैरामीटर के लिए, FrameTimingMetric का इस्तेमाल करें. इससे यह पता चलता है कि यूज़र इंटरफ़ेस (यूआई) फ़्रेम बनाने में कितना समय लगता है:

private fun scroll(compilationMode: CompilationMode) {
   rule.measureRepeated(
       packageName = "com.example.baselineprofiles_codelab",
       metrics = listOf(FrameTimingMetric()),
       compilationMode = compilationMode,
       startupMode = StartupMode.WARM,
       iterations = 10,
       setupBlock = {
           // TODO implement
       },
       measureBlock = {
           // TODO implement
       }
   )
}

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

private fun scroll(compilationMode: CompilationMode) {
   rule.measureRepeated(
       packageName = "com.example.baselineprofiles_codelab",
       metrics = listOf(FrameTimingMetric()),
       compilationMode = compilationMode,
       startupMode = StartupMode.WARM,
       iterations = 10,
       setupBlock = {
           pressHome()
           startActivityAndWait()
       },
       measureBlock = {
           waitForAsyncContent()
           scrollSnackListJourney()
       }
   )
}

बेंचमार्क तैयार होने के बाद, इसे पहले की तरह चलाया जा सकता है, ताकि आपको नीचे दिए गए स्क्रीनशॉट में दिखाए गए नतीजे मिल सकें:

84aa99247226fc3a.png

FrameTimingMetric, फ़्रेम की अवधि को मिलीसेकंड (frameDurationCpuMs) में 50वें, 90वें, 95वें, और 99वें पर्सेंटाइल में दिखाता है. Android 12 (एपीआई लेवल 31) और उसके बाद के वर्शन पर, यह भी दिखाता है कि आपके फ़्रेम, तय सीमा (frameOverrunMs) से कितना ज़्यादा समय तक हैं. वैल्यू नेगेटिव हो सकती है. इसका मतलब है कि फ़्रेम बनाने में ज़्यादा समय बचा है.

नतीजों से यह देखा जा सकता है कि CompilationBaselineProfiles के फ़्रेम की औसत अवधि औसतन 2 मि॰से॰ तक कम है, जो कि शायद उपयोगकर्ताओं को न दिखे. हालांकि, अन्य पर्सेंटाइल के लिए नतीजे ज़्यादा साफ़ तौर पर दिखते हैं. P99 के लिए, यह फ़र्क़ 43.5 मिलीसेकंड है. यह 90 FPS पर काम करने वाले डिवाइस पर, स्किप किए गए तीन से ज़्यादा फ़्रेम के बराबर है. उदाहरण के लिए, Pixel 6 के लिए किसी फ़्रेम को रेंडर करने में 1000 मि॰से॰ / 90 FPS = ~11 मि॰से॰ ज़्यादा से ज़्यादा समय लगता है.

11. बधाई हो

बधाई हो, आपने यह कोडलैब पूरा कर लिया है. साथ ही, बेसलाइन प्रोफ़ाइलों की मदद से अपने ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाया है!

अन्य संसाधन

यहां दिए गए अन्य संसाधन देखें:

रेफ़रंस दस्तावेज़