ব্যবহারিক কর্মক্ষমতা ডিবাগিং উদাহরণ: ANR

এই বিভাগটি দেখানো হয়েছে কিভাবে ProfilingManager ব্যবহার করে একটি অ্যাপ্লিকেশন নট রেসপন্ডিং (ANR) ডিবাগ করতে হয়, একটি উদাহরণ ট্রেস সহ।

ANR সংগ্রহের জন্য অ্যাপ সেট আপ করুন

আপনার অ্যাপে একটি ANR ট্রিগার সেট আপ করে শুরু করুন:

public void addANRTrigger() {
  ProfilingManager profilingManager = getApplicationContext().getSystemService(
      ProfilingManager.class);
  List<ProfilingTrigger> triggers = new ArrayList<>();
  ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder(
      ProfilingTrigger.TRIGGER_TYPE_ANR);
  triggers.add(triggerBuilder.build());
  Executor mainExecutor = Executors.newSingleThreadExecutor();
  Consumer<ProfilingResult> resultCallback =
      profilingResult -> {
        // Handle uploading trace to your back-end
      };
  profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback);
  profilingManager.addProfilingTriggers(triggers);
}

একটি ANR ট্রেস ক্যাপচার এবং আপলোড করার পরে, এটি Perfetto UI তে খুলুন।

ট্রেস বিশ্লেষণ করুন

যেহেতু ANR ট্রেসটি ট্রিগার করেছিল, আপনি জানেন যে সিস্টেমটি যখন আপনার অ্যাপের প্রধান থ্রেডে প্রতিক্রিয়াহীনতা সনাক্ত করে তখন ট্রেসটি শেষ হয়ে যায়। চিত্র 1 দেখায় যে কীভাবে আপনার অ্যাপের প্রধান থ্রেডে নেভিগেট করবেন যা UI এর মধ্যে সেই অনুযায়ী ট্যাগ করা হয়েছে।

অ্যাপের মূল থ্রেডে পারফেটো UI নেভিগেশন।
চিত্র ১. অ্যাপের মূল থ্রেডে নেভিগেশন।

চিত্র ২-এ দেখানো হিসাবে, ট্রেসের শেষ অংশটি ANR-এর টাইমস্ট্যাম্পের সাথে মিলে যায়।

Perfetto UI একটি ট্রেসের শেষ দেখাচ্ছে, ANR ট্রিগার অবস্থান হাইলাইট করছে।
চিত্র ২। ANR ট্রিগারের অবস্থান।

ট্রেসটি ANR হওয়ার সময় অ্যাপটি যে অপারেশনগুলি চালাচ্ছিল তাও দেখায়। বিশেষ করে, অ্যাপটি handleNetworkResponse ট্রেস স্লাইসে কোড চালাত। এই স্লাইসটি MyApp:SubmitButton স্লাইসের ভিতরে ছিল। এটি CPU সময় 1.48 সেকেন্ড ব্যবহার করেছিল (চিত্র 3)।

ANR-এর সময় হ্যান্ডেলনেটওয়ার্করেসপন্স এক্সিকিউশন দ্বারা ব্যবহৃত CPU সময় দেখানো Perfetto UI।
চিত্র ৩. ANR-এর সময় সম্পাদন।

যদি আপনি ডিবাগিংয়ের জন্য ANR-এর মুহূর্তে শুধুমাত্র স্ট্যাক ট্রেসের উপর নির্ভর করেন, তাহলে আপনি ভুলভাবে ANR সম্পূর্ণরূপে handleNetworkResponse ট্রেস স্লাইসের মধ্যে চলমান কোডের সাথে যুক্ত করতে পারেন যা প্রোফাইল রেকর্ডিং শেষ হওয়ার পরেও শেষ হয়নি। তবে, ANR নিজে থেকে ট্রিগার করার জন্য 1.48 সেকেন্ড যথেষ্ট নয়, যদিও এটি একটি ব্যয়বহুল অপারেশন। এই পদ্ধতির আগে মূল থ্রেডটি কী ব্লক করেছিল তা বুঝতে আপনাকে আরও পিছনে ফিরে তাকাতে হবে।

