Android ডিভাইসের পারফর্ম্যান্স বিশ্লেষণ করার জন্য systrace হল প্রাথমিক টুল। তবে, এটি আসলে অন্যান্য টুলের একটি র্যাপার। এটি হল atrace-এর চারপাশের হোস্ট-সাইড র্যাপার, ডিভাইস-সাইড এক্সিকিউটেবল যা ইউজারস্পেস ট্রেসিং কন্ট্রোল করে এবং ftrace সেট-আপ করে এবং এটি হল Linux কার্নেলের প্রাথমিক ট্রেসিং মেকানিজম। ট্রেসিং চালু করতে systrace, atrace ব্যবহার করে, তারপর ftrace বাফার পড়ে এবং সেটি একটি সেল্ফ-কন্টেন্ড HTML ভিউয়ারে র্যাপ করে। (যদিও নতুন কার্নেলে Linux Enhanced Berkeley Packet Filter (eBPF) কাজ করে, এই পৃষ্ঠাটি 3.18 কার্নেলের (কোনও eFPF নেই) সাথে সম্পর্কিত কারণ এটি Pixel বা Pixel XL-এ ব্যবহার করা হয়েছে।)
systrace-এর মালিকানা Google Android ও Google Chrome টিমের এবং এটি ওপেন সোর্স হিসেবে Catapult প্রোজেক্টের অংশ। systrace ছাড়াও, Catapult-এ অন্যান্য দরকারী ইউটিলিটি অন্তর্ভুক্ত থাকে। যেমন, ftrace-এ systrace বা atrace-এর সরাসরি চালু করা ফিচারের চেয়ে বেশি ফিচার আছে এবং এতে কিছু উন্নত কার্যকারিতা আছে যা পারফর্ম্যান্সের সমস্যা ডিবাগ করার জন্য গুরুত্বপূর্ণ। (এইসব ফিচারের জন্য রুট অ্যাক্সেস এবং প্রায়শই নতুন কার্নেল প্রয়োজন হয়।)
systrace চালান
Pixel বা Pixel XL-এ জিটার সংক্রান্ত সমস্যা ডিবাগ করার সময়, নিম্নলিখিত কমান্ড দিয়ে শুরু করুন:
./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000
GPU ও ডিসপ্লে পাইপলাইন অ্যাক্টিভিটির জন্য প্রয়োজনীয় অতিরিক্ত ট্রেসপয়েন্টের সাথে এটি যোগ করলে, আপনি ব্যবহারকারীর ইনপুট থেকে স্ক্রিনে দেখানো ফ্রেম পর্যন্ত ট্রেস করতে পারবেন। ইভেন্ট যাতে মিস না হয় সেই জন্য বাফার সাইজ বড় করে সেট করুন (কারণ বড় বাফার না থাকলে, ট্রেসের কোনও পয়েন্টের পরে কিছু CPU-তে কোনও ইভেন্ট থাকে না)।
systrace-এর মাধ্যমে যাওয়ার সময় মনে রাখবেন যে প্রতিটি ইভেন্ট CPU-তে কোনও কিছুর মাধ্যমে ট্রিগার করা হয়।
যেহেতু ftrace-এর উপরে systrace তৈরি করা হয়েছে এবং ftrace সিপিইউতে রান করে, তাই সিপিইউতে এমন কিছু থাকতে হবে যা ftrace বাফার লিখবে এবং হার্ডওয়্যার পরিবর্তন লগ করবে। এর অর্থ হল, ডিসপ্লে ফেন্সের স্টেট কেন পরিবর্তিত হল তা জানতে চাইলে, ঠিক সেই মুহূর্তে CPU-তে কী চলছিল তা আপনি দেখতে পাবেন (CPU-তে কিছু চলার ফলে লগে সেই পরিবর্তনটি ট্রিগার হয়েছে)। এই ধারণাটি হল systrace ব্যবহার করে পারফর্ম্যান্স বিশ্লেষণ করার ভিত্তি।
উদাহরণ: ওয়ার্কিং ফ্রেম
এই উদাহরণে সাধারণ UI পাইপলাইনের জন্য systrace বর্ণনা করা হয়েছে। উদাহরণটি অনুসরণ করতে,
ট্রেসের জিপ ফাইল ডাউনলোড করুন
(এতে এই বিভাগে উল্লেখ করা অন্যান্য ট্রেসও অন্তর্ভুক্ত), ফাইলটি আনজিপ করুন
এবং আপনার ব্রাউজারে systrace_tutorial.html ফাইলটি খুলুন।
TouchLatency-এর মতো ধারাবাহিক, পর্যায়ক্রমিক ওয়ার্কলোডের জন্য, UI পাইপলাইন এই ক্রম অনুসরণ করে:
- SurfaceFlinger-এর EventThread অ্যাপ UI থ্রেডকে জাগিয়ে তোলে, এটি ইঙ্গিত করে যে নতুন ফ্রেম রেন্ডার করার সময় হয়ে গেছে।
- অ্যাপটি UI থ্রেড, RenderThread এবং HWUI টাস্কে CPU এবং GPU রিসোর্স ব্যবহার করে ফ্রেম রেন্ডার করে। UI-এর জন্য বেশিরভাগ ক্যাপাসিটি খরচ করা হয়েছে।
- অ্যাপটি বাইন্ডার ব্যবহার করে রেন্ডার করা ফ্রেম SurfaceFlinger-এ পাঠায়, তারপর SurfaceFlinger স্লিপ মোডে চলে যায়।
- SurfaceFlinger-এর দ্বিতীয় EventThread, কম্পোজিশন ও ডিসপ্লে আউটপুট ট্রিগার করতে SurfaceFlinger-কে জাগিয়ে তোলে। SurfaceFlinger যদি দেখে যে আর কোনও কাজ নেই, তাহলে এটি আবার স্লিপ মোডে চলে যায়।
- SurfaceFlinger, হার্ডওয়্যার কম্পোজার (HWC) বা হার্ডওয়্যার কম্পোজার ২ (HWC2) বা GL ব্যবহার করে কম্পোজিশন ম্যানেজ করে। HWC এবং HWC2 কম্পোজিশন দ্রুততর এবং কম পাওয়ার খরচ করে, তবে সিস্টেম অন চিপ (SoC)-এর উপর নির্ভর করে সীমাবদ্ধতা থাকে। এতে সাধারণত ৪ থেকে ৬ মিলি-সেকেন্ড সময় লাগে, তবে ধাপ ২-এর সাথে ওভারল্যাপ করতে পারে কারণ Android অ্যাপ সবসময় ট্রিপল বাফার করা থাকে। (অ্যাপ সবসময় ট্রিপল বাফার করা হলেও, SurfaceFlinger-এ শুধুমাত্র একটি পেন্ডিং ফ্রেম থাকতে পারে, যার ফলে এটি ডবল বাফারিংয়ের মতোই মনে হয়।)
- SurfaceFlinger ভেন্ডর ড্রাইভারের সাথে ডিসপ্লে করার জন্য চূড়ান্ত আউটপুট পাঠায় এবং EventThread জেগে ওঠার জন্য অপেক্ষা করে আবার স্লিপ মোডে ফিরে যায়।
১৫৪০৯ মিলি সেকেন্ডে শুরু হওয়া ফ্রেম সিকোয়েন্সের একটি উদাহরণ এখানে দেওয়া হল:

