systrace হল অ্যান্ড্রয়েড ডিভাইসের কর্মক্ষমতা বিশ্লেষণের প্রাথমিক টুল। যাইহোক, এটি সত্যিই অন্যান্য সরঞ্জামগুলির চারপাশে একটি মোড়ক। এটি atrace এর চারপাশে হোস্ট-সাইড র্যাপার, ডিভাইস-সাইড এক্সিকিউটেবল যা ইউজারস্পেস ট্রেসিং নিয়ন্ত্রণ করে এবং ftrace সেট আপ করে এবং লিনাক্স কার্নেলে প্রাথমিক ট্রেসিং মেকানিজম। systrace ট্রেসিং সক্ষম করতে atrace ব্যবহার করে, তারপর ftrace বাফার পড়ে এবং এটি একটি স্বয়ংসম্পূর্ণ HTML ভিউয়ারে মোড়ানো হয়। (যদিও নতুন কার্নেলগুলিতে লিনাক্স এনহ্যান্সড বার্কলে প্যাকেট ফিল্টার (eBPF) এর জন্য সমর্থন রয়েছে, নিম্নলিখিত ডকুমেন্টেশনগুলি 3.18 কার্নেলের সাথে সম্পর্কিত (কোনও ইএফপিএফ নেই) কারণ এটিই পিক্সেল/পিক্সেল এক্সএল-এ ব্যবহৃত হয়েছিল।)
systrace গুগল অ্যান্ড্রয়েড এবং গুগল ক্রোম টিমের মালিকানাধীন এবং এটি ক্যাটাপল্ট প্রকল্পের অংশ হিসাবে ওপেন সোর্স। সিস্ট্রেস ছাড়াও, ক্যাটাপল্ট অন্যান্য দরকারী ইউটিলিটিগুলি অন্তর্ভুক্ত করে। উদাহরণস্বরূপ, ftrace-এ সিস্ট্রেস বা অ্যাট্রেস দ্বারা সরাসরি সক্ষম করার চেয়ে আরও বেশি বৈশিষ্ট্য রয়েছে এবং এতে কিছু উন্নত কার্যকারিতা রয়েছে যা কর্মক্ষমতা সমস্যা ডিবাগ করার জন্য গুরুত্বপূর্ণ। (এই বৈশিষ্ট্যগুলির জন্য রুট অ্যাক্সেস এবং প্রায়শই একটি নতুন কার্নেল প্রয়োজন।)
সিস্ট্রেস চালান
Pixel/Pixel XL-এ জিটার ডিবাগ করার সময়, নিম্নলিখিত কমান্ড দিয়ে শুরু করুন:
./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000
GPU এবং ডিসপ্লে পাইপলাইন কার্যকলাপের জন্য প্রয়োজনীয় অতিরিক্ত ট্রেসপয়েন্টগুলির সাথে মিলিত হলে, এটি আপনাকে ব্যবহারকারীর ইনপুট থেকে স্ক্রিনে প্রদর্শিত ফ্রেমে ট্রেস করার ক্ষমতা দেয়। ইভেন্ট হারানো এড়াতে বাফারের আকার বড় কিছুতে সেট করুন (কারণ একটি বড় বাফার ছাড়া কিছু CPU-তে ট্রেসের কিছু পরে কোনো ইভেন্ট থাকে না)।
সিস্ট্রেসের মধ্য দিয়ে যাওয়ার সময়, মনে রাখবেন যে প্রতিটি ইভেন্ট CPU-তে কিছু দ্বারা ট্রিগার হয় ।
যেহেতু systrace ftrace-এর উপরে তৈরি করা হয় এবং ftrace CPU-তে চলে, তাই CPU-তে কিছু ftrace বাফার লিখতে হবে যা হার্ডওয়্যার পরিবর্তনগুলি লগ করে। এর মানে হল যে আপনি যদি কৌতূহলী হন কেন একটি ডিসপ্লে বেড়ার অবস্থা পরিবর্তিত হয়, তাহলে আপনি দেখতে পারেন যে CPU-তে কি চলছিল তার ট্রানজিশনের সঠিক সময়ে (CPU তে চলমান কিছু লগে সেই পরিবর্তনটিকে ট্রিগার করেছে)। এই ধারণাটি সিস্ট্রেস ব্যবহার করে কর্মক্ষমতা বিশ্লেষণের ভিত্তি।
উদাহরণ: ওয়ার্কিং ফ্রেম
এই উদাহরণটি একটি সাধারণ UI পাইপলাইনের জন্য একটি সিস্ট্রেস বর্ণনা করে। উদাহরণটি অনুসরণ করতে, ট্রেসের জিপ ফাইলটি ডাউনলোড করুন (যা এই বিভাগে উল্লেখ করা অন্যান্য ট্রেসগুলিও অন্তর্ভুক্ত করে), ফাইলটি আনজিপ করুন এবং আপনার ব্রাউজারে systrace_tutorial.html
ফাইলটি খুলুন৷ সতর্ক থাকুন যে এই systrace একটি বড় ফাইল; আপনি যদি আপনার প্রতিদিনের কাজে সিস্ট্রেস ব্যবহার না করেন, এটি সম্ভবত অনেক বেশি তথ্য সহ অনেক বড় ট্রেস যা আপনি আগে কখনও একটি একক ট্রেসে দেখেছেন।
টাচল্যাটেন্সির মতো সামঞ্জস্যপূর্ণ, পর্যায়ক্রমিক কাজের চাপের জন্য, UI পাইপলাইনে নিম্নলিখিতগুলি রয়েছে:
- SurfaceFlinger-এ EventThread অ্যাপের UI থ্রেডকে জাগিয়ে তোলে, ইঙ্গিত দেয় যে এটি একটি নতুন ফ্রেম রেন্ডার করার সময়।
- অ্যাপটি CPU এবং GPU রিসোর্স ব্যবহার করে UI থ্রেড, RenderThread এবং hwuiTasks-এ একটি ফ্রেম রেন্ডার করে। এটি UI এর জন্য ব্যয় করা ক্ষমতার সিংহভাগ।
- অ্যাপটি রেন্ডার করা ফ্রেমটিকে বাইন্ডার ব্যবহার করে SurfaceFlinger-এ পাঠায়, তারপর SurfaceFlinger ঘুমাতে যায়।
- SurfaceFlinger-এ একটি দ্বিতীয় ইভেন্ট থ্রেড কম্পোজিশন এবং ডিসপ্লে আউটপুট ট্রিগার করতে SurfaceFlinger কে জাগিয়ে তোলে। যদি SurfaceFlinger নির্ধারণ করে যে কোন কাজ করা হবে না, এটি আবার ঘুমাতে যায়।
- সারফেসফ্লিংগার হার্ডওয়্যার কম্পোজার (HWC)/হার্ডওয়্যার কম্পোজার 2 (HWC2) বা GL ব্যবহার করে কম্পোজিশন পরিচালনা করে। HWC/HWC2 কম্পোজিশন দ্রুত এবং কম শক্তি কিন্তু একটি চিপ (SoC) সিস্টেমের উপর নির্ভর করে এর সীমাবদ্ধতা রয়েছে। এটি সাধারণত ~4-6 ms লাগে, কিন্তু ধাপ 2 এর সাথে ওভারল্যাপ করতে পারে কারণ Android অ্যাপগুলি সর্বদা ট্রিপল বাফার করা হয়৷ (যদিও অ্যাপগুলি সর্বদা ট্রিপল বাফার করা হয়, সারফেসফ্লিংগারে শুধুমাত্র একটি মুলতুবি ফ্রেম অপেক্ষা করতে পারে, যা এটিকে ডাবল বাফারিংয়ের মতো দেখায়৷)
- SurfaceFlinger একটি বিক্রেতা ড্রাইভারের সাথে প্রদর্শনের জন্য চূড়ান্ত আউটপুট প্রেরণ করে এবং ইভেন্ট থ্রেড জেগে ওঠার জন্য অপেক্ষা করে ঘুমাতে ফিরে যায়।
চলুন ফ্রেমের মধ্য দিয়ে 15409 ms থেকে শুরু করি:
চিত্র 1 হল একটি সাধারণ ফ্রেম যা সাধারণ ফ্রেমে ঘেরা, তাই UI পাইপলাইন কীভাবে কাজ করে তা বোঝার জন্য এটি একটি ভাল সূচনা পয়েন্ট। TouchLatency-এর জন্য UI থ্রেড সারি বিভিন্ন সময়ে বিভিন্ন রং অন্তর্ভুক্ত করে। বারগুলি থ্রেডের জন্য বিভিন্ন রাজ্যকে নির্দেশ করে:
- ধূসর ঘুমন্ত।
- নীল। চালানোর যোগ্য (এটি চলতে পারে, কিন্তু সময়সূচী এখনও চালানোর জন্য এটি বেছে নেয়নি)।
- সবুজ। সক্রিয়ভাবে চলছে (নির্ধারক মনে করে এটি চলছে)।
- লাল। নিরবচ্ছিন্ন ঘুম (সাধারণত কার্নেলে তালা লাগিয়ে ঘুমানো)। I/O লোড নির্দেশক হতে পারে। কর্মক্ষমতা সমস্যা ডিবাগ করার জন্য অত্যন্ত দরকারী।
- কমলা। I/O লোডের কারণে নিরবচ্ছিন্ন ঘুম।
নিরবচ্ছিন্ন ঘুমের কারণ দেখতে ( sched_blocked_reason
ট্রেসপয়েন্ট থেকে পাওয়া যায়), লাল নিরবচ্ছিন্ন ঘুমের স্লাইস নির্বাচন করুন।
EventThread চলাকালীন, TouchLatency-এর জন্য UI থ্রেড চালানোর যোগ্য হয়ে ওঠে। এটি কি জাগিয়েছে তা দেখতে, নীল বিভাগে ক্লিক করুন।
চিত্র 2 দেখায় TouchLatency UI থ্রেডটি tid 6843 দ্বারা জাগ্রত হয়েছিল, যা EventThread-এর সাথে মিলে যায়। UI থ্রেড জেগে ওঠে, একটি ফ্রেম রেন্ডার করে এবং SurfaceFlinger ব্যবহার করার জন্য এটিকে সারিবদ্ধ করে।
যদি binder_driver
ট্যাগটি একটি ট্রেসে সক্ষম করা থাকে, আপনি সেই লেনদেনের সাথে জড়িত সমস্ত প্রক্রিয়ার তথ্য দেখতে একটি বাইন্ডার লেনদেন নির্বাচন করতে পারেন।
চিত্র 4 দেখায় যে, সারফেসফ্লিংগারে 15,423.65 ms Binder:6832_1 টিআইডি 9579-এর কারণে চালানোর যোগ্য হয়ে উঠেছে, যা TouchLatency এর RenderThread। আপনি বাইন্ডার লেনদেনের উভয় পাশে queueBuffer দেখতে পারেন।
SurfaceFlinger পাশে queueBuffer চলাকালীন, TouchLatency থেকে মুলতুবি ফ্রেমের সংখ্যা 1 থেকে 2 হয়ে যায়৷
চিত্র 5 ট্রিপল বাফারিং দেখায়, যেখানে দুটি সম্পূর্ণ ফ্রেম রয়েছে এবং অ্যাপটি তৃতীয়টি রেন্ডার করা শুরু করতে চলেছে৷ এর কারণ হল আমরা ইতিমধ্যে কিছু ফ্রেম বাদ দিয়েছি, তাই অ্যাপটি আরও ড্রপ করা ফ্রেম এড়াতে চেষ্টা করার জন্য একটির পরিবর্তে দুটি মুলতুবি ফ্রেম রাখে।
শীঘ্রই, SurfaceFlinger এর প্রধান থ্রেড একটি দ্বিতীয় ইভেন্ট থ্রেড দ্বারা জাগ্রত হয় যাতে এটি ডিসপ্লেতে পুরানো মুলতুবি ফ্রেমটিকে আউটপুট করতে পারে:
SurfaceFlinger প্রথমে পুরানো মুলতুবি থাকা বাফারটি আটকে দেয়, যার ফলে মুলতুবি থাকা বাফার সংখ্যা 2 থেকে 1 এ কমে যায়।
বাফারটি ল্যাচ করার পরে, সারফেসফ্লিংগার কম্পোজিশন সেট আপ করে এবং ডিসপ্লেতে চূড়ান্ত ফ্রেম জমা দেয়। (এই বিভাগগুলির মধ্যে কিছু mdss
ট্রেসপয়েন্টের অংশ হিসাবে সক্ষম করা হয়েছে, তাই সেগুলি আপনার SoC-তে অন্তর্ভুক্ত নাও হতে পারে।)
এরপর, mdss_fb0
CPU 0-এ জেগে ওঠে। mdss_fb0
হল ডিসপ্লে পাইপলাইনের কার্নেল থ্রেড যা ডিসপ্লেতে একটি রেন্ডার করা ফ্রেম আউটপুট করার জন্য। আমরা ট্রেসে mdss_fb0
তার নিজস্ব সারি হিসাবে দেখতে পারি (দেখতে নীচে স্ক্রোল করুন)।
mdss_fb0
জেগে ওঠে, সংক্ষিপ্তভাবে চলে, নিরবচ্ছিন্ন ঘুমে প্রবেশ করে, তারপর আবার জেগে ওঠে।
উদাহরণ: নন-ওয়ার্কিং ফ্রেম
এই উদাহরণটি পিক্সেল/পিক্সেল এক্সএল জিটার ডিবাগ করতে ব্যবহৃত একটি সিস্ট্রেস বর্ণনা করে। উদাহরণটি অনুসরণ করতে, ট্রেসের জিপ ফাইলটি ডাউনলোড করুন (যা এই বিভাগে উল্লেখ করা অন্যান্য ট্রেসগুলি অন্তর্ভুক্ত করে), ফাইলটি আনজিপ করুন এবং আপনার ব্রাউজারে systrace_tutorial.html
ফাইলটি খুলুন।
আপনি যখন সিস্ট্রেস খুলবেন, তখন আপনি এরকম কিছু দেখতে পাবেন:
জ্যাঙ্ক খোঁজার সময়, SurfaceFlinger এর অধীনে FrameMissed সারিটি পরীক্ষা করুন। FrameMissed হল HWC2 দ্বারা প্রদত্ত একটি মানের-জীবনের উন্নতি৷ অন্যান্য ডিভাইসের জন্য সিস্ট্রেস দেখার সময়, ডিভাইসটি HWC2 ব্যবহার না করলে FrameMissed সারিটি উপস্থিত নাও হতে পারে। উভয় ক্ষেত্রেই, FrameMissed-এর সাথে SurfaceFlinger এর একটি অত্যন্ত নিয়মিত রানটাইম অনুপস্থিত এবং একটি vsync-এ অ্যাপের ( com.prefabulated.touchlatency
) জন্য একটি অপরিবর্তিত মুলতুবি-বাফার গণনার সাথে সম্পর্কযুক্ত।
চিত্র 11 15598.29&nbps;ms এ একটি মিস করা ফ্রেম দেখায়। সারফেসফ্লিংগার vsync ব্যবধানে সংক্ষিপ্তভাবে জেগে ওঠে এবং কোনো কাজ না করেই ঘুমাতে ফিরে যায়, যার মানে SurfaceFlinger নির্ধারণ করেছে যে এটি আবার ডিসপ্লেতে একটি ফ্রেম পাঠানোর চেষ্টা করা মূল্যবান নয়। কেন?
এই ফ্রেমের জন্য পাইপলাইন কীভাবে ভেঙে গেছে তা বোঝার জন্য, সিস্ট্রেসে একটি সাধারণ UI পাইপলাইন কীভাবে উপস্থিত হয় তা দেখতে প্রথমে উপরের কাজের ফ্রেমের উদাহরণটি পর্যালোচনা করুন। প্রস্তুত হলে, মিস করা ফ্রেমে ফিরে যান এবং পিছনের দিকে কাজ করুন। লক্ষ্য করুন যে SurfaceFlinger জেগে ওঠে এবং অবিলম্বে ঘুমাতে যায়। TouchLatency থেকে মুলতুবি থাকা ফ্রেমের সংখ্যা দেখার সময়, দুটি ফ্রেম রয়েছে (কী ঘটছে তা বের করতে সাহায্য করার জন্য একটি ভাল সূত্র)।
যেহেতু আমাদের সারফেসফ্লিংগারে ফ্রেম রয়েছে, এটি কোনও অ্যাপের সমস্যা নয়। উপরন্তু, SurfaceFlinger সঠিক সময়ে জেগে উঠছে, তাই এটি একটি SurfaceFlinger সমস্যা নয়। যদি সারফেসফ্লিংগার এবং অ্যাপ উভয়ই স্বাভাবিক দেখায় তবে এটি সম্ভবত ড্রাইভারের সমস্যা।
যেহেতু mdss
এবং sync
ট্রেসপয়েন্টগুলি সক্রিয় করা আছে, আমরা বেড়া সম্পর্কে তথ্য পেতে পারি (ডিসপ্লে ড্রাইভার এবং সারফেসফ্লিংগারের মধ্যে ভাগ করা) যা ডিসপ্লেতে ফ্রেম জমা দেওয়ার সময় নিয়ন্ত্রণ করে। এই বেড়াগুলি mdss_fb0_retire
এর অধীনে তালিকাভুক্ত করা হয়েছে, যা বোঝায় যখন একটি ফ্রেম ডিসপ্লেতে থাকে। এই বেড়া sync
ট্রেস বিভাগের অংশ হিসাবে প্রদান করা হয়. কোন বেড়াগুলি SurfaceFlinger-এর নির্দিষ্ট ইভেন্টগুলির সাথে সামঞ্জস্যপূর্ণ তা আপনার SOC এবং ড্রাইভার স্ট্যাকের উপর নির্ভর করে, তাই আপনার চিহ্নগুলিতে বেড়া বিভাগগুলির অর্থ বোঝার জন্য আপনার SOC বিক্রেতার সাথে কাজ করুন৷
চিত্র 13 একটি ফ্রেম দেখায় যা প্রত্যাশিত হিসাবে 16.7 ms নয়, 33 ms এর জন্য প্রদর্শিত হয়েছিল৷ সেই স্লাইসটির অর্ধেক পথ, সেই ফ্রেমটিকে একটি নতুন দ্বারা প্রতিস্থাপন করা উচিত ছিল কিন্তু তা হয়নি৷ আগের ফ্রেমটি দেখুন এবং কিছু সন্ধান করুন।
চিত্র 14 দেখায় 14.482 ms একটি ফ্রেম। ভাঙা দুই-ফ্রেম সেগমেন্ট ছিল 33.6 ms, যা মোটামুটি আমরা দুটি ফ্রেমের জন্য আশা করব (আমরা 60 Hz, প্রতি ফ্রেমে 16.7 ms রেন্ডার করি, যা কাছাকাছি)। কিন্তু 14.482 ms মোটেও 16.7 ms এর কাছাকাছি নয়, এটি নির্দেশ করে যে ডিসপ্লে পাইপের সাথে কিছু ভুল আছে।
এটি কী নিয়ন্ত্রণ করে তা নির্ধারণ করতে সেই বেড়াটি কোথায় শেষ হয়েছে তা তদন্ত করুন।
একটি ওয়ার্কসারিতে রয়েছে __vsync_retire_work_handler
, যা বেড়া পরিবর্তিত হলে চলছে। কার্নেল উৎসের মাধ্যমে খুঁজছেন, আপনি দেখতে পারেন যে এটি ডিসপ্লে ড্রাইভারের অংশ। এটি ডিসপ্লে পাইপলাইনের জন্য জটিল পথে বলে মনে হচ্ছে, তাই এটি যত তাড়াতাড়ি সম্ভব চালাতে হবে। এটি আমাদের বা তার বেশি 70 জনের জন্য চালানোর যোগ্য (দীর্ঘ সময়সূচী বিলম্ব নয়), তবে এটি একটি কাজের সারি এবং সঠিকভাবে নির্ধারিত নাও হতে পারে।
এটি অবদান কিনা তা নির্ধারণ করতে পূর্ববর্তী ফ্রেম পরীক্ষা করুন; কখনও কখনও ঝগড়া সময়ের সাথে যোগ করতে পারে এবং অবশেষে একটি সময়সীমা মিস করতে পারে।
kworker-এ চলমান লাইনটি দৃশ্যমান নয় কারণ এটি নির্বাচন করা হলে দর্শক এটিকে সাদা করে দেয়, কিন্তু পরিসংখ্যান গল্পটি বলে: ডিসপ্লে পাইপলাইনের সমালোচনামূলক পথের অংশের জন্য 2.3 ms সময়সূচী বিলম্ব খারাপ । চালিয়ে যাওয়ার আগে, ডিসপ্লে পাইপলাইনের এই অংশটিকে একটি কাজের সারি থেকে (যেটি একটি SCHED_OTHER
CFS থ্রেড হিসাবে চলে) থেকে একটি ডেডিকেটেড SCHED_FIFO
kthread-এ সরানোর মাধ্যমে বিলম্বের সমাধান করুন৷ এই ফাংশনের জন্য সময়ের গ্যারান্টি প্রয়োজন যে কাজের সারিগুলি প্রদান করতে পারে না (এবং এটি করার উদ্দেশ্যে নয়)।
এটা কি জ্যাংকের কারণ? এটা চূড়ান্তভাবে বলা কঠিন. সহজে নির্ণয়ের ক্ষেত্রে যেমন কার্নেল লক বিতর্কের কারণে ডিসপ্লে-সমালোচনামূলক থ্রেডগুলি ঘুমাতে পারে, ট্রেসগুলি সাধারণত সমস্যাটি নির্দিষ্ট করে না। এই জীর্ণতা কি ফ্রেমের বাদ পড়ার কারণ হতে পারে? একেবারে। বেড়ার সময়গুলি 16.7 ms হওয়া উচিত, কিন্তু ড্রপ করা ফ্রেমের দিকে এগিয়ে যাওয়া ফ্রেমে সেগুলি একেবারেই কাছাকাছি নয়৷ ডিসপ্লে পাইপলাইনটি কতটা দৃঢ়ভাবে সংযুক্ত করা হয়েছে তা বিবেচনা করে, এটা সম্ভব যে বেড়ার চারপাশের ঝাঁকুনির ফলে একটি ড্রপ ফ্রেম হয়েছে৷
এই উদাহরণে, সমাধানটি __vsync_retire_work_handler
একটি workqueue থেকে একটি ডেডিকেটেড kthread-এ রূপান্তর করা জড়িত। এর ফলে বাউন্সিং বলের পরীক্ষায় লক্ষণীয় ঝাঁকুনির উন্নতি হয়েছে এবং জ্যাঙ্ক কমে গেছে। পরবর্তী চিহ্নগুলি বেড়ার সময় দেখায় যা 16.7 ms এর খুব কাছাকাছি ঘোরাফেরা করে৷