ANR এর কারণ অনুসন্ধানের জন্য একটি সূচনা বিন্দু বের করার জন্য, আমরা UI থ্রেড দ্বারা তৈরি শেষ ফ্রেমটি দেখা শুরু করি যা Choreographer#doFrame 551275 স্লাইসের সাথে সম্পর্কিত এবং ANR-এ শেষ হওয়া MyApp:SubmitButton স্লাইসটি শুরু করার আগে বিলম্বের কোনও বড় কারণ নেই (চিত্র 4)।

পারফেটো UI ANR-এর আগে UI থ্রেড দ্বারা রেন্ডার করা শেষ ফ্রেমটি দেখাচ্ছে।
চিত্র ৪। ANR-এর আগে তৈরি হওয়া শেষ অ্যাপ ফ্রেম।

ব্লকেজ বুঝতে, জুম কমান এবং সম্পূর্ণ MyApp:SubmitButton স্লাইসটি পরীক্ষা করুন। চিত্র ৪-এ দেখানো থ্রেডের অবস্থায় আপনি একটি গুরুত্বপূর্ণ বিশদ লক্ষ্য করবেন: থ্রেডটি ৭৫% সময় (৬.৭ সেকেন্ড) Sleeping অবস্থায় এবং মাত্র ২৪% সময় Running অবস্থায় ব্যয় করেছে।

Perfetto UI একটি অপারেশনের সময় থ্রেডের অবস্থা দেখায়, যা ৭৫% ঘুমন্ত সময় এবং ২৪% চলমান সময় হাইলাইট করে।
চিত্র ৫। `MyApp:SubmitButton` অপারেশনের সময় থ্রেডের অবস্থা।

এটি ইঙ্গিত দেয় যে ANR-এর প্রাথমিক কারণ গণনা নয়, অপেক্ষা ছিল। একটি প্যাটার্ন খুঁজে পেতে পৃথক ঘুমের ঘটনাগুলি পরীক্ষা করুন।

Perfetto UI-তে MyAppSubmitButton ট্রেস স্লাইসের মধ্যে প্রথম স্লিপিং ইন্টারভাল দেখানো হচ্ছে।
চিত্র ৬। `MyAppSubmitButton` এর মধ্যে প্রথম স্লিপ টাইম।
Perfetto UI-তে MyAppSubmitButton ট্রেস স্লাইসের মধ্যে দ্বিতীয় স্লিপিং ব্যবধান দেখানো হচ্ছে।
চিত্র ৭। `MyAppSubmitButton` এর মধ্যে দ্বিতীয় স্লিপ টাইম।
Perfetto UI  MyAppSubmitButton ট্রেস স্লাইসের মধ্যে তৃতীয় স্লিপিং ব্যবধান দেখাচ্ছে।
চিত্র ৮। `MyAppSubmitButton` এর মধ্যে তৃতীয় স্লিপ টাইম।
Perfetto UI  MyAppSubmitButton ট্রেস স্লাইসের মধ্যে চতুর্থ স্লিপিং ব্যবধান দেখাচ্ছে।
চিত্র ৯। `MyAppSubmitButton` এর মধ্যে চতুর্থ স্লিপ টাইম।

প্রথম তিনটি ঘুমের ব্যবধান (চিত্র ৬-৮) প্রায় একই রকম, প্রতিটির প্রায় ২ সেকেন্ড। চতুর্থ ঘুমের (চিত্র ৯) 0.7 সেকেন্ড। ঠিক ২ সেকেন্ডের সময়কাল কম্পিউটিং পরিবেশে খুব কমই কাকতালীয়। এটি দৃঢ়ভাবে একটি প্রোগ্রাম করা টাইমআউটের ইঙ্গিত দেয়, এলোমেলো রিসোর্স বিতর্কের পরিবর্তে। শেষ ঘুমের কারণ হতে পারে থ্রেডটি তার অপেক্ষা শেষ করে কারণ এটি যে অপারেশনটির জন্য অপেক্ষা করছিল তা সফল হয়েছিল।