ছবি ১. সাধারণ UI পাইপলাইন, EventThread চলছে।
ছবি ১ হল একটি সাধারণ ফ্রেম যা সাধারণ ফ্রেম দিয়ে ঘেরা, তাই UI পাইপলাইন কীভাবে কাজ করে তা বোঝার জন্য এটি একটি ভাল শুরু। TouchLatency-এর জন্য UI থ্রেড সারিতে বিভিন্ন সময়ে বিভিন্ন রঙ থাকে। বারগুলি থ্রেডের জন্য বিভিন্ন অবস্থা বোঝায়:
- ধূসর। ঘুমাচ্ছি।
- নীল। রান করার উপযুক্ত (এটি রান করা যেতে পারে, কিন্তু শিডিউলার এখনও এটি রান করার জন্য বেছে নেয়নি)।
- সবুজ। অ্যাক্টিভভাবে চলছে (শিডিউলার মনে করে যে এটি চলছে)।
- লাল। নিরবচ্ছিন্ন ঘুম (সাধারণত কার্নেলে লক করা অবস্থায় ঘুম)। I/O লোডের ইঙ্গিত হতে পারে। পারফর্ম্যান্স সংক্রান্ত সমস্যা ডিবাগ করার জন্য অত্যন্ত উপযোগী।
- কমলা। I/O লোডের কারণে নিরবচ্ছিন্ন ঘুম।
অবাধ ঘুমের কারণ দেখতে (যা
sched_blocked_reason ট্রেসপয়েন্ট থেকে উপলভ্য), লাল অবাধ
ঘুমের স্লাইস বেছে নিন।
EventThread চলাকালীন, TouchLatency-এর জন্য UI থ্রেড রানযোগ্য হয়ে যায়। কী কারণে এটি চালু হয়েছে তা দেখতে, নীল বিভাগে ক্লিক করুন।

