ट्रिगर के आधार पर प्रोफ़ाइलिंग

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

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

पुराना डेटा कैप्चर करना

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

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

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

ट्रिगर-आधारित कैप्चर का इस्तेमाल क्यों करना चाहिए?

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

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

ट्रिगर सेट अप करना

यहां दिए गए कोड में, TRIGGER_TYPE_APP_FULLY_DRAWN ट्रिगर के लिए रजिस्टर करने और उस पर अनुरोध संख्या सीमित करने की सुविधा लागू करने का तरीका बताया गया है.

Kotlin

fun recordWithTrigger() {
    val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java)

    val triggers = ArrayList<ProfilingTrigger>()

    val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN)
        .setRateLimitingPeriodHours(1)

    triggers.add(triggerBuilder.build())

    val mainExecutor: Executor = Executors.newSingleThreadExecutor()

    val resultCallback = Consumer<ProfilingResult> { profilingResult ->
        if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
            Log.d(
                "ProfileTest",
                "Received profiling result file=" + profilingResult.resultFilePath
            )
            setupProfileUploadWorker(profilingResult.resultFilePath)
        } else {
            Log.e(
                "ProfileTest",
                "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage
            )
        }
    }

    profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback)
    profilingManager.addProfilingTriggers(triggers)

}

Java

public void recordWithTrigger() {
  ProfilingManager profilingManager = getApplicationContext().getSystemService(
      ProfilingManager.class);
  List<ProfilingTrigger> triggers = new ArrayList<>();
  ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder(
      ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN);
  triggerBuilder.setRateLimitingPeriodHours(1);
  triggers.add(triggerBuilder.build());

  Executor mainExecutor = Executors.newSingleThreadExecutor();
  Consumer<ProfilingResult> resultCallback =
      new Consumer<ProfilingResult>() {
        @Override
        public void accept(ProfilingResult profilingResult) {
          if (profilingResult.getErrorCode() == ProfilingResult.ERROR_NONE) {
            Log.d(
                "ProfileTest",
                "Received profiling result file=" + profilingResult.getResultFilePath());
            setupProfileUploadWorker(profilingResult.getResultFilePath());
          } else {
            Log.e(
                "ProfileTest",
                "Profiling failed errorcode="
                    + profilingResult.getErrorCode()
                    + " errormsg="
                    + profilingResult.getErrorMessage());
          }
        }
      };
  profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback);
  profilingManager.addProfilingTriggers(triggers);

}

कोड ये चरण पूरे करता है:

  1. मैनेजर वापस लाएं: ProfilingManager सेवा को वापस लाता है.
  2. ट्रिगर तय करें: TRIGGER_TYPE_APP_FULLY_DRAWN के लिए ProfilingTrigger बनाता है. यह इवेंट तब होता है, जब ऐप्लिकेशन यह रिपोर्ट करता है कि उसने स्टार्टअप पूरा कर लिया है और वह इंटरैक्टिव है.
  3. अनुरोध संख्या सीमित करना: इस विकल्प को चुनने पर, इस ट्रिगर (setRateLimitingPeriodHours(1)) के लिए एक घंटे की समयसीमा लागू होती है. इससे ऐप्लिकेशन, हर घंटे एक से ज़्यादा स्टार्टअप प्रोफ़ाइल रिकॉर्ड नहीं कर पाता.
  4. लिसनर को रजिस्टर करें: यह registerForAllProfilingResults को कॉल करता है, ताकि नतीजे को हैंडल करने वाले कॉलबैक को तय किया जा सके. इस कॉलबैक को, getResultFilePath() के ज़रिए सेव की गई प्रोफ़ाइल का पाथ मिलता है.
  5. ट्रिगर जोड़ें: addProfilingTriggers का इस्तेमाल करके, ProfilingManager के साथ ट्रिगर की सूची को रजिस्टर करता है.
  6. इवेंट ट्रिगर करना: reportFullyDrawn() को कॉल करता है, जो सिस्टम को TRIGGER_TYPE_APP_FULLY_DRAWN इवेंट भेजता है. इससे प्रोफ़ाइल कलेक्शन ट्रिगर होता है. इसके लिए, यह ज़रूरी है कि सिस्टम बैकग्राउंड ट्रेस चल रहा हो और अनुरोध संख्या सीमित करने का कोटा उपलब्ध हो. यह चरण ज़रूरी नहीं है. इसमें एंड-टू-एंड फ़्लो दिखाया गया है, क्योंकि इस ट्रिगर के लिए आपके ऐप्लिकेशन को reportFullyDrawn() को कॉल करना होगा.

ट्रेस वापस पाना

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

profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>

एडीबी का इस्तेमाल करके, फ़ाइल को पुल किया जा सकता है. उदाहरण के लिए, एडीबी का इस्तेमाल करके कोड के उदाहरण से कैप्चर किए गए सिस्टम ट्रेस को पुल करने के लिए, यह कुछ ऐसा दिख सकता है:

adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace

इन ट्रेस को विज़ुअलाइज़ करने के बारे में जानकारी पाने के लिए, प्रोफ़ाइलिंग डेटा को वापस पाना और उसका विश्लेषण करना लेख पढ़ें.

बैकग्राउंड ट्रेसिंग की सुविधा कैसे काम करती है

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

प्रोफ़ाइल सेव होने के बाद, सिस्टम registerForAllProfilingResults को दिए गए कॉलबैक का इस्तेमाल करके, आपके ऐप्लिकेशन को सूचना देता है. यह कॉलबैक, कैप्चर की गई प्रोफ़ाइल का पाथ उपलब्ध कराता है. इसे ProfilingResult#getResultFilePath() को कॉल करके ऐक्सेस किया जा सकता है.

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

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

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

ट्रिगर के हिसाब से, अनुरोध संख्या सीमित करने की सुविधा लागू करना

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

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

ट्रिगर को डिवाइस पर डीबग करना

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

adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>

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

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