এই অনুমানটি হল যে অ্যাপটি একাধিকবার ব্যবহারকারী-নির্ধারিত 2 সেকেন্ডের টাইমআউটে ছিল এবং অবশেষে সফল হয়েছিল, যার ফলে ANR ট্রিগার করার জন্য যথেষ্ট বিলম্ব হয়েছিল।

Perfetto UI MyApp:SubmitButton ট্রেস স্লাইসের সময় বিলম্বের সারাংশ দেখাচ্ছে, যা একাধিক 2-সেকেন্ডের ঘুমের ব্যবধান নির্দেশ করে।
চিত্র ১০। `MyApp:SubmitButton` স্লাইসের সময় বিলম্বের সারাংশ।

এটি যাচাই করতে, MyApp:SubmitButton ট্রেস বিভাগের সাথে সম্পর্কিত কোডটি পরীক্ষা করুন:

private static final int NETWORK_TIMEOUT_MILLISECS = 2000;
public void setupButtonCallback() {
  findViewById(R.id.submit).setOnClickListener(submitButtonView -> {
    Trace.beginSection("MyApp:SubmitButton");
    onClickSubmit();
    Trace.endSection();
  });
}

public void onClickSubmit() {
  prepareNetworkRequest();

  boolean networkRequestSuccess = false;
  int maxAttempts = 10;
  while (!networkRequestSuccess && maxAttempts > 0) {
    networkRequestSuccess = performNetworkRequest(NETWORK_TIMEOUT_MILLISECS);
    maxAttempts--;
  }

  if (networkRequestSuccess) {
    handleNetworkResponse();
  }
}

boolean performNetworkRequest(int timeoutMiliseconds) {
  // ...
}

  // ...
}

public void handleNetworkResponse() {
  Trace.beginSection("handleNetworkResponse");
  // ...
  Trace.endSection();
}

কোডটি এই অনুমানকে নিশ্চিত করে। onClickSubmit পদ্ধতিটি UI থ্রেডে 2000ms এর হার্ডকোডেড NETWORK_TIMEOUT_MILLISECS সহ একটি নেটওয়ার্ক অনুরোধ কার্যকর করে। গুরুত্বপূর্ণভাবে, এটি একটি while লুপের মধ্যে চলে যা 10 বার পর্যন্ত পুনরায় চেষ্টা করে।

এই নির্দিষ্ট ট্রেসে, ব্যবহারকারীর সম্ভবত নেটওয়ার্ক সংযোগ দুর্বল ছিল। প্রথম তিনটি প্রচেষ্টা ব্যর্থ হয়েছে, যার ফলে তিনটি 2-সেকেন্ড টাইমআউট হয়েছে (মোট 6 সেকেন্ড)। চতুর্থ প্রচেষ্টা 0.7 সেকেন্ড পরে সফল হয়েছে, যার ফলে কোডটি handleNetworkResponse এ এগিয়ে যেতে সক্ষম হয়েছে। তবে, জমা হওয়া অপেক্ষার সময় ইতিমধ্যেই ANR ট্রিগার করেছে।

এই ধরণের ANR এড়িয়ে চলুন, নেটওয়ার্ক-সম্পর্কিত অপারেশনগুলিকে মূল থ্রেডে চালানোর পরিবর্তে ব্যাকগ্রাউন্ড থ্রেডে রেখে। এটি UI কে দুর্বল সংযোগের সাথেও প্রতিক্রিয়াশীল থাকতে দেয়, এই শ্রেণীর ANR গুলিকে সম্পূর্ণরূপে বাদ দেয়।