প্রোফাইল GPU রেন্ডারিংয়ের মাধ্যমে বিশ্লেষণ করা

Profile GPU Rendering টুলটি সেই আপেক্ষিক সময় দেখায় যা রেন্ডারিং পাইপলাইনের প্রতিটি পর্যায় পূর্ববর্তী ফ্রেম রেন্ডার করতে নেয়। এই জ্ঞান আপনাকে পাইপলাইনে বাধা শনাক্ত করতে সাহায্য করতে পারে যাতে আপনি আপনার অ্যাপের রেন্ডারিং পারফর্ম্যান্স উন্নত করতে অপ্টিমাইজ করতে পারেন।

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

ভিজ্যুয়াল রিপ্রেজেন্টেশন

প্রোফাইল GPU রেন্ডারিং টুল গ্রাফের আকারে বিভিন্ন স্টেজ ও তাদের আপেক্ষিক সময় দেখায়: একটি কালার-কোডেড হিস্টোগ্রাম। ছবি ১-এ এই ধরনের ডিসপ্লের উদাহরণ দেখানো হয়েছে।

প্রোফাইল GPU রেন্ডারিং গ্রাফ
ছবি ১. প্রোফাইল GPU রেন্ডারিং গ্রাফ

প্রোফাইল GPU রেন্ডারিং গ্রাফে দেখানো প্রতিটি উল্লম্ব বারের প্রতিটি অংশ পাইপলাইনের একটি পর্যায়কে দেখায় এবং বার গ্রাফে একটি নির্দিষ্ট রঙ ব্যবহার করে হাইলাইট করা হয়। ছবি ২-এ দেখানো প্রতিটি রঙের অর্থ কী তা একটি 'কী'-এর মাধ্যমে দেখানো হয়েছে।

প্রোফাইল GPU রেন্ডারিং গ্রাফ লিজেন্ড
ছবি ২. প্রোফাইল GPU রেন্ডারিং গ্রাফ লিজেন্ড

প্রতিটি রঙের অর্থ কী তা বুঝতে পারলে, আপনি নিজের অ্যাপের নির্দিষ্ট দিক টার্গেট করতে পারবেন যাতে এর রেন্ডারিং পারফর্ম্যান্স অপ্টিমাইজ করার চেষ্টা করতে পারেন।

স্টেজ ও তার অর্থ

এই বিভাগে প্রতিটি পর্যায়ে কী হয় তা ব্যাখ্যা করা হয়েছে এবং সেইসাথে কোন কোন কারণে সমস্যা হতে পারে তাও উল্লেখ করা হয়েছে।

ইনপুট হ্যান্ডলিং

পাইপলাইনের ইনপুট হ্যান্ডলিং স্টেজ পরিমাপ করে যে ইনপুট ইভেন্ট হ্যান্ডেল করতে অ্যাপটি কতক্ষণ সময় নিয়েছে। ইনপুট ইভেন্ট কলব্যাকের ফলে কল করা কোড এক্সিকিউট করতে অ্যাপটি কতক্ষণ সময় ব্যয় করেছে তা এই মেট্রিক থেকে জানা যায়।

এই সেগমেন্ট বড় হলে

এই অংশে বেশি ভ্যালু থাকার অর্থ হল, ইনপুট-হ্যান্ডলার ইভেন্ট কলব্যাকে অনেক বেশি কাজ বা খুব জটিল কাজ করা হচ্ছে। এই কলব্যাকগুলি সবসময় মূল থ্রেডে হয়, তাই এই সমস্যার সমাধান সরাসরি কাজ অপ্টিমাইজ করা বা অন্য থ্রেডে কাজ অফলোড করার উপর ফোকাস করে।

LazyColumn বা LazyRow স্ক্রল করার সময়ও এই ফেজ দেখা যেতে পারে। ব্যবহারকারীর টাচ স্ক্রল হিসেবে বিবেচিত হলে, লেজি লিস্ট টাচ ইভেন্ট ব্যবহার করে আইটেম কম্পোজ ও লে-আউট করে। আপনার অ্যাপ যদি স্ক্রল পজিশনে রেসপন্স করার জন্য কাস্টম কাজ করে, তাহলে ফ্রেম ড্রপ হওয়া আটকাতে এই অপারেশন যত দ্রুত সম্ভব করা গুরুত্বপূর্ণ। Android Studio-তে CPU Profiler বা Perfetto-এর মতো প্রোফাইলিং টুল আপনাকে আরও তদন্ত করতে সাহায্য করতে পারে। আরও তথ্যের জন্য সিস্টেম ট্রেসিংয়ের ওভারভিউ দেখুন।

অ্যানিমেশন

অ্যানিমেশন ফেজ আপনাকে দেখায় যে সেই ফ্রেমে চলা সমস্ত অ্যানিমেশন স্টেট মূল্যায়ন করতে কত সময় লেগেছে। Compose-এ কিছু সাধারণ অ্যানিমেশন API হল animate*AsState, Transition, এবং Animatable। এছাড়াও, স্ন্যাপশট স্টেট পরিবর্তন প্রসেস করতে এবং কম্পোজিশন আপডেট করতে এই ফেজ চলাকালীন Recomposer রান করে। এর অর্থ হল, রিকম্পোজিশন ওভারহেড প্রায়ই সরাসরি অ্যানিমেশন স্টেজে দেখা যায়।

Jetpack Compose UI-এর জন্য, সিস্টেম ইভেন্টের পাশাপাশি বিস্তারিত কম্পোজিশন ট্রেস দেখতে Compose Runtime Tracing লাইব্রেরি অন্তর্ভুক্ত করুন।

এই সেগমেন্ট বড় হলে

এই অংশে বেশি ভ্যালু সাধারণত অ্যানিমেশনের মাধ্যমে চালিত স্টেট পরিবর্তনের কারণে সম্পন্ন হওয়া কাজের ফলাফল। যেমন, একটি ফ্লিং অ্যানিমেশন, যা আপনার LazyColumn বা LazyRow স্ক্রল করে, নতুন তালিকা আইটেমের দ্রুত কম্পোজিশন, পরিমাপ এবং বরাদ্দ করে।

Measure

স্ক্রিনে আপনার কম্পোজেবল আঁকার জন্য, Android আপনার UI ট্রিতে লেআউট নোড জুড়ে তিনটি ফেজ এক্সিকিউট করে।

প্রথমে, সিস্টেম লেআউট নোড পরিমাপ করে। প্রতিটি কম্পোজেবলের নির্দিষ্ট সীমাবদ্ধতা এবং মডিফায়ার থাকে যা স্ক্রিনে অবজেক্টের সাইজের সীমা বর্ণনা করে। কম্পোজ করা যায় এমন কিছু আইটেমের নির্দিষ্ট, স্থির সাইজ থাকতে পারে; অন্যদের এমন সাইজ থাকে যা পেরেন্ট লেআউট কন্টেনারের মাধ্যমে পাস করা সীমাবদ্ধতার সাথে মানিয়ে নেয়।

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

দক্ষতার জন্য সিস্টেম সবসময় এই সিঙ্গেল-পাস লেআউট পারফর্ম করে। কম্পোজেবল লেআউট অবৈধ হয়ে গেলে, Compose সেই নির্দিষ্ট নোড পরিমাপ করে এবং চাইল্ড তার সাইজ বা কনস্ট্রেন্ট পরিবর্তন করলে তবেই পেরেন্ট হায়ারার্কি পর্যন্ত লেআউট আপডেট প্রোপাগেট করে।

এই সেগমেন্ট বড় হলে

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

লেআউট পাস পরীক্ষা করতে এবং বাধা শনাক্ত করতে Android Studio বা Perfetto-তে CPU Profiler ব্যবহার করুন। আরও তথ্যের জন্য সিস্টেম ট্রেসিংয়ের ওভারভিউ দেখুন।

ড্র

ড্র স্টেজে রেন্ডারিং অপারেশন, যেমন ব্যাকগ্রাউন্ড, আকার বা টেক্সট আঁকা, নেটিভ ড্রয়িং কমান্ডের একটি সিকোয়েন্সে অনুবাদ করা হয়। GPU এক্সিকিউশনের জন্য সিস্টেম এইসব কমান্ড ডিসপ্লে লিস্টে ক্যাপচার করে।

এই ফ্রেমের জন্য স্ক্রিনে আপডেট করতে হবে এমন সব লেআউট নোডের জন্য ডিসপ্লে লিস্টে কমান্ড ক্যাপচার করা সম্পূর্ণ করতে কত সময় লাগে তা ড্র বার রেকর্ড করে। পরিমাপ করা সময় যেকোনও কাস্টম ড্রয়িং লজিকের ক্ষেত্রেও প্রযোজ্য হয় যা আপনার ড্র মডিফায়ার বা Canvas কম্পোজেবলের মধ্যে থাকতে পারে।

এই সেগমেন্ট বড় হলে

সহজ কথায়, প্রতিটি ইনভ্যালিডেট করা লেআউট নোডের জন্য সব ড্রয়িং কমান্ড রান করতে কত সময় লেগেছে, তা এই মেট্রিক থেকে বোঝা যায়। এই পরিমাপে চাইল্ড নোড এবং ভেক্টর ড্রয়েবেলে এইসব কমান্ড পাঠাতে ব্যয় করা যেকোনও সময় অন্তর্ভুক্ত। এই কারণে, আপনি যখন এই বারে স্পাইক দেখতে পান, তখন এর কারণ হতে পারে যে অনেক কম্পোজেবল হঠাৎ অবৈধ হয়ে গেছে। ইনভ্যালিডেশনের কারণে ড্রয়িং কমান্ড আবার এক্সিকিউট করা এবং লেআউট নোডের ডিসপ্লে লিস্ট আবার তৈরি করা প্রয়োজনীয় হয়ে পড়ে। অথবা, কিছু কাস্টম কম্পোজেবল বা ক্যানভাসের কারণেও বেশি সময় লাগতে পারে, যেগুলির DrawScope ইমপ্লিমেন্টেশনে অত্যন্ত জটিল লজিক রয়েছে।

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

আপলোড করুন

আপলোড মেট্রিক বর্তমান ফ্রেম চলাকালীন CPU মেমরি থেকে GPU মেমরিতে বিটম্যাপ অবজেক্ট ট্রান্সফার করতে যে সময় লাগে তা দেখায়।

আলাদা প্রসেসর হিসেবে, CPU ও GPU-এর প্রসেসিংয়ের জন্য আলাদা RAM এরিয়া আছে। Android-এ বিটম্যাপ আঁকলে, GPU স্ক্রিনে রেন্ডার করার আগে সিস্টেম বিটম্যাপকে GPU মেমরিতে ট্রান্সফার করে। তারপর, GPU বিটম্যাপ ক্যাশে করে যাতে সিস্টেমকে আবার ডেটা ট্রান্সফার করতে না হয়, যতক্ষণ না GPU টেক্সচার ক্যাশে থেকে টেক্সচার সরিয়ে দেওয়া হয়।

মনে রাখবেন: Lollipop ডিভাইসে, এই স্টেজটি বেগুনি রঙের হয়।

এই সেগমেন্ট বড় হলে

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

এই বারটি সঙ্কুচিত করতে, আপনি এই ধরনের কৌশল ব্যবহার করতে পারেন:

  • বিটম্যাপ রেজোলিউশন যেন ডিসপ্লে করা সাইজের থেকে অনেক বেশি না হয় তা নিশ্চিত করা। যেমন, ১০২৪x১০২৪ মাপের ছবিকে ৪৮x৪৮ মাপের ছবি হিসেবে দেখাবেন না।
  • পরবর্তী সিঙ্ক ফেজের আগে বিটম্যাপ অ্যাসিঙ্ক্রোনাসভাবে প্রি-আপলোড করতে Coil-এর মতো আধুনিক লাইব্রেরির সুবিধা নেওয়া।

সমস্যা সংক্রান্ত কমান্ড

ইস্যু কমান্ড সেগমেন্ট স্ক্রিনে ডিসপ্লে তালিকা আঁকার জন্য প্রয়োজনীয় সমস্ত কমান্ড ইস্যু করতে যে সময় লাগে তা দেখায়।

সিস্টেম যাতে স্ক্রিনে ডিসপ্লে তালিকা দেখাতে পারে, তার জন্য এটি GPU-তে প্রয়োজনীয় কমান্ড পাঠায়। সাধারণত, এটি OpenGL ES API-এর মাধ্যমে এই অ্যাকশনটি করে।

এই প্রসেসটি সম্পূর্ণ হতে কিছুটা সময় লাগে, কারণ GPU-তে কমান্ড পাঠানোর আগে সিস্টেম প্রতিটি কমান্ডের জন্য চূড়ান্ত ট্রান্সফর্মেশন ও ক্লিপিং করে। এরপরে, GPU-এর দিকে অতিরিক্ত ওভারহেড তৈরি হয়, যা চূড়ান্ত কমান্ড গণনা করে। এইসব কমান্ডে চূড়ান্ত ট্রান্সফর্মেশন ও অতিরিক্ত ক্লিপিং অন্তর্ভুক্ত থাকে।

এই সেগমেন্ট বড় হলে

এই পর্যায়ে ব্যয় করা সময় হল ডিসপ্লে তালিকার জটিলতা ও পরিমাণের প্রত্যক্ষ পরিমাপ যা সিস্টেম কোনও নির্দিষ্ট ফ্রেমে রেন্ডার করে। যেমন, অনেক ড্র অপারেশন থাকলে, বিশেষ করে এমন ক্ষেত্রে যেখানে প্রতিটি ড্র প্রিমিটিভের জন্য একটি ছোট অন্তর্নিহিত খরচ থাকে, এই সময়টি বাড়িয়ে দিতে পারে। যেমন:

for (i in 0 until 1000) {
    canvas.drawPoint()
}

ইস্যু করার জন্য এর থেকে অনেক বেশি খরচ হয়:

canvas.drawPoints(thousandPointArray)

কমান্ড ইস্যু করা এবং ডিসপ্লে তালিকা আঁকার মধ্যে সবসময় ১:১ সম্পর্ক থাকে না। ইস্যু কমান্ড বারের মতো নয়, যা GPU-তে ড্রয়িং কমান্ড পাঠাতে যে সময় লাগে তা ক্যাপচার করে, ড্র মেট্রিক সেই সময়কে দেখায় যা ডিসপ্লে লিস্টে ইস্যু করা কমান্ড ক্যাপচার করতে লেগেছে।

এই পার্থক্য দেখা যায় কারণ যেখানে সম্ভব সেখানে সিস্টেমের মাধ্যমে ডিসপ্লে তালিকা ক্যাশে করা হয়। এর ফলে, এমন পরিস্থিতি তৈরি হয় যেখানে স্ক্রল, ট্রান্সফর্ম বা অ্যানিমেশনের জন্য সিস্টেমকে ডিসপ্লে লিস্ট আবার পাঠাতে হয়, কিন্তু সেটি আসলে নতুন করে তৈরি করতে হয় না—ড্রয়িং কমান্ড আবার ক্যাপচার করতে হয়—একেবারে শুরু থেকে। এর ফলে, আপনি হাই ড্র কমান্ড বার না দেখেও হাই ইস্যু কমান্ড বার দেখতে পাবেন।

বাফার সোয়্যাপ করুন

Android, GPU-তে ডিসপ্লে লিস্ট জমা দেওয়া শেষ করলে, সিস্টেম, গ্রাফিক্স ড্রাইভারকে একটি চূড়ান্ত কমান্ড ইস্যু করে জানায় যে বর্তমান ফ্রেমের কাজ শেষ হয়েছে। এই পর্যায়ে, ড্রাইভার অবশেষে স্ক্রিনে আপডেট করা ছবি দেখাতে পারবেন।

এই সেগমেন্ট বড় হলে

এটি বোঝা গুরুত্বপূর্ণ যে GPU, CPU-এর সাথে সমান্তরালভাবে কাজ করে। Android সিস্টেম GPU-তে ড্র কমান্ড ইস্যু করে এবং তারপরে পরবর্তী টাস্কে চলে যায়। GPU একটি সারি থেকে সেই ড্র কমান্ডগুলি পড়ে এবং সেগুলি প্রসেস করে।

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

এই সমস্যা কমানোর মূল উপায় হল GPU-তে হওয়া কাজের জটিলতা কমানো, ঠিক যেভাবে আপনি ইস্যু কমান্ড ফেজের জন্য করতেন।

বিবিধ

রেন্ডারিং সিস্টেমের কাজ করতে যে সময় লাগে তার পাশাপাশি, মূল থ্রেডে অতিরিক্ত কিছু কাজ হয় এবং এর সাথে রেন্ডারিংয়ের কোনও সম্পর্ক নেই। এই কাজের জন্য যে সময় লাগে তা বিবিধ সময় হিসেবে রিপোর্ট করা হয়। বিবিধ সময় সাধারণত এমন কাজকে বোঝায় যা রেন্ডারিংয়ের দুটি পরপর ফ্রেমের মধ্যে UI থ্রেডে ঘটতে পারে।

এই সেগমেন্ট বড় হলে

এই ভ্যালু বেশি হলে, আপনার অ্যাপে কলব্যাক, ইনটেন্ট বা অন্য কোনও কাজ থাকতে পারে যা অন্য থ্রেডে হওয়া উচিত। Android Studio-তে CPU Profiler বা Perfetto-এর মতো টুল মূল থ্রেডে চলা টাস্কের ব্যাপারে তথ্য প্রদান করতে পারে। এই তথ্য আপনাকে পারফর্ম্যান্স উন্নত করার লক্ষ্য স্থির করতে সাহায্য করতে পারে। আরও তথ্যের জন্য সিস্টেম ট্রেসিংয়ের ওভারভিউ দেখুন।