অ্যাপ-চালিত প্রোফাইলিং

এই পৃষ্ঠায় দেখানো হয়েছে কীভাবে ProfilingManager API ব্যবহার করে একটি সিস্টেম ট্রেস রেকর্ড করতে হয়।

ProfilingManager অন্যান্য প্রোফাইল টাইপও রেকর্ড করতে পারে। এই প্রক্রিয়াটি একটি সিস্টেম ট্রেস রেকর্ড করার মতোই, তবে প্রতিটি টাইপের জন্য আলাদা বিল্ডার ব্যবহৃত হয়। সমর্থিত প্রোফাইল এবং তাদের বিল্ডারগুলো হলো:

  • সিস্টেম ট্রেস: SystemTraceRequestBuilder ব্যবহার করে রেকর্ড করা হয়, যা লেটেন্সি বিশ্লেষণ এবং সাধারণ পারফরম্যান্স ডিবাগিংয়ের জন্য উপযোগী।

  • হিপ ডাম্প: JavaHeapDumpRequestBuilder ব্যবহার করে রেকর্ড করা হয়, যা মেমরি লিক শনাক্তকরণ এবং অপ্টিমাইজেশনের জন্য সহায়ক।

  • হিপ প্রোফাইল: HeapProfileRequestBuilder ব্যবহার করে রেকর্ড করা হয়, যা মেমরি অপ্টিমাইজেশনের জন্য উপযোগী।

  • কল স্ট্যাক প্রোফাইল: StackSamplingRequestBuilder ব্যবহার করে রেকর্ড করা হয়, যা কোড এক্সিকিউশন এবং লেটেন্সি বিশ্লেষণ বুঝতে সহায়ক।

নির্ভরতা যোগ করুন

ProfilingManager API-এর সর্বোত্তম অভিজ্ঞতার জন্য, আপনার build.gradle.kts ফাইলে নিম্নলিখিত Jetpack লাইব্রেরিগুলো যোগ করুন।

কোটলিন

   dependencies {
       implementation("androidx.tracing:tracing:1.3.0")
       implementation("androidx.core:core:1.18.0")
   }
   

গ্রুভি

   dependencies {
       implementation 'androidx.tracing:tracing:1.3.0'
       implementation 'androidx.core:core:1.18.0'
   }
   

সিস্টেম ট্রেস রেকর্ড করুন

প্রয়োজনীয় ডিপেন্ডেন্সিগুলো যোগ করার পর, একটি সিস্টেম ট্রেস রেকর্ড করতে নিম্নলিখিত কোডটি ব্যবহার করুন। এই উদাহরণটি একটি Activity মধ্যে প্রোফাইলিং সেশন শুরু ও পরিচালনা করার জন্য একটি প্রাথমিক সেটআপ দেখায়।

কোটলিন

@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
fun sampleRecordSystemTrace() {
    val mainExecutor: Executor =
        Dispatchers.IO.asExecutor() // Your choice of executor for the callback to occur on.
    val resultCallback = Consumer<ProfilingResult> { profilingResult ->
        if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
            Log.d(
                "ProfileTest",
                "Received profiling result file=" + profilingResult.resultFilePath
            )
        } else {
            Log.e(
                "ProfileTest",
                "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage
            )
        }
    }
    val stopSignal = CancellationSignal()

    val requestBuilder = SystemTraceRequestBuilder()
    requestBuilder.setCancellationSignal(stopSignal)
    requestBuilder.setTag("FOO") // Caller supplied tag for identification
    requestBuilder.setDurationMs(60000)
    requestBuilder.setBufferFillPolicy(BufferFillPolicy.RING_BUFFER)
    requestBuilder.setBufferSizeKb(20971520)
    requestProfiling(applicationContext, requestBuilder.build(), mainExecutor, resultCallback)

    // Wait some time for profiling to start.

    Trace.beginSection("MyApp:HeavyOperation")
    heavyOperation()
    Trace.endSection()

    // Once the interesting code section is profiled, stop profile
    stopSignal.cancel()
}

fun heavyOperation() {
    // Computations you want to profile
}

জাভা

void heavyOperation() {
  // Computations you want to profile
}

void sampleRecordSystemTrace() {
  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());
          }
        }
      };
  CancellationSignal stopSignal = new CancellationSignal();

  SystemTraceRequestBuilder requestBuilder = new SystemTraceRequestBuilder();
  requestBuilder.setCancellationSignal(stopSignal);
  requestBuilder.setTag("FOO");
  requestBuilder.setDurationMs(60000);
  requestBuilder.setBufferFillPolicy(BufferFillPolicy.RING_BUFFER);
  requestBuilder.setBufferSizeKb(20971520);
  Profiling.requestProfiling(getApplicationContext(), requestBuilder.build(), mainExecutor,
      resultCallback);

  // Wait some time for profiling to start.

  Trace.beginSection("MyApp:HeavyOperation");
  heavyOperation();
  Trace.endSection();

  // Once the interesting code section is profiled, stop profile
  stopSignal.cancel();
}

নমুনা কোডটি নিম্নলিখিত ধাপগুলো অনুসরণ করে প্রোফাইলিং সেশনটি সেট আপ এবং পরিচালনা করে:

  1. এক্সিকিউটর সেট আপ করুন। যে থ্রেডটি প্রোফাইলিংয়ের ফলাফল গ্রহণ করবে, তা নির্ধারণ করতে একটি Executor তৈরি করুন। প্রোফাইলিং ব্যাকগ্রাউন্ডে সম্পন্ন হয়। যদি আপনি পরবর্তীতে কলব্যাকে আরও প্রসেসিং যোগ করেন, তবে একটি নন-ইউআই থ্রেড এক্সিকিউটর ব্যবহার করলে অ্যাপ্লিকেশন নট রেসপন্ডিং (ANR) ত্রুটি প্রতিরোধ করা যায়।

  2. প্রোফাইলিং ফলাফল পরিচালনা করুন। একটি Consumer<ProfilingResult> অবজেক্ট তৈরি করুন। সিস্টেম এই অবজেক্টটি ব্যবহার করে ProfilingManager থেকে আপনার অ্যাপে প্রোফাইলিং ফলাফল ফেরত পাঠায়।

  3. প্রোফাইলিং অনুরোধটি তৈরি করুন। আপনার প্রোফাইলিং সেশন সেট আপ করার জন্য একটি SystemTraceRequestBuilder তৈরি করুন। এই বিল্ডারটি আপনাকে ProfilingManager ট্রেস সেটিংস কাস্টমাইজ করার সুযোগ দেয়। বিল্ডারটি কাস্টমাইজ করা ঐচ্ছিক; যদি আপনি তা না করেন, তবে সিস্টেম ডিফল্ট সেটিংস ব্যবহার করবে।

    • একটি ট্যাগ নির্ধারণ করুন। ট্রেসের নামে ট্যাগ যোগ করতে setTag() ব্যবহার করুন। এই ট্যাগটি আপনাকে ট্রেসটি শনাক্ত করতে সাহায্য করে।
    • ঐচ্ছিক: সময়কাল নির্ধারণ করুন। কতক্ষণ ধরে প্রোফাইল চলবে তা মিলিসেকেন্ডে নির্দিষ্ট করতে setDurationMs() ব্যবহার করুন। উদাহরণস্বরূপ, 60000 একটি ৬০-সেকেন্ডের ট্রেস সেট করে। নির্দিষ্ট সময়কালের আগে যদি CancellationSignal ট্রিগার না হয়, তাহলে ট্রেসটি স্বয়ংক্রিয়ভাবে শেষ হয়ে যাবে।
    • একটি বাফার পলিসি বেছে নিন। ট্রেস ডেটা কীভাবে সংরক্ষিত হবে তা নির্ধারণ করতে setBufferFillPolicy() ব্যবহার করুন। BufferFillPolicy.RING_BUFFER অর্থ হলো, যখন বাফার পূর্ণ হয়ে যায়, তখন নতুন ডেটা সবচেয়ে পুরোনো ডেটাকে ওভাররাইট করে, যার ফলে সাম্প্রতিক কার্যকলাপের একটি অবিচ্ছিন্ন রেকর্ড বজায় থাকে।
    • একটি বাফার সাইজ সেট করুন। ট্রেসিংয়ের জন্য একটি বাফার সাইজ নির্দিষ্ট করতে setBufferSizeKb() ব্যবহার করুন, যা দিয়ে আপনি আউটপুট ট্রেস ফাইলের সাইজ নিয়ন্ত্রণ করতে পারবেন।
  4. ঐচ্ছিক: সেশনের জীবনচক্র পরিচালনা করুন। একটি CancellationSignal তৈরি করুন। এই অবজেক্টটি আপনাকে যখন খুশি প্রোফাইলিং সেশন বন্ধ করার সুযোগ দেয়, যার ফলে আপনি এর দৈর্ঘ্যের উপর সুনির্দিষ্ট নিয়ন্ত্রণ রাখতে পারেন।

  5. শুরু করুন এবং ফলাফল গ্রহণ করুন। আপনি যখন requestProfiling() কল করেন, ProfilingManager ব্যাকগ্রাউন্ডে একটি প্রোফাইলিং সেশন শুরু করে। প্রোফাইলিং সম্পন্ন হলে, এটি আপনার resultCallback#accept মেথডে ProfilingResult ফাইলটি পাঠিয়ে দেয়। প্রোফাইলিং সফলভাবে শেষ হলে, ProfilingResult ProfilingResult#getResultFilePath এর মাধ্যমে আপনার ডিভাইসে ট্রেসটি যেখানে সেভ করা হয়েছে, সেই পাথটি পাওয়া যায়। আপনি এই ফাইলটি প্রোগ্রাম্যাটিকভাবে পেতে পারেন অথবা, লোকাল প্রোফাইলিংয়ের জন্য, আপনার কম্পিউটার থেকে adb pull <trace_path> চালাতে পারেন।

  6. কাস্টম ট্রেস পয়েন্ট যোগ করুন। আপনি আপনার অ্যাপের কোডে কাস্টম ট্রেস পয়েন্ট যোগ করতে পারেন। পূর্ববর্তী কোড উদাহরণে, Trace.beginSection() এবং Trace.endSection() ব্যবহার করে MyApp:HeavyOperation নামের একটি ট্রেস স্লাইস যোগ করা হয়েছে। এই কাস্টম স্লাইসটি তৈরি হওয়া প্রোফাইলে প্রদর্শিত হয় এবং আপনার অ্যাপের ভেতরের নির্দিষ্ট অপারেশনগুলোকে হাইলাইট করে।