ছবি ২. TouchLatency-এর জন্য UI থ্রেড।
ছবি ২-এ দেখানো হয়েছে যে tid 6843-এর মাধ্যমে TouchLatency UI থ্রেডকে জাগানো হয়েছে, যা EventThread-এর সাথে সম্পর্কিত। UI থ্রেড জেগে ওঠে, একটি ফ্রেম রেন্ডার করে এবং SurfaceFlinger-এর ব্যবহারের জন্য সেটি এনকিউ করে।

ছবি ৩. UI থ্রেড জেগে ওঠে, একটি ফ্রেম রেন্ডার করে এবং SurfaceFlinger-এর ব্যবহারের জন্য এটি এনকিউ করে।
কোনও ট্রেসে binder_driver ট্যাগ চালু করা থাকলে, আপনি কোনও
বাইন্ডার ট্রানজ্যাকশন বেছে নিয়ে সেই ট্রানজ্যাকশনে
ইনভলভ থাকা সব প্রসেস সম্পর্কে তথ্য দেখতে পারবেন।

ছবি ৪. বাইন্ডার ট্রানজ্যাকশন।
৪ নম্বর ছবিতে দেখানো হয়েছে যে, SurfaceFlinger-এ ১৫,৪২৩.৬৫ ms-এ Binder:6832_1, tid 9579-এর কারণে রান করার উপযুক্ত হয়ে যায়, যা TouchLatency-এর RenderThread. এছাড়াও, আপনি বাইন্ডার ট্রানজ্যাকশনের দু'দিকেই queueBuffer দেখতে পাবেন।
SurfaceFlinger-এর দিকে queueBuffer চলাকালীন, TouchLatency থেকে বাকি থাকা ফ্রেমের সংখ্যা ১ থেকে ২ হয়ে যায়।

ছবি ৫. পেন্ডিং ফ্রেম ১ থেকে ২ পর্যন্ত যায়।
৫ নম্বর ছবিতে ট্রিপল বাফারিং দেখানো হয়েছে, যেখানে দুটি সম্পূর্ণ ফ্রেম আছে এবং অ্যাপটি তৃতীয় ফ্রেম রেন্ডার করা শুরু করতে চলেছে। এর কারণ হল, আমরা আগেই কিছু ফ্রেম বাদ দিয়েছি, তাই আরও ফ্রেম বাদ দেওয়া এড়াতে অ্যাপ একটির পরিবর্তে দুটি পেন্ডিং ফ্রেম রাখে।
এর পরেই, SurfaceFlinger-এর মূল থ্রেডকে দ্বিতীয় EventThread জাগিয়ে তোলে, যাতে এটি ডিসপ্লেতে পুরনো পেন্ডিং ফ্রেম আউটপুট করতে পারে:

ছবি ৬. SurfaceFlinger-এর মূল থ্রেড দ্বিতীয় EventThread-এর মাধ্যমে জেগে ওঠে।
SurfaceFlinger প্রথমে পুরনো পেন্ডিং বাফার ল্যাচ করে, যার ফলে পেন্ডিং বাফারের সংখ্যা ২ থেকে কমে ১ হয়ে যায়:

ছবি ৭. SurfaceFlinger প্রথমে পুরনো পেন্ডিং বাফারে ল্যাচ করে।
বাফার ল্যাচ করার পরে, SurfaceFlinger কম্পোজিশন সেট-আপ করে এবং ডিসপ্লেতে
চূড়ান্ত ফ্রেম জমা দেয়। (এইসব বিভাগের কিছু অংশ
mdss ট্রেসপয়েন্টের অংশ হিসেবে চালু করা হয়, তাই সেগুলি আপনার SoC-তে নাও থাকতে পারে।)

ছবি ৮. SurfaceFlinger কম্পোজিশন সেট-আপ করে এবং চূড়ান্ত ফ্রেম জমা দেয়।
এরপরে, mdss_fb0 CPU 0-এ জেগে ওঠে। mdss_fb0 হল
ডিসপ্লে পাইপলাইনের কার্নেল থ্রেড যা ডিসপ্লেতে রেন্ডার করা ফ্রেম আউটপুট করে।
লক্ষ্য করুন যে mdss_fb0 ট্রেসে নিজস্ব সারিতে আছে (নিচের দিকে স্ক্রল করে
দেখুন):

ছবি ৯. CPU 0-তে mdss_fb0 চালু হয়।
mdss_fb0 জেগে ওঠে, কিছুক্ষণ চলে, বাধা দেওয়া যায় না এমন স্লিপ মোডে যায়,
তারপর আবার জেগে ওঠে।
উদাহরণ: কাজ করছে না এমন ফ্রেম
এই উদাহরণে Pixel বা Pixel XL-এর জিটার সংক্রান্ত সমস্যা ডিবাগ করার জন্য ব্যবহৃত সিস্ট্রেস সম্পর্কে বর্ণনা করা হয়েছে। উদাহরণ
অনুসরণ করতে, ট্রেসের zip
ফাইল ডাউনলোড করুন (যার মধ্যে এই
বিভাগে উল্লেখ করা অন্যান্য ট্রেস অন্তর্ভুক্ত), ফাইলটি আনজিপ করুন এবং আপনার
ব্রাউজারে systrace_tutorial.html ফাইলটি খুলুন।
আপনি systrace খুললে, নিচের ছবির মতো কিছু দেখতে পাবেন:

ছবি ১০. বেশিরভাগ বিকল্প চালু করা Pixel XL-এ TouchLatency চলছে।
১০ নম্বর ছবিতে, mdss এবং kgsl
ট্রেসপয়েন্ট সহ বেশিরভাগ বিকল্প চালু করা আছে।
জ্যাঙ্ক খোঁজার সময়, SurfaceFlinger-এর অধীনে FrameMissed সারি চেক করুন।
FrameMissed হল HWC2-এর মাধ্যমে প্রদান করা কোয়ালিটি-অফ-লাইফ সংক্রান্ত উন্নতি। অন্যান্য ডিভাইসের জন্য
সিস্ট্রেস দেখার সময়, ডিভাইসটি
HWC2 ব্যবহার না করলে, FrameMissed সারিটি নাও থাকতে পারে। দু'টি ক্ষেত্রেই, FrameMissed-এর সাথে SurfaceFlinger-এর একটি
রেগুলার রানটাইম মিস করা এবং অ্যাপের জন্য অপরিবর্তিত পেন্ডিং-বাফার সংখ্যা
(com.prefabulated.touchlatency) VSync-এ কোরিলেট করা হয়।

ছবি ১১. SurfaceFlinger-এর সাথে FrameMissed কোরিলেশন।
ছবি ১১-তে ১৫৫৯৮.২৯ মিলি সেকেন্ডে একটি মিস করা ফ্রেম দেখানো হয়েছে। SurfaceFlinger VSync ইন্টারভ্যালে সংক্ষেপে জেগে ওঠে এবং কোনও কাজ না করেই আবার ঘুমিয়ে পড়ে, এর অর্থ হল SurfaceFlinger নির্ধারণ করেছে যে ডিসপ্লেতে আবার ফ্রেম পাঠানোর চেষ্টা করা উচিত নয়।
এই ফ্রেমের জন্য পাইপলাইন কেন ভেঙে গেছে তা বুঝতে, প্রথমে উপরের ওয়ার্কিং ফ্রেমের উদাহরণ পর্যালোচনা করে দেখুন যে কীভাবে সিস্ট্রেসে একটি সাধারণ UI পাইপলাইন দেখা যায়। প্রস্তুত হয়ে গেলে, মিস হয়ে যাওয়া ফ্রেমে ফিরে যান এবং পিছন থেকে কাজ করুন। লক্ষ্য করুন যে SurfaceFlinger চালু হয় এবং সাথে সাথেই স্লিপ মোডে চলে যায়। TouchLatency থেকে পেন্ডিং ফ্রেমের সংখ্যা দেখার সময়, দুটি ফ্রেম থাকে (কী ঘটছে তা নির্ধারণ করতে সাহায্য করার জন্য একটি ভালো ক্লু)।

ছবি ১২. SurfaceFlinger জেগে ওঠে এবং সঙ্গে সঙ্গে স্লিপ মোডে চলে যায়।
SurfaceFlinger-এ ফ্রেম থাকার কারণে এটি অ্যাপ সংক্রান্ত সমস্যা নয়। এছাড়াও, SurfaceFlinger সঠিক সময়ে জেগে উঠছে, তাই এটি SurfaceFlinger সংক্রান্ত সমস্যা নয়। SurfaceFlinger ও অ্যাপ, দু'টিই স্বাভাবিক দেখালে, সম্ভবত এটি ড্রাইভার সংক্রান্ত সমস্যা।
mdss ও sync ট্রেসপয়েন্ট চালু করা আছে বলে,
আপনি সেইসব ফেন্স (ডিসপ্লে ড্রাইভার ও
SurfaceFlinger-এর মধ্যে শেয়ার করা) সম্পর্কে তথ্য পেতে পারেন যেগুলি ডিসপ্লেতে ফ্রেম জমা দেওয়ার সময় কন্ট্রোল করে।
এইসব ফেন্স mdss_fb0_retire-এর অধীনে তালিকাভুক্ত করা আছে, যা
কোনও ফ্রেম ডিসপ্লেতে কখন আছে তা বোঝায়। এইসব ফেন্স sync ট্রেস ক্যাটেগরির
অংশ হিসেবে প্রদান করা হয়। SurfaceFlinger-এ নির্দিষ্ট ইভেন্টের সাথে কোন ফেন্স সম্পর্কিত তা আপনার SOC এবং ড্রাইভার স্ট্যাকের উপর নির্ভর করে, তাই
আপনার ট্রেসে ফেন্স বিভাগের অর্থ বুঝতে আপনার SOC ভেন্ডরের সাথে কাজ করুন।

ছবি ১৩. mdss_fb0_retire বেড়া।
১৩ নম্বর ছবিতে এমন একটি ফ্রেম দেখানো হয়েছে যা ৩৩ মিলি সেকেন্ডের জন্য দেখানো হয়েছে, প্রত্যাশিত ১৬.৭ মিলি সেকেন্ডের জন্য নয়। সেই স্লাইসের মাঝামাঝি, সেই ফ্রেমটি একটি নতুন ফ্রেম দিয়ে প্রতিস্থাপন করা উচিত ছিল কিন্তু তা করা হয়নি। আগের ফ্রেম দেখুন এবং কিছু খুঁজে দেখুন।

ছবি ১৪. খারাপ ফ্রেমের আগের ফ্রেম।
১৪ নম্বর ছবিতে ১৪.৪৮২ মিলি সেকেন্ডের ফ্রেম দেখানো হয়েছে। দুটি ফ্রেমের ভাঙা সেগমেন্টটি ছিল ৩৩.৬ ms, যা দুটি ফ্রেমের জন্য মোটামুটি প্রত্যাশিত (৬০ Hz-এ রেন্ডার করা, ১৬.৭ ms প্রতি ফ্রেম, যা কাছাকাছি)। কিন্তু ১৪.৪৮২ মি.সে. ১৬.৭ মি.সে.-এর কাছাকাছি নয়, যা থেকে বোঝা যায় যে ডিসপ্লে পাইপে কোনও সমস্যা হয়েছে।
সেই বেড়াটি ঠিক কোথায় শেষ হচ্ছে তা খতিয়ে দেখুন, যাতে সেটি কী নিয়ন্ত্রণ করছে তা নির্ধারণ করা যায়:

ছবি ১৫. বেড়ার শেষ প্রান্ত পরীক্ষা করে দেখুন।
ওয়ার্ককিউতে __vsync_retire_work_handler থাকে, যা
ফেন্স পরিবর্তন হলে রান করে। কার্নেল সোর্স দেখলে বুঝতে পারবেন যে
এটি ডিসপ্লে ড্রাইভারের অংশ। এটি ডিসপ্লে পাইপলাইনের জন্য গুরুত্বপূর্ণ
পাথে আছে বলে মনে হচ্ছে, তাই এটি যত দ্রুত সম্ভব রান করতে হবে। এটি প্রায় ৭০ μs ধরে রান করা যায় (শিডিউলিংয়ে বেশি দেরি হয় না), তবে এটি একটি ওয়ার্ককিউ এবং
সঠিকভাবে শিডিউল নাও করা হতে পারে।
আগের ফ্রেম চেক করে দেখুন যে সেটি কন্ট্রিবিউট করেছে কিনা; কখনও কখনও জিটার সময়ের সাথে সাথে বেড়ে যেতে পারে এবং শেষ পর্যন্ত ডেডলাইন মিস হয়ে যেতে পারে:

ছবি ১৬. আগের ফ্রেম।
kworker-এ রান করার উপযুক্ত লাইনটি দেখা যাচ্ছে না কারণ ভিউয়ার এটি বেছে নিলে
সাদা করে দেয়, কিন্তু পরিসংখ্যান থেকে বোঝা যাচ্ছে: ডিসপ্লে পাইপলাইনের গুরুত্বপূর্ণ পাথের অংশের জন্য শিডিউলার
বিলম্বের ২.৩ মিলি সেকেন্ড খারাপ।
চালিয়ে যাওয়ার আগে, ডিসপ্লে পাইপলাইনের
ক্রিটিক্যাল পাথের এই অংশটি ওয়ার্ককিউ থেকে (যা একটি
SCHED_OTHER CFS থ্রেড হিসেবে রান করে) একটি ডেডিকেটেড SCHED_FIFO
kthread-এ সরিয়ে নিয়ে বিলম্বের সমস্যা সমাধান করুন। এই ফাংশনের জন্য টাইমিং গ্যারান্টি প্রয়োজন যা ওয়ার্ককিউ দিতে পারে না (এবং দেওয়ার
উদ্দেশ্যও নেই)।
এটি যে জ্যাঙ্কের কারণ তা স্পষ্ট নয়। সহজে-ডায়াগনসিস-করা-যায় এমন কেস, যেমন কার্নেল লক কন্টেনশন যার কারণে ডিসপ্লে-ক্রিটিক্যাল থ্রেড স্লিপ করে, এগুলি ছাড়া ট্রেস সাধারণত সমস্যা নির্দিষ্ট করে না। এই জিটার হয়ত ড্রপ করা ফ্রেমের কারণ। ফেন্স টাইম ১৬.৭ মি.সে. হওয়া উচিত, কিন্তু ড্রপ করা ফ্রেমের ঠিক আগের ফ্রেমগুলিতে সেটি এর কাছাকাছিও নেই। ডিসপ্লে পাইপলাইন কতটা টাইটলি কাপলড তা বিবেচনা করে, এটি সম্ভব যে ফেঞ্চ টাইমিংয়ের আশেপাশে জিটার হওয়ার ফলে একটি ফ্রেম ড্রপ হয়ে গেছে।
এই উদাহরণে, সমাধানটি
__vsync_retire_work_handler-কে একটি ওয়ার্ককিউ থেকে একটি ডেডিকেটেড
kthread-এ রূপান্তর করার সাথে জড়িত। এর ফলে বাউন্সিং বল টেস্টে জিটার উল্লেখযোগ্যভাবে উন্নত হয় এবং জ্যাঙ্ক কমে যায়। পরবর্তী ট্রেস থেকে দেখা যায় যে ফেন্স টাইমিং ১৬.৭ মিলি সেকেন্ডের খুব কাছাকাছি।