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

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

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

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

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

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

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>

